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

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: Addressed hubbe's comments. 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_to_emit_frames_(false),
51 weak_factory_(this) { 52 weak_factory_(this) {
52 if (!audio_config.use_external_decoder) 53 if (!audio_config.use_external_decoder)
53 audio_decoder_.reset(new AudioDecoder(cast_environment, audio_config)); 54 audio_decoder_.reset(new AudioDecoder(cast_environment, audio_config));
54 decryptor_.Initialize(audio_config.aes_key, audio_config.aes_iv_mask); 55 decryptor_.Initialize(audio_config.aes_key, audio_config.aes_iv_mask);
55 rtcp_.SetTargetDelay(target_delay_delta_); 56 rtcp_.SetTargetDelay(target_playout_delay_);
56 cast_environment_->Logging()->AddRawEventSubscriber(&event_subscriber_); 57 cast_environment_->Logging()->AddRawEventSubscriber(&event_subscriber_);
57 memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_)); 58 memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_));
58 } 59 }
59 60
60 AudioReceiver::~AudioReceiver() { 61 AudioReceiver::~AudioReceiver() {
61 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 62 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
62 cast_environment_->Logging()->RemoveRawEventSubscriber(&event_subscriber_); 63 cast_environment_->Logging()->RemoveRawEventSubscriber(&event_subscriber_);
63 } 64 }
64 65
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, 66 void AudioReceiver::OnReceivedPayloadData(const uint8* payload_data,
72 size_t payload_size, 67 size_t payload_size,
73 const RtpCastHeader& rtp_header) { 68 const RtpCastHeader& rtp_header) {
74 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 69 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
75 base::TimeTicks now = cast_environment_->Clock()->NowTicks();
76 70
77 // TODO(pwestin): update this as video to refresh over time. 71 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 72
84 frame_id_to_rtp_timestamp_[rtp_header.frame_id & 0xff] = 73 frame_id_to_rtp_timestamp_[rtp_header.frame_id & 0xff] =
85 rtp_header.rtp_timestamp; 74 rtp_header.rtp_timestamp;
86 cast_environment_->Logging()->InsertPacketEvent( 75 cast_environment_->Logging()->InsertPacketEvent(
87 now, PACKET_RECEIVED, AUDIO_EVENT, rtp_header.rtp_timestamp, 76 now, PACKET_RECEIVED, AUDIO_EVENT, rtp_header.rtp_timestamp,
88 rtp_header.frame_id, rtp_header.packet_id, rtp_header.max_packet_id, 77 rtp_header.frame_id, rtp_header.packet_id, rtp_header.max_packet_id,
89 payload_size); 78 payload_size);
90 79
91 bool duplicate = false; 80 bool duplicate = false;
92 const bool complete = 81 const bool complete =
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 // payload yet! Or, at least, peek using a StringPiece instead of a copy. 158 // payload yet! Or, at least, peek using a StringPiece instead of a copy.
170 scoped_ptr<transport::EncodedAudioFrame> encoded_frame( 159 scoped_ptr<transport::EncodedAudioFrame> encoded_frame(
171 new transport::EncodedAudioFrame()); 160 new transport::EncodedAudioFrame());
172 bool is_consecutively_next_frame = false; 161 bool is_consecutively_next_frame = false;
173 if (!framer_.GetEncodedAudioFrame(encoded_frame.get(), 162 if (!framer_.GetEncodedAudioFrame(encoded_frame.get(),
174 &is_consecutively_next_frame)) { 163 &is_consecutively_next_frame)) {
175 VLOG(1) << "Wait for more audio packets to produce a completed frame."; 164 VLOG(1) << "Wait for more audio packets to produce a completed frame.";
176 return; // OnReceivedPayloadData() will invoke this method in the future. 165 return; // OnReceivedPayloadData() will invoke this method in the future.
177 } 166 }
178 167
168 const base::TimeTicks playout_time =
169 GetPlayoutTime(encoded_frame->rtp_timestamp);
170
179 // If |framer_| has a frame ready that is out of sequence, examine the 171 // If |framer_| has a frame ready that is out of sequence, examine the
180 // playout time to determine whether it's acceptable to continue, thereby 172 // playout time to determine whether it's acceptable to continue, thereby
181 // skipping one or more frames. Skip if the missing frame wouldn't complete 173 // skipping one or more frames. Skip if the missing frame wouldn't complete
182 // playing before the start of playback of the available frame. 174 // playing before the start of playback of the available frame.
183 const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
184 const base::TimeTicks playout_time =
185 GetPlayoutTime(now, encoded_frame->rtp_timestamp);
186 if (!is_consecutively_next_frame) { 175 if (!is_consecutively_next_frame) {
176 const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
187 // TODO(miu): Also account for expected decode time here? 177 // TODO(miu): Also account for expected decode time here?
188 const base::TimeTicks earliest_possible_end_time_of_missing_frame = 178 const base::TimeTicks earliest_possible_end_time_of_missing_frame =
189 now + base::TimeDelta::FromMilliseconds(kTypicalAudioFrameDurationMs); 179 now + base::TimeDelta::FromMilliseconds(kTypicalAudioFrameDurationMs);
190 if (earliest_possible_end_time_of_missing_frame < playout_time) { 180 if (earliest_possible_end_time_of_missing_frame < playout_time) {
191 VLOG(1) << "Wait for next consecutive frame instead of skipping."; 181 VLOG(1) << "Wait for next consecutive frame instead of skipping.";
192 if (!is_waiting_for_consecutive_frame_) { 182 RetryEmitAfterWaiting(playout_time - now);
193 is_waiting_for_consecutive_frame_ = true;
194 cast_environment_->PostDelayedTask(
195 CastEnvironment::MAIN,
196 FROM_HERE,
197 base::Bind(&AudioReceiver::EmitAvailableEncodedFramesAfterWaiting,
198 weak_factory_.GetWeakPtr()),
199 playout_time - now);
200 }
201 return; 183 return;
202 } 184 }
203 } 185 }
204 186
205 // Decrypt the payload data in the frame, if crypto is being used. 187 // Decrypt the payload data in the frame, if crypto is being used.
206 if (decryptor_.initialized()) { 188 if (decryptor_.initialized()) {
207 std::string decrypted_audio_data; 189 std::string decrypted_audio_data;
208 if (!decryptor_.Decrypt(encoded_frame->frame_id, 190 if (!decryptor_.Decrypt(encoded_frame->frame_id,
209 encoded_frame->data, 191 encoded_frame->data,
210 &decrypted_audio_data)) { 192 &decrypted_audio_data)) {
(...skipping 10 matching lines...) Expand all
221 framer_.ReleaseFrame(encoded_frame->frame_id); 203 framer_.ReleaseFrame(encoded_frame->frame_id);
222 cast_environment_->PostTask(CastEnvironment::MAIN, 204 cast_environment_->PostTask(CastEnvironment::MAIN,
223 FROM_HERE, 205 FROM_HERE,
224 base::Bind(frame_request_queue_.front(), 206 base::Bind(frame_request_queue_.front(),
225 base::Passed(&encoded_frame), 207 base::Passed(&encoded_frame),
226 playout_time)); 208 playout_time));
227 frame_request_queue_.pop_front(); 209 frame_request_queue_.pop_front();
228 } 210 }
229 } 211 }
230 212
213 void AudioReceiver::RetryEmitAfterWaiting(base::TimeDelta wait_time) {
hubbe 2014/05/19 17:52:20 This doesn't seem complicated enough to break out
miu 2014/05/23 03:09:01 Done.
214 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
215 if (is_waiting_to_emit_frames_)
216 return;
217 is_waiting_to_emit_frames_ = true;
218 cast_environment_->PostDelayedTask(
219 CastEnvironment::MAIN,
220 FROM_HERE,
221 base::Bind(&AudioReceiver::EmitAvailableEncodedFramesAfterWaiting,
222 weak_factory_.GetWeakPtr()),
223 wait_time);
224 }
225
231 void AudioReceiver::EmitAvailableEncodedFramesAfterWaiting() { 226 void AudioReceiver::EmitAvailableEncodedFramesAfterWaiting() {
232 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 227 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
233 DCHECK(is_waiting_for_consecutive_frame_); 228 DCHECK(is_waiting_to_emit_frames_);
234 is_waiting_for_consecutive_frame_ = false; 229 is_waiting_to_emit_frames_ = false;
235 EmitAvailableEncodedFrames(); 230 EmitAvailableEncodedFrames();
236 } 231 }
237 232
233 base::TimeTicks AudioReceiver::GetPlayoutTime(uint32 rtp_timestamp) const {
234 base::TimeTicks capture_time = rtcp_.ToApproximateCaptureTime(rtp_timestamp,
235 frequency_);
236
237 // HACK: The sender should have provided Sender Reports which allow this
238 // receiver to map RTP timestamps back to the time the frame was captured on
239 // the sender. It should have done this before sending the first frame, but
240 // the spec does not currently require this. Therefore, if the data is
241 // missing, this receiver is forced to take a guess.
242 //
243 // The guess is based on a number of assumptions which in many environments
244 // will be completely wrong:
245 // 1. The difference between the sender clock and receiver clock (relative
246 // to NTP epoch) is very close to zero.
247 // 2. The amount of time the sender took to encode/process the frame before
248 // transport is approximately 1/2 the amount of time between frames.
249 // 3. Perfect network conditions (i.e., negligible latency, no packet loss,
250 // frames are arriving in-order, etc.).
251 if (capture_time.is_null()) {
252 VLOG(1) << ("Guessing playout time because sender has not yet sent lip "
253 "sync info. Expect jank in the near future!");
254 capture_time = cast_environment_->Clock()->NowTicks() -
hubbe 2014/05/19 17:52:20 This is not a very good guess. I think the guess s
miu 2014/05/23 03:09:01 Done. See the code I added in OnReceivedPayloadDa
255 (base::TimeDelta::FromMilliseconds(kTypicalAudioFrameDurationMs) / 2);
256 }
257
258 return capture_time + target_playout_delay_;
259 }
260
238 void AudioReceiver::IncomingPacket(scoped_ptr<Packet> packet) { 261 void AudioReceiver::IncomingPacket(scoped_ptr<Packet> packet) {
239 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 262 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
240 if (Rtcp::IsRtcpPacket(&packet->front(), packet->size())) { 263 if (Rtcp::IsRtcpPacket(&packet->front(), packet->size())) {
241 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); 264 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size());
242 } else { 265 } else {
243 ReceivedPacket(&packet->front(), packet->size()); 266 ReceivedPacket(&packet->front(), packet->size());
244 } 267 }
245 } 268 if (!reports_are_scheduled_) {
246 269 ScheduleNextRtcpReport();
247 void AudioReceiver::SetTargetDelay(base::TimeDelta target_delay) { 270 ScheduleNextCastMessage();
248 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 271 reports_are_scheduled_ = true;
249 target_delay_delta_ = target_delay; 272 }
250 rtcp_.SetTargetDelay(target_delay_delta_);
251 } 273 }
252 274
253 void AudioReceiver::CastFeedback(const RtcpCastMessage& cast_message) { 275 void AudioReceiver::CastFeedback(const RtcpCastMessage& cast_message) {
254 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 276 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
255 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); 277 base::TimeTicks now = cast_environment_->Clock()->NowTicks();
256 RtpTimestamp rtp_timestamp = 278 RtpTimestamp rtp_timestamp =
257 frame_id_to_rtp_timestamp_[cast_message.ack_frame_id_ & 0xff]; 279 frame_id_to_rtp_timestamp_[cast_message.ack_frame_id_ & 0xff];
258 cast_environment_->Logging()->InsertFrameEvent( 280 cast_environment_->Logging()->InsertFrameEvent(
259 now, FRAME_ACK_SENT, AUDIO_EVENT, rtp_timestamp, 281 now, FRAME_ACK_SENT, AUDIO_EVENT, rtp_timestamp,
260 cast_message.ack_frame_id_); 282 cast_message.ack_frame_id_);
261 283
262 ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events; 284 ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events;
263 event_subscriber_.GetRtcpEventsAndReset(&rtcp_events); 285 event_subscriber_.GetRtcpEventsAndReset(&rtcp_events);
264 rtcp_.SendRtcpFromRtpReceiver(&cast_message, &rtcp_events); 286 rtcp_.SendRtcpFromRtpReceiver(&cast_message, &rtcp_events);
265 } 287 }
266 288
267 base::TimeTicks AudioReceiver::GetPlayoutTime(base::TimeTicks now,
268 uint32 rtp_timestamp) {
269 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
270 // Senders time in ms when this frame was recorded.
271 // Note: the senders clock and our local clock might not be synced.
272 base::TimeTicks rtp_timestamp_in_ticks;
273 base::TimeTicks playout_time;
274 if (time_offset_ == base::TimeDelta()) {
275 if (rtcp_.RtpTimestampInSenderTime(frequency_,
276 first_incoming_rtp_timestamp_,
277 &rtp_timestamp_in_ticks)) {
278 time_offset_ = time_first_incoming_packet_ - rtp_timestamp_in_ticks;
279 // TODO(miu): As clocks drift w.r.t. each other, and other factors take
280 // effect, |time_offset_| should be updated. Otherwise, we might as well
281 // always compute the time offsets agnostic of RTCP's time data.
282 } else {
283 // We have not received any RTCP to sync the stream play it out as soon as
284 // possible.
285
286 // BUG: This means we're literally switching to a different timeline a
287 // short time after a cast receiver has been running. Re-enable
288 // End2EndTest.StartSenderBeforeReceiver once this is fixed.
289 // http://crbug.com/356942
290 uint32 rtp_timestamp_diff = rtp_timestamp - first_incoming_rtp_timestamp_;
291
292 int frequency_khz = frequency_ / 1000;
293 base::TimeDelta rtp_time_diff_delta =
294 base::TimeDelta::FromMilliseconds(rtp_timestamp_diff / frequency_khz);
295 base::TimeDelta time_diff_delta = now - time_first_incoming_packet_;
296
297 playout_time = now + std::max(rtp_time_diff_delta - time_diff_delta,
298 base::TimeDelta());
299 }
300 }
301 if (playout_time.is_null()) {
302 // This can fail if we have not received any RTCP packets in a long time.
303 if (rtcp_.RtpTimestampInSenderTime(frequency_, rtp_timestamp,
304 &rtp_timestamp_in_ticks)) {
305 playout_time =
306 rtp_timestamp_in_ticks + time_offset_ + target_delay_delta_;
307 } else {
308 playout_time = now;
309 }
310 }
311
312 // TODO(miu): This is broken since we literally switch timelines once |rtcp_|
313 // can provide us the |time_offset_|. Furthermore, this "getter" method may
314 // be called on frames received out-of-order, which means the playout times
315 // for earlier frames will be computed incorrectly.
316 #if 0
317 // Don't allow the playout time to go backwards.
318 if (last_playout_time_ > playout_time) playout_time = last_playout_time_;
319 last_playout_time_ = playout_time;
320 #endif
321
322 return playout_time;
323 }
324
325 void AudioReceiver::ScheduleNextRtcpReport() { 289 void AudioReceiver::ScheduleNextRtcpReport() {
326 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 290 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
327 base::TimeDelta time_to_send = rtcp_.TimeToSendNextRtcpReport() - 291 base::TimeDelta time_to_send = rtcp_.TimeToSendNextRtcpReport() -
328 cast_environment_->Clock()->NowTicks(); 292 cast_environment_->Clock()->NowTicks();
329 293
330 time_to_send = std::max( 294 time_to_send = std::max(
331 time_to_send, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); 295 time_to_send, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
332 296
333 cast_environment_->PostDelayedTask( 297 cast_environment_->PostDelayedTask(
334 CastEnvironment::MAIN, 298 CastEnvironment::MAIN,
(...skipping 29 matching lines...) Expand all
364 } 328 }
365 329
366 void AudioReceiver::SendNextCastMessage() { 330 void AudioReceiver::SendNextCastMessage() {
367 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 331 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
368 framer_.SendCastMessage(); // Will only send a message if it is time. 332 framer_.SendCastMessage(); // Will only send a message if it is time.
369 ScheduleNextCastMessage(); 333 ScheduleNextCastMessage();
370 } 334 }
371 335
372 } // namespace cast 336 } // namespace cast
373 } // namespace media 337 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698