Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Side by Side Diff: media/cast/audio_receiver/audio_receiver.cc

Issue 280993002: [Cast] Repair receiver playout time calculations and frame skip logic. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added playout_time smoothness checks in End2EndTest. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 // payload yet! Or, at least, peek using a StringPiece instead of a copy. 192 // payload yet! Or, at least, peek using a StringPiece instead of a copy.
169 scoped_ptr<transport::EncodedFrame> encoded_frame( 193 scoped_ptr<transport::EncodedFrame> encoded_frame(
170 new transport::EncodedFrame()); 194 new transport::EncodedFrame());
171 bool is_consecutively_next_frame = false; 195 bool is_consecutively_next_frame = false;
172 if (!framer_.GetEncodedAudioFrame(encoded_frame.get(), 196 if (!framer_.GetEncodedAudioFrame(encoded_frame.get(),
173 &is_consecutively_next_frame)) { 197 &is_consecutively_next_frame)) {
174 VLOG(1) << "Wait for more audio packets to produce a completed frame."; 198 VLOG(1) << "Wait for more audio packets to produce a completed frame.";
175 return; // OnReceivedPayloadData() will invoke this method in the future. 199 return; // OnReceivedPayloadData() will invoke this method in the future.
176 } 200 }
177 201
202 const base::TimeTicks playout_time =
203 GetPlayoutTime(encoded_frame->rtp_timestamp);
204
178 // If |framer_| has a frame ready that is out of sequence, examine the 205 // If |framer_| has a frame ready that is out of sequence, examine the
179 // playout time to determine whether it's acceptable to continue, thereby 206 // playout time to determine whether it's acceptable to continue, thereby
180 // skipping one or more frames. Skip if the missing frame wouldn't complete 207 // skipping one or more frames. Skip if the missing frame wouldn't complete
181 // playing before the start of playback of the available frame. 208 // playing before the start of playback of the available frame.
182 const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
183 const base::TimeTicks playout_time =
184 GetPlayoutTime(now, encoded_frame->rtp_timestamp);
185 if (!is_consecutively_next_frame) { 209 if (!is_consecutively_next_frame) {
210 const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
186 // TODO(miu): Also account for expected decode time here? 211 // TODO(miu): Also account for expected decode time here?
187 const base::TimeTicks earliest_possible_end_time_of_missing_frame = 212 const base::TimeTicks earliest_possible_end_time_of_missing_frame =
188 now + base::TimeDelta::FromMilliseconds(kTypicalAudioFrameDurationMs); 213 now + base::TimeDelta::FromMilliseconds(kTypicalAudioFrameDurationMs);
189 if (earliest_possible_end_time_of_missing_frame < playout_time) { 214 if (earliest_possible_end_time_of_missing_frame < playout_time) {
190 VLOG(1) << "Wait for next consecutive frame instead of skipping."; 215 VLOG(1) << "Wait for next consecutive frame instead of skipping.";
191 if (!is_waiting_for_consecutive_frame_) { 216 if (!is_waiting_for_consecutive_frame_) {
192 is_waiting_for_consecutive_frame_ = true; 217 is_waiting_for_consecutive_frame_ = true;
193 cast_environment_->PostDelayedTask( 218 cast_environment_->PostDelayedTask(
194 CastEnvironment::MAIN, 219 CastEnvironment::MAIN,
195 FROM_HERE, 220 FROM_HERE,
(...skipping 30 matching lines...) Expand all
226 } 251 }
227 } 252 }
228 253
229 void AudioReceiver::EmitAvailableEncodedFramesAfterWaiting() { 254 void AudioReceiver::EmitAvailableEncodedFramesAfterWaiting() {
230 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 255 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
231 DCHECK(is_waiting_for_consecutive_frame_); 256 DCHECK(is_waiting_for_consecutive_frame_);
232 is_waiting_for_consecutive_frame_ = false; 257 is_waiting_for_consecutive_frame_ = false;
233 EmitAvailableEncodedFrames(); 258 EmitAvailableEncodedFrames();
234 } 259 }
235 260
261 base::TimeTicks AudioReceiver::GetPlayoutTime(uint32 rtp_timestamp) const {
262 return lip_sync_reference_time_ +
263 lip_sync_drift_.Current() +
264 RtpDeltaToTimeDelta(
265 static_cast<int32>(rtp_timestamp - lip_sync_rtp_timestamp_),
266 frequency_) +
267 target_playout_delay_;
268 }
269
236 void AudioReceiver::IncomingPacket(scoped_ptr<Packet> packet) { 270 void AudioReceiver::IncomingPacket(scoped_ptr<Packet> packet) {
237 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 271 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
238 if (Rtcp::IsRtcpPacket(&packet->front(), packet->size())) { 272 if (Rtcp::IsRtcpPacket(&packet->front(), packet->size())) {
239 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); 273 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size());
240 } else { 274 } else {
241 ReceivedPacket(&packet->front(), packet->size()); 275 ReceivedPacket(&packet->front(), packet->size());
242 } 276 }
243 } 277 if (!reports_are_scheduled_) {
244 278 ScheduleNextRtcpReport();
245 void AudioReceiver::SetTargetDelay(base::TimeDelta target_delay) { 279 ScheduleNextCastMessage();
246 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 280 reports_are_scheduled_ = true;
247 target_delay_delta_ = target_delay; 281 }
248 rtcp_.SetTargetDelay(target_delay_delta_);
249 } 282 }
250 283
251 void AudioReceiver::CastFeedback(const RtcpCastMessage& cast_message) { 284 void AudioReceiver::CastFeedback(const RtcpCastMessage& cast_message) {
252 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 285 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
253 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); 286 base::TimeTicks now = cast_environment_->Clock()->NowTicks();
254 RtpTimestamp rtp_timestamp = 287 RtpTimestamp rtp_timestamp =
255 frame_id_to_rtp_timestamp_[cast_message.ack_frame_id_ & 0xff]; 288 frame_id_to_rtp_timestamp_[cast_message.ack_frame_id_ & 0xff];
256 cast_environment_->Logging()->InsertFrameEvent( 289 cast_environment_->Logging()->InsertFrameEvent(
257 now, FRAME_ACK_SENT, AUDIO_EVENT, rtp_timestamp, 290 now, FRAME_ACK_SENT, AUDIO_EVENT, rtp_timestamp,
258 cast_message.ack_frame_id_); 291 cast_message.ack_frame_id_);
259 292
260 ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events; 293 ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
261 event_subscriber_.GetRtcpEventsAndReset(&rtcp_events); 294 event_subscriber_.GetRtcpEventsAndReset(&rtcp_events);
262 rtcp_.SendRtcpFromRtpReceiver(&cast_message, &rtcp_events); 295 rtcp_.SendRtcpFromRtpReceiver(&cast_message, &rtcp_events);
263 } 296 }
264 297
265 base::TimeTicks AudioReceiver::GetPlayoutTime(base::TimeTicks now,
266 uint32 rtp_timestamp) {
267 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
268 // Senders time in ms when this frame was recorded.
269 // Note: the senders clock and our local clock might not be synced.
270 base::TimeTicks rtp_timestamp_in_ticks;
271 base::TimeTicks playout_time;
272 if (time_offset_ == base::TimeDelta()) {
273 if (rtcp_.RtpTimestampInSenderTime(frequency_,
274 first_incoming_rtp_timestamp_,
275 &rtp_timestamp_in_ticks)) {
276 time_offset_ = time_first_incoming_packet_ - rtp_timestamp_in_ticks;
277 // TODO(miu): As clocks drift w.r.t. each other, and other factors take
278 // effect, |time_offset_| should be updated. Otherwise, we might as well
279 // always compute the time offsets agnostic of RTCP's time data.
280 } else {
281 // We have not received any RTCP to sync the stream play it out as soon as
282 // possible.
283
284 // BUG: This means we're literally switching to a different timeline a
285 // short time after a cast receiver has been running. Re-enable
286 // End2EndTest.StartSenderBeforeReceiver once this is fixed.
287 // http://crbug.com/356942
288 uint32 rtp_timestamp_diff = rtp_timestamp - first_incoming_rtp_timestamp_;
289
290 int frequency_khz = frequency_ / 1000;
291 base::TimeDelta rtp_time_diff_delta =
292 base::TimeDelta::FromMilliseconds(rtp_timestamp_diff / frequency_khz);
293 base::TimeDelta time_diff_delta = now - time_first_incoming_packet_;
294
295 playout_time = now + std::max(rtp_time_diff_delta - time_diff_delta,
296 base::TimeDelta());
297 }
298 }
299 if (playout_time.is_null()) {
300 // This can fail if we have not received any RTCP packets in a long time.
301 if (rtcp_.RtpTimestampInSenderTime(frequency_, rtp_timestamp,
302 &rtp_timestamp_in_ticks)) {
303 playout_time =
304 rtp_timestamp_in_ticks + time_offset_ + target_delay_delta_;
305 } else {
306 playout_time = now;
307 }
308 }
309
310 // TODO(miu): This is broken since we literally switch timelines once |rtcp_|
311 // can provide us the |time_offset_|. Furthermore, this "getter" method may
312 // be called on frames received out-of-order, which means the playout times
313 // for earlier frames will be computed incorrectly.
314 #if 0
315 // Don't allow the playout time to go backwards.
316 if (last_playout_time_ > playout_time) playout_time = last_playout_time_;
317 last_playout_time_ = playout_time;
318 #endif
319
320 return playout_time;
321 }
322
323 void AudioReceiver::ScheduleNextRtcpReport() { 298 void AudioReceiver::ScheduleNextRtcpReport() {
324 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 299 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
325 base::TimeDelta time_to_send = rtcp_.TimeToSendNextRtcpReport() - 300 base::TimeDelta time_to_send = rtcp_.TimeToSendNextRtcpReport() -
326 cast_environment_->Clock()->NowTicks(); 301 cast_environment_->Clock()->NowTicks();
327 302
328 time_to_send = std::max( 303 time_to_send = std::max(
329 time_to_send, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); 304 time_to_send, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
330 305
331 cast_environment_->PostDelayedTask( 306 cast_environment_->PostDelayedTask(
332 CastEnvironment::MAIN, 307 CastEnvironment::MAIN,
(...skipping 29 matching lines...) Expand all
362 } 337 }
363 338
364 void AudioReceiver::SendNextCastMessage() { 339 void AudioReceiver::SendNextCastMessage() {
365 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 340 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
366 framer_.SendCastMessage(); // Will only send a message if it is time. 341 framer_.SendCastMessage(); // Will only send a message if it is time.
367 ScheduleNextCastMessage(); 342 ScheduleNextCastMessage();
368 } 343 }
369 344
370 } // namespace cast 345 } // namespace cast
371 } // namespace media 346 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698