OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/cast/audio_receiver/audio_receiver.h" | 5 #include "media/cast/audio_receiver/audio_receiver.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 namespace cast { | 22 namespace cast { |
23 | 23 |
24 AudioReceiver::AudioReceiver(scoped_refptr<CastEnvironment> cast_environment, | 24 AudioReceiver::AudioReceiver(scoped_refptr<CastEnvironment> cast_environment, |
25 const AudioReceiverConfig& audio_config, | 25 const AudioReceiverConfig& audio_config, |
26 transport::PacedPacketSender* const packet_sender) | 26 transport::PacedPacketSender* const packet_sender) |
27 : RtpReceiver(cast_environment->Clock(), &audio_config, NULL), | 27 : RtpReceiver(cast_environment->Clock(), &audio_config, NULL), |
28 cast_environment_(cast_environment), | 28 cast_environment_(cast_environment), |
29 event_subscriber_(kReceiverRtcpEventHistorySize, AUDIO_EVENT), | 29 event_subscriber_(kReceiverRtcpEventHistorySize, AUDIO_EVENT), |
30 codec_(audio_config.codec), | 30 codec_(audio_config.codec), |
31 frequency_(audio_config.frequency), | 31 frequency_(audio_config.frequency), |
32 target_delay_delta_( | 32 target_playout_delay_( |
33 base::TimeDelta::FromMilliseconds(audio_config.rtp_max_delay_ms)), | 33 base::TimeDelta::FromMilliseconds(audio_config.rtp_max_delay_ms)), |
| 34 reports_are_scheduled_(false), |
34 framer_(cast_environment->Clock(), | 35 framer_(cast_environment->Clock(), |
35 this, | 36 this, |
36 audio_config.incoming_ssrc, | 37 audio_config.incoming_ssrc, |
37 true, | 38 true, |
38 audio_config.rtp_max_delay_ms / kTypicalAudioFrameDurationMs), | 39 audio_config.rtp_max_delay_ms / kTypicalAudioFrameDurationMs), |
39 rtcp_(cast_environment, | 40 rtcp_(cast_environment, |
40 NULL, | 41 NULL, |
41 NULL, | 42 NULL, |
42 packet_sender, | 43 packet_sender, |
43 GetStatistics(), | 44 GetStatistics(), |
44 audio_config.rtcp_mode, | 45 audio_config.rtcp_mode, |
45 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval), | 46 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval), |
46 audio_config.feedback_ssrc, | 47 audio_config.feedback_ssrc, |
47 audio_config.incoming_ssrc, | 48 audio_config.incoming_ssrc, |
48 audio_config.rtcp_c_name, | 49 audio_config.rtcp_c_name, |
49 true), | 50 true), |
50 is_waiting_for_consecutive_frame_(false), | 51 is_waiting_for_consecutive_frame_(false), |
| 52 lip_sync_drift_(ClockDriftSmoother::GetDefaultTimeConstant()), |
51 weak_factory_(this) { | 53 weak_factory_(this) { |
52 if (!audio_config.use_external_decoder) | 54 if (!audio_config.use_external_decoder) |
53 audio_decoder_.reset(new AudioDecoder(cast_environment, audio_config)); | 55 audio_decoder_.reset(new AudioDecoder(cast_environment, audio_config)); |
54 decryptor_.Initialize(audio_config.aes_key, audio_config.aes_iv_mask); | 56 decryptor_.Initialize(audio_config.aes_key, audio_config.aes_iv_mask); |
55 rtcp_.SetTargetDelay(target_delay_delta_); | 57 rtcp_.SetTargetDelay(target_playout_delay_); |
56 cast_environment_->Logging()->AddRawEventSubscriber(&event_subscriber_); | 58 cast_environment_->Logging()->AddRawEventSubscriber(&event_subscriber_); |
57 memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_)); | 59 memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_)); |
58 } | 60 } |
59 | 61 |
60 AudioReceiver::~AudioReceiver() { | 62 AudioReceiver::~AudioReceiver() { |
61 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 63 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
62 cast_environment_->Logging()->RemoveRawEventSubscriber(&event_subscriber_); | 64 cast_environment_->Logging()->RemoveRawEventSubscriber(&event_subscriber_); |
63 } | 65 } |
64 | 66 |
65 void AudioReceiver::InitializeTimers() { | |
66 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
67 ScheduleNextRtcpReport(); | |
68 ScheduleNextCastMessage(); | |
69 } | |
70 | |
71 void AudioReceiver::OnReceivedPayloadData(const uint8* payload_data, | 67 void AudioReceiver::OnReceivedPayloadData(const uint8* payload_data, |
72 size_t payload_size, | 68 size_t payload_size, |
73 const RtpCastHeader& rtp_header) { | 69 const RtpCastHeader& rtp_header) { |
74 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 70 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
75 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | |
76 | 71 |
77 // TODO(pwestin): update this as video to refresh over time. | 72 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
78 if (time_first_incoming_packet_.is_null()) { | |
79 InitializeTimers(); | |
80 first_incoming_rtp_timestamp_ = rtp_header.rtp_timestamp; | |
81 time_first_incoming_packet_ = now; | |
82 } | |
83 | 73 |
84 frame_id_to_rtp_timestamp_[rtp_header.frame_id & 0xff] = | 74 frame_id_to_rtp_timestamp_[rtp_header.frame_id & 0xff] = |
85 rtp_header.rtp_timestamp; | 75 rtp_header.rtp_timestamp; |
86 cast_environment_->Logging()->InsertPacketEvent( | 76 cast_environment_->Logging()->InsertPacketEvent( |
87 now, PACKET_RECEIVED, AUDIO_EVENT, rtp_header.rtp_timestamp, | 77 now, PACKET_RECEIVED, AUDIO_EVENT, rtp_header.rtp_timestamp, |
88 rtp_header.frame_id, rtp_header.packet_id, rtp_header.max_packet_id, | 78 rtp_header.frame_id, rtp_header.packet_id, rtp_header.max_packet_id, |
89 payload_size); | 79 payload_size); |
90 | 80 |
91 bool duplicate = false; | 81 bool duplicate = false; |
92 const bool complete = | 82 const bool complete = |
93 framer_.InsertPacket(payload_data, payload_size, rtp_header, &duplicate); | 83 framer_.InsertPacket(payload_data, payload_size, rtp_header, &duplicate); |
94 | 84 |
95 // Duplicate packets are ignored. | 85 // Duplicate packets are ignored. |
96 if (duplicate || !complete) | 86 if (duplicate) |
| 87 return; |
| 88 |
| 89 // Update lip-sync values upon receiving the first packet of each frame, or if |
| 90 // they have never been set yet. |
| 91 if (rtp_header.packet_id == 0 || lip_sync_reference_time_.is_null()) { |
| 92 RtpTimestamp fresh_sync_rtp; |
| 93 base::TimeTicks fresh_sync_reference; |
| 94 if (!rtcp_.GetLatestLipSyncTimes(&fresh_sync_rtp, &fresh_sync_reference)) { |
| 95 // HACK: The sender should have provided Sender Reports before the first |
| 96 // frame was sent. However, the spec does not currently require this. |
| 97 // Therefore, when the data is missing, the local clock is used to |
| 98 // generate reference timestamps. |
| 99 VLOG(2) << "Lip sync info missing. Falling-back to local clock."; |
| 100 fresh_sync_rtp = rtp_header.rtp_timestamp; |
| 101 fresh_sync_reference = now; |
| 102 } |
| 103 // |lip_sync_reference_time_| is always incremented according to the time |
| 104 // delta computed from the difference in RTP timestamps. Then, |
| 105 // |lip_sync_drift_| accounts for clock drift and also smoothes-out any |
| 106 // sudden/discontinuous shifts in the series of reference time values. |
| 107 if (lip_sync_reference_time_.is_null()) { |
| 108 lip_sync_reference_time_ = fresh_sync_reference; |
| 109 } else { |
| 110 lip_sync_reference_time_ += RtpDeltaToTimeDelta( |
| 111 static_cast<int32>(fresh_sync_rtp - lip_sync_rtp_timestamp_), |
| 112 frequency_); |
| 113 } |
| 114 lip_sync_rtp_timestamp_ = fresh_sync_rtp; |
| 115 lip_sync_drift_.Update( |
| 116 now, fresh_sync_reference - lip_sync_reference_time_); |
| 117 } |
| 118 |
| 119 // Frame not complete; wait for more packets. |
| 120 if (!complete) |
97 return; | 121 return; |
98 | 122 |
99 EmitAvailableEncodedFrames(); | 123 EmitAvailableEncodedFrames(); |
100 } | 124 } |
101 | 125 |
102 void AudioReceiver::GetRawAudioFrame( | 126 void AudioReceiver::GetRawAudioFrame( |
103 const AudioFrameDecodedCallback& callback) { | 127 const AudioFrameDecodedCallback& callback) { |
104 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 128 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
105 DCHECK(!callback.is_null()); | 129 DCHECK(!callback.is_null()); |
106 DCHECK(audio_decoder_.get()); | 130 DCHECK(audio_decoder_.get()); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 bool have_multiple_complete_frames = false; | 196 bool have_multiple_complete_frames = false; |
173 if (!framer_.GetEncodedFrame(encoded_frame.get(), | 197 if (!framer_.GetEncodedFrame(encoded_frame.get(), |
174 &is_consecutively_next_frame, | 198 &is_consecutively_next_frame, |
175 &have_multiple_complete_frames)) { | 199 &have_multiple_complete_frames)) { |
176 VLOG(1) << "Wait for more audio packets to produce a completed frame."; | 200 VLOG(1) << "Wait for more audio packets to produce a completed frame."; |
177 return; // OnReceivedPayloadData() will invoke this method in the future. | 201 return; // OnReceivedPayloadData() will invoke this method in the future. |
178 } | 202 } |
179 | 203 |
180 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 204 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
181 const base::TimeTicks playout_time = | 205 const base::TimeTicks playout_time = |
182 GetPlayoutTime(now, encoded_frame->rtp_timestamp); | 206 GetPlayoutTime(encoded_frame->rtp_timestamp); |
183 | 207 |
184 // If we have multiple decodable frames, and the current frame is | 208 // If we have multiple decodable frames, and the current frame is |
185 // too old, then skip it and decode the next frame instead. | 209 // too old, then skip it and decode the next frame instead. |
186 if (have_multiple_complete_frames && now > playout_time) { | 210 if (have_multiple_complete_frames && now > playout_time) { |
187 framer_.ReleaseFrame(encoded_frame->frame_id); | 211 framer_.ReleaseFrame(encoded_frame->frame_id); |
188 continue; | 212 continue; |
189 } | 213 } |
190 | 214 |
191 // If |framer_| has a frame ready that is out of sequence, examine the | 215 // If |framer_| has a frame ready that is out of sequence, examine the |
192 // playout time to determine whether it's acceptable to continue, thereby | 216 // playout time to determine whether it's acceptable to continue, thereby |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 } | 260 } |
237 } | 261 } |
238 | 262 |
239 void AudioReceiver::EmitAvailableEncodedFramesAfterWaiting() { | 263 void AudioReceiver::EmitAvailableEncodedFramesAfterWaiting() { |
240 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 264 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
241 DCHECK(is_waiting_for_consecutive_frame_); | 265 DCHECK(is_waiting_for_consecutive_frame_); |
242 is_waiting_for_consecutive_frame_ = false; | 266 is_waiting_for_consecutive_frame_ = false; |
243 EmitAvailableEncodedFrames(); | 267 EmitAvailableEncodedFrames(); |
244 } | 268 } |
245 | 269 |
| 270 base::TimeTicks AudioReceiver::GetPlayoutTime(uint32 rtp_timestamp) const { |
| 271 return lip_sync_reference_time_ + |
| 272 lip_sync_drift_.Current() + |
| 273 RtpDeltaToTimeDelta( |
| 274 static_cast<int32>(rtp_timestamp - lip_sync_rtp_timestamp_), |
| 275 frequency_) + |
| 276 target_playout_delay_; |
| 277 } |
| 278 |
246 void AudioReceiver::IncomingPacket(scoped_ptr<Packet> packet) { | 279 void AudioReceiver::IncomingPacket(scoped_ptr<Packet> packet) { |
247 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 280 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
248 if (Rtcp::IsRtcpPacket(&packet->front(), packet->size())) { | 281 if (Rtcp::IsRtcpPacket(&packet->front(), packet->size())) { |
249 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); | 282 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); |
250 } else { | 283 } else { |
251 ReceivedPacket(&packet->front(), packet->size()); | 284 ReceivedPacket(&packet->front(), packet->size()); |
252 } | 285 } |
253 } | 286 if (!reports_are_scheduled_) { |
254 | 287 ScheduleNextRtcpReport(); |
255 void AudioReceiver::SetTargetDelay(base::TimeDelta target_delay) { | 288 ScheduleNextCastMessage(); |
256 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 289 reports_are_scheduled_ = true; |
257 target_delay_delta_ = target_delay; | 290 } |
258 rtcp_.SetTargetDelay(target_delay_delta_); | |
259 } | 291 } |
260 | 292 |
261 void AudioReceiver::CastFeedback(const RtcpCastMessage& cast_message) { | 293 void AudioReceiver::CastFeedback(const RtcpCastMessage& cast_message) { |
262 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 294 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
263 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 295 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
264 RtpTimestamp rtp_timestamp = | 296 RtpTimestamp rtp_timestamp = |
265 frame_id_to_rtp_timestamp_[cast_message.ack_frame_id_ & 0xff]; | 297 frame_id_to_rtp_timestamp_[cast_message.ack_frame_id_ & 0xff]; |
266 cast_environment_->Logging()->InsertFrameEvent( | 298 cast_environment_->Logging()->InsertFrameEvent( |
267 now, FRAME_ACK_SENT, AUDIO_EVENT, rtp_timestamp, | 299 now, FRAME_ACK_SENT, AUDIO_EVENT, rtp_timestamp, |
268 cast_message.ack_frame_id_); | 300 cast_message.ack_frame_id_); |
269 | 301 |
270 ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events; | 302 ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events; |
271 event_subscriber_.GetRtcpEventsAndReset(&rtcp_events); | 303 event_subscriber_.GetRtcpEventsAndReset(&rtcp_events); |
272 rtcp_.SendRtcpFromRtpReceiver(&cast_message, &rtcp_events); | 304 rtcp_.SendRtcpFromRtpReceiver(&cast_message, &rtcp_events); |
273 } | 305 } |
274 | 306 |
275 base::TimeTicks AudioReceiver::GetPlayoutTime(base::TimeTicks now, | |
276 uint32 rtp_timestamp) { | |
277 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
278 // Senders time in ms when this frame was recorded. | |
279 // Note: the senders clock and our local clock might not be synced. | |
280 base::TimeTicks rtp_timestamp_in_ticks; | |
281 base::TimeTicks playout_time; | |
282 if (time_offset_ == base::TimeDelta()) { | |
283 if (rtcp_.RtpTimestampInSenderTime(frequency_, | |
284 first_incoming_rtp_timestamp_, | |
285 &rtp_timestamp_in_ticks)) { | |
286 time_offset_ = time_first_incoming_packet_ - rtp_timestamp_in_ticks; | |
287 // TODO(miu): As clocks drift w.r.t. each other, and other factors take | |
288 // effect, |time_offset_| should be updated. Otherwise, we might as well | |
289 // always compute the time offsets agnostic of RTCP's time data. | |
290 } else { | |
291 // We have not received any RTCP to sync the stream play it out as soon as | |
292 // possible. | |
293 | |
294 // BUG: This means we're literally switching to a different timeline a | |
295 // short time after a cast receiver has been running. Re-enable | |
296 // End2EndTest.StartSenderBeforeReceiver once this is fixed. | |
297 // http://crbug.com/356942 | |
298 uint32 rtp_timestamp_diff = rtp_timestamp - first_incoming_rtp_timestamp_; | |
299 | |
300 int frequency_khz = frequency_ / 1000; | |
301 base::TimeDelta rtp_time_diff_delta = | |
302 base::TimeDelta::FromMilliseconds(rtp_timestamp_diff / frequency_khz); | |
303 base::TimeDelta time_diff_delta = now - time_first_incoming_packet_; | |
304 | |
305 playout_time = now + std::max(rtp_time_diff_delta - time_diff_delta, | |
306 base::TimeDelta()); | |
307 } | |
308 } | |
309 if (playout_time.is_null()) { | |
310 // This can fail if we have not received any RTCP packets in a long time. | |
311 if (rtcp_.RtpTimestampInSenderTime(frequency_, rtp_timestamp, | |
312 &rtp_timestamp_in_ticks)) { | |
313 playout_time = | |
314 rtp_timestamp_in_ticks + time_offset_ + target_delay_delta_; | |
315 } else { | |
316 playout_time = now; | |
317 } | |
318 } | |
319 | |
320 // TODO(miu): This is broken since we literally switch timelines once |rtcp_| | |
321 // can provide us the |time_offset_|. Furthermore, this "getter" method may | |
322 // be called on frames received out-of-order, which means the playout times | |
323 // for earlier frames will be computed incorrectly. | |
324 #if 0 | |
325 // Don't allow the playout time to go backwards. | |
326 if (last_playout_time_ > playout_time) playout_time = last_playout_time_; | |
327 last_playout_time_ = playout_time; | |
328 #endif | |
329 | |
330 return playout_time; | |
331 } | |
332 | |
333 void AudioReceiver::ScheduleNextRtcpReport() { | 307 void AudioReceiver::ScheduleNextRtcpReport() { |
334 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 308 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
335 base::TimeDelta time_to_send = rtcp_.TimeToSendNextRtcpReport() - | 309 base::TimeDelta time_to_send = rtcp_.TimeToSendNextRtcpReport() - |
336 cast_environment_->Clock()->NowTicks(); | 310 cast_environment_->Clock()->NowTicks(); |
337 | 311 |
338 time_to_send = std::max( | 312 time_to_send = std::max( |
339 time_to_send, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | 313 time_to_send, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); |
340 | 314 |
341 cast_environment_->PostDelayedTask( | 315 cast_environment_->PostDelayedTask( |
342 CastEnvironment::MAIN, | 316 CastEnvironment::MAIN, |
(...skipping 29 matching lines...) Expand all Loading... |
372 } | 346 } |
373 | 347 |
374 void AudioReceiver::SendNextCastMessage() { | 348 void AudioReceiver::SendNextCastMessage() { |
375 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 349 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
376 framer_.SendCastMessage(); // Will only send a message if it is time. | 350 framer_.SendCastMessage(); // Will only send a message if it is time. |
377 ScheduleNextCastMessage(); | 351 ScheduleNextCastMessage(); |
378 } | 352 } |
379 | 353 |
380 } // namespace cast | 354 } // namespace cast |
381 } // namespace media | 355 } // namespace media |
OLD | NEW |