Refactor management of overview window copy lifetime into a separate class.
[chromium-blink-merge.git] / media / cast / audio_receiver / audio_receiver.cc
blob9329bf21ab48d240e2874b048edca152557d70f5
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/cast/audio_receiver/audio_receiver.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "media/cast/audio_receiver/audio_decoder.h"
11 #include "media/cast/framer/framer.h"
12 #include "media/cast/rtcp/rtcp.h"
13 #include "media/cast/rtp_receiver/rtp_receiver.h"
15 // Max time we wait until an audio frame is due to be played out is released.
16 static const int64 kMaxAudioFrameWaitMs = 20;
17 static const int64 kMinSchedulingDelayMs = 1;
19 namespace media {
20 namespace cast {
23 // Local implementation of RtpData (defined in rtp_rtcp_defines.h).
24 // Used to pass payload data into the audio receiver.
25 class LocalRtpAudioData : public RtpData {
26 public:
27 LocalRtpAudioData(AudioReceiver* audio_receiver, base::TickClock* clock)
28 : audio_receiver_(audio_receiver),
29 time_first_incoming_packet_(),
30 first_incoming_rtp_timestamp_(0),
31 clock_(clock) {}
33 virtual void OnReceivedPayloadData(
34 const uint8* payload_data,
35 size_t payload_size,
36 const RtpCastHeader* rtp_header) OVERRIDE {
37 // TODO(pwestin): update this as video to refresh over time.
38 if (time_first_incoming_packet_.is_null()) {
39 first_incoming_rtp_timestamp_ = rtp_header->webrtc.header.timestamp;
40 time_first_incoming_packet_ = clock_->NowTicks();
42 audio_receiver_->IncomingParsedRtpPacket(payload_data, payload_size,
43 *rtp_header);
46 void GetFirstPacketInformation(base::TimeTicks* time_incoming_packet,
47 uint32* incoming_rtp_timestamp) {
48 *time_incoming_packet = time_first_incoming_packet_;
49 *incoming_rtp_timestamp = first_incoming_rtp_timestamp_;
52 private:
53 AudioReceiver* audio_receiver_;
54 base::TimeTicks time_first_incoming_packet_;
55 uint32 first_incoming_rtp_timestamp_;
56 base::TickClock* clock_;
59 // Local implementation of RtpPayloadFeedback (defined in rtp_defines.h)
60 // Used to convey cast-specific feedback from receiver to sender.
61 class LocalRtpAudioFeedback : public RtpPayloadFeedback {
62 public:
63 explicit LocalRtpAudioFeedback(AudioReceiver* audio_receiver)
64 : audio_receiver_(audio_receiver) {
67 virtual void CastFeedback(const RtcpCastMessage& cast_message) OVERRIDE {
68 audio_receiver_->CastFeedback(cast_message);
71 private:
72 AudioReceiver* audio_receiver_;
75 class LocalRtpReceiverStatistics : public RtpReceiverStatistics {
76 public:
77 explicit LocalRtpReceiverStatistics(RtpReceiver* rtp_receiver)
78 : rtp_receiver_(rtp_receiver) {
81 virtual void GetStatistics(uint8* fraction_lost,
82 uint32* cumulative_lost, // 24 bits valid.
83 uint32* extended_high_sequence_number,
84 uint32* jitter) OVERRIDE {
85 rtp_receiver_->GetStatistics(fraction_lost,
86 cumulative_lost,
87 extended_high_sequence_number,
88 jitter);
91 private:
92 RtpReceiver* rtp_receiver_;
95 AudioReceiver::AudioReceiver(scoped_refptr<CastEnvironment> cast_environment,
96 const AudioReceiverConfig& audio_config,
97 PacedPacketSender* const packet_sender)
98 : cast_environment_(cast_environment),
99 codec_(audio_config.codec),
100 incoming_ssrc_(audio_config.incoming_ssrc),
101 frequency_(audio_config.frequency),
102 audio_buffer_(),
103 audio_decoder_(),
104 time_offset_(),
105 weak_factory_(this) {
106 target_delay_delta_ =
107 base::TimeDelta::FromMilliseconds(audio_config.rtp_max_delay_ms);
108 incoming_payload_callback_.reset(
109 new LocalRtpAudioData(this, cast_environment->Clock()));
110 incoming_payload_feedback_.reset(new LocalRtpAudioFeedback(this));
111 if (audio_config.use_external_decoder) {
112 audio_buffer_.reset(new Framer(cast_environment->Clock(),
113 incoming_payload_feedback_.get(),
114 audio_config.incoming_ssrc,
115 true,
116 0));
117 } else {
118 audio_decoder_ = new AudioDecoder(audio_config);
120 rtp_receiver_.reset(new RtpReceiver(cast_environment->Clock(),
121 &audio_config,
122 NULL,
123 incoming_payload_callback_.get()));
124 rtp_audio_receiver_statistics_.reset(
125 new LocalRtpReceiverStatistics(rtp_receiver_.get()));
126 base::TimeDelta rtcp_interval_delta =
127 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval);
128 rtcp_.reset(new Rtcp(cast_environment->Clock(),
129 NULL,
130 packet_sender,
131 NULL,
132 rtp_audio_receiver_statistics_.get(),
133 audio_config.rtcp_mode,
134 rtcp_interval_delta,
135 false,
136 audio_config.feedback_ssrc,
137 audio_config.rtcp_c_name));
138 rtcp_->SetRemoteSSRC(audio_config.incoming_ssrc);
139 ScheduleNextRtcpReport();
142 AudioReceiver::~AudioReceiver() {}
144 void AudioReceiver::IncomingParsedRtpPacket(const uint8* payload_data,
145 size_t payload_size,
146 const RtpCastHeader& rtp_header) {
147 if (audio_decoder_) {
148 DCHECK(!audio_buffer_) << "Invalid internal state";
149 audio_decoder_->IncomingParsedRtpPacket(payload_data, payload_size,
150 rtp_header);
151 return;
153 DCHECK(audio_buffer_) << "Invalid internal state";
154 DCHECK(!audio_decoder_) << "Invalid internal state";
155 bool complete = audio_buffer_->InsertPacket(payload_data, payload_size,
156 rtp_header);
157 if (!complete) return; // Audio frame not complete; wait for more packets.
158 if (queued_encoded_callbacks_.empty()) return; // No pending callback.
160 AudioFrameEncodedCallback callback = queued_encoded_callbacks_.front();
161 queued_encoded_callbacks_.pop_front();
162 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
163 base::Bind(&AudioReceiver::GetEncodedAudioFrame,
164 weak_factory_.GetWeakPtr(), callback));
167 void AudioReceiver::GetRawAudioFrame(int number_of_10ms_blocks,
168 int desired_frequency, const AudioFrameDecodedCallback& callback) {
169 DCHECK(audio_decoder_) << "Invalid function call in this configuration";
171 cast_environment_->PostTask(CastEnvironment::AUDIO_DECODER, FROM_HERE,
172 base::Bind(&AudioReceiver::DecodeAudioFrameThread,
173 weak_factory_.GetWeakPtr(),
174 number_of_10ms_blocks,
175 desired_frequency,
176 callback));
179 void AudioReceiver::DecodeAudioFrameThread(
180 int number_of_10ms_blocks,
181 int desired_frequency,
182 const AudioFrameDecodedCallback callback) {
183 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::AUDIO_DECODER));
184 // TODO(mikhal): Allow the application to allocate this memory.
185 scoped_ptr<PcmAudioFrame> audio_frame(new PcmAudioFrame());
187 uint32 rtp_timestamp = 0;
188 if (!audio_decoder_->GetRawAudioFrame(number_of_10ms_blocks,
189 desired_frequency,
190 audio_frame.get(),
191 &rtp_timestamp)) {
192 return;
194 base::TimeTicks now = cast_environment_->Clock()->NowTicks();
195 base::TimeTicks playout_time;
196 playout_time = GetPlayoutTime(now, rtp_timestamp);
198 // Frame is ready - Send back to the main thread.
199 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
200 base::Bind(callback,
201 base::Passed(&audio_frame), playout_time));
204 void AudioReceiver::PlayoutTimeout() {
205 if (queued_encoded_callbacks_.empty()) {
206 // Already released by incoming packet.
207 return;
209 AudioFrameEncodedCallback callback = queued_encoded_callbacks_.front();
210 queued_encoded_callbacks_.pop_front();
212 uint32 rtp_timestamp = 0;
213 bool next_frame = false;
214 scoped_ptr<EncodedAudioFrame> encoded_frame(new EncodedAudioFrame());
216 if (!audio_buffer_->GetEncodedAudioFrame(encoded_frame.get(),
217 &rtp_timestamp, &next_frame)) {
218 // We have no audio frames. Wait for new packet(s).
219 DCHECK(false);
220 queued_encoded_callbacks_.push_front(callback);
221 return;
223 // Put the callback back first in the queue on a wait event.
224 PostEncodedAudioFrame(true, callback, rtp_timestamp, next_frame,
225 &encoded_frame);
228 void AudioReceiver::GetEncodedAudioFrame(
229 const AudioFrameEncodedCallback& callback) {
230 DCHECK(audio_buffer_) << "Invalid function call in this configuration";
232 uint32 rtp_timestamp = 0;
233 bool next_frame = false;
234 scoped_ptr<EncodedAudioFrame> encoded_frame(new EncodedAudioFrame());
236 if (!audio_buffer_->GetEncodedAudioFrame(encoded_frame.get(),
237 &rtp_timestamp, &next_frame)) {
238 // We have no audio frames. Wait for new packet(s).
239 VLOG(1) << "Wait for more audio packets in frame";
240 queued_encoded_callbacks_.push_back(callback);
241 return;
243 PostEncodedAudioFrame(false, callback, rtp_timestamp, next_frame,
244 &encoded_frame);
247 void AudioReceiver::PostEncodedAudioFrame(
248 bool on_wait_event_put_first_in_queue,
249 const AudioFrameEncodedCallback& callback,
250 uint32 rtp_timestamp,
251 bool next_frame,
252 scoped_ptr<EncodedAudioFrame>* encoded_frame) {
253 base::TimeTicks now = cast_environment_->Clock()->NowTicks();
254 base::TimeTicks playout_time = GetPlayoutTime(now, rtp_timestamp);
255 base::TimeDelta time_until_playout = playout_time - now;
256 base::TimeDelta min_wait_delta =
257 base::TimeDelta::FromMilliseconds(kMaxAudioFrameWaitMs);
259 if (!next_frame && (time_until_playout > min_wait_delta)) {
260 // We have an audio frame; however we are missing packets and we have time
261 // to wait for new packet(s).
262 if (on_wait_event_put_first_in_queue) {
263 queued_encoded_callbacks_.push_front(callback);
264 } else {
265 queued_encoded_callbacks_.push_back(callback);
268 base::TimeDelta time_until_release = time_until_playout - min_wait_delta;
269 cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE,
270 base::Bind(&AudioReceiver::PlayoutTimeout, weak_factory_.GetWeakPtr()),
271 time_until_release);
272 VLOG(1) << "Wait until time to playout:"
273 << time_until_release.InMilliseconds();
274 return;
276 (*encoded_frame)->codec = codec_;
277 audio_buffer_->ReleaseFrame((*encoded_frame)->frame_id);
279 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
280 base::Bind(callback, base::Passed(encoded_frame), playout_time));
283 void AudioReceiver::IncomingPacket(const uint8* packet, size_t length,
284 const base::Closure callback) {
285 bool rtcp_packet = Rtcp::IsRtcpPacket(packet, length);
286 if (!rtcp_packet) {
287 rtp_receiver_->ReceivedPacket(packet, length);
288 } else {
289 rtcp_->IncomingRtcpPacket(packet, length);
291 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, callback);
294 void AudioReceiver::CastFeedback(const RtcpCastMessage& cast_message) {
295 rtcp_->SendRtcpCast(cast_message);
298 base::TimeTicks AudioReceiver::GetPlayoutTime(base::TimeTicks now,
299 uint32 rtp_timestamp) {
300 // Senders time in ms when this frame was recorded.
301 // Note: the senders clock and our local clock might not be synced.
302 base::TimeTicks rtp_timestamp_in_ticks;
303 if (time_offset_ == base::TimeDelta()) {
304 base::TimeTicks time_first_incoming_packet;
305 uint32 first_incoming_rtp_timestamp;
307 incoming_payload_callback_->GetFirstPacketInformation(
308 &time_first_incoming_packet, &first_incoming_rtp_timestamp);
310 if (rtcp_->RtpTimestampInSenderTime(frequency_,
311 first_incoming_rtp_timestamp,
312 &rtp_timestamp_in_ticks)) {
313 time_offset_ = time_first_incoming_packet - rtp_timestamp_in_ticks;
314 } else {
315 // We have not received any RTCP to sync the stream play it out as soon as
316 // possible.
317 uint32 rtp_timestamp_diff =
318 rtp_timestamp - first_incoming_rtp_timestamp;
320 int frequency_khz = frequency_ / 1000;
321 base::TimeDelta rtp_time_diff_delta =
322 base::TimeDelta::FromMilliseconds(rtp_timestamp_diff / frequency_khz);
323 base::TimeDelta time_diff_delta = now - time_first_incoming_packet;
325 return now + std::max(rtp_time_diff_delta - time_diff_delta,
326 base::TimeDelta());
329 // This can fail if we have not received any RTCP packets in a long time.
330 return rtcp_->RtpTimestampInSenderTime(frequency_, rtp_timestamp,
331 &rtp_timestamp_in_ticks) ?
332 rtp_timestamp_in_ticks + time_offset_ + target_delay_delta_ :
333 now;
336 void AudioReceiver::ScheduleNextRtcpReport() {
337 base::TimeDelta time_to_send = rtcp_->TimeToSendNextRtcpReport() -
338 cast_environment_->Clock()->NowTicks();
340 time_to_send = std::max(time_to_send,
341 base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
343 cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE,
344 base::Bind(&AudioReceiver::SendNextRtcpReport,
345 weak_factory_.GetWeakPtr()), time_to_send);
348 void AudioReceiver::SendNextRtcpReport() {
349 rtcp_->SendRtcpReport(incoming_ssrc_);
350 ScheduleNextRtcpReport();
353 } // namespace cast
354 } // namespace media