 Chromium Code Reviews
 Chromium Code Reviews Issue 225023010:
  [Cast] Refactor/clean-up VideoReceiver to match AudioReceiver as closely as possible.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 225023010:
  [Cast] Refactor/clean-up VideoReceiver to match AudioReceiver as closely as possible.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| 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> | |
| 8 | |
| 7 #include "base/bind.h" | 9 #include "base/bind.h" | 
| 8 #include "base/logging.h" | 10 #include "base/logging.h" | 
| 9 #include "base/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" | 
| 10 #include "media/cast/audio_receiver/audio_decoder.h" | 12 #include "media/cast/audio_receiver/audio_decoder.h" | 
| 11 #include "media/cast/transport/cast_transport_defines.h" | 13 #include "media/cast/transport/cast_transport_defines.h" | 
| 12 | 14 | 
| 13 namespace { | 15 namespace { | 
| 16 const int kMinSchedulingDelayMs = 1; | |
| 17 // TODO(miu): These should go in AudioReceiverConfig. | |
| 14 const int kTypicalAudioFrameDurationMs = 10; | 18 const int kTypicalAudioFrameDurationMs = 10; | 
| 15 const int kMinSchedulingDelayMs = 1; | 19 const int kTypicalFramesPerSecond = 1000 / kTypicalAudioFrameDurationMs; | 
| 16 } // namespace | 20 } // namespace | 
| 17 | 21 | 
| 18 namespace media { | 22 namespace media { | 
| 19 namespace cast { | 23 namespace cast { | 
| 20 | 24 | 
| 21 AudioReceiver::AudioReceiver(scoped_refptr<CastEnvironment> cast_environment, | 25 AudioReceiver::AudioReceiver(scoped_refptr<CastEnvironment> cast_environment, | 
| 22 const AudioReceiverConfig& audio_config, | 26 const AudioReceiverConfig& audio_config, | 
| 23 transport::PacedPacketSender* const packet_sender) | 27 transport::PacedPacketSender* const packet_sender) | 
| 24 : RtpReceiver(cast_environment->Clock(), &audio_config, NULL), | 28 : RtpReceiver(cast_environment->Clock(), &audio_config, NULL), | 
| 25 cast_environment_(cast_environment), | 29 cast_environment_(cast_environment), | 
| 26 event_subscriber_(kReceiverRtcpEventHistorySize, | 30 event_subscriber_(kReceiverRtcpEventHistorySize, | 
| 27 ReceiverRtcpEventSubscriber::kAudioEventSubscriber), | 31 ReceiverRtcpEventSubscriber::kAudioEventSubscriber), | 
| 28 codec_(audio_config.codec), | 32 codec_(audio_config.codec), | 
| 29 frequency_(audio_config.frequency), | 33 frequency_(audio_config.frequency), | 
| 34 target_delay_delta_( | |
| 35 base::TimeDelta::FromMilliseconds(audio_config.rtp_max_delay_ms)), | |
| 30 framer_(cast_environment->Clock(), | 36 framer_(cast_environment->Clock(), | 
| 31 this, | 37 this, | 
| 32 audio_config.incoming_ssrc, | 38 audio_config.incoming_ssrc, | 
| 33 true, | 39 true, | 
| 34 0), | 40 audio_config.rtp_max_delay_ms * kTypicalFramesPerSecond / 1000), | 
| 
hubbe
2014/04/07 18:40:17
Seems simpler to just divide by kTypicalAudioFrame
 
miu
2014/04/08 00:59:41
Oh, duh.  Yes, agreed.  Done.
 | |
| 35 rtcp_(cast_environment, | 41 rtcp_(cast_environment, | 
| 36 NULL, | 42 NULL, | 
| 37 NULL, | 43 NULL, | 
| 38 packet_sender, | 44 packet_sender, | 
| 39 GetStatistics(), | 45 GetStatistics(), | 
| 40 audio_config.rtcp_mode, | 46 audio_config.rtcp_mode, | 
| 41 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval), | 47 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval), | 
| 42 audio_config.feedback_ssrc, | 48 audio_config.feedback_ssrc, | 
| 43 audio_config.incoming_ssrc, | 49 audio_config.incoming_ssrc, | 
| 44 audio_config.rtcp_c_name), | 50 audio_config.rtcp_c_name), | 
| 45 is_waiting_for_consecutive_frame_(false), | 51 is_waiting_for_consecutive_frame_(false), | 
| 46 weak_factory_(this) { | 52 weak_factory_(this) { | 
| 47 target_delay_delta_ = | |
| 48 base::TimeDelta::FromMilliseconds(audio_config.rtp_max_delay_ms); | |
| 49 if (!audio_config.use_external_decoder) | 53 if (!audio_config.use_external_decoder) | 
| 50 audio_decoder_.reset(new AudioDecoder(cast_environment, audio_config)); | 54 audio_decoder_.reset(new AudioDecoder(cast_environment, audio_config)); | 
| 51 decryptor_.Initialize(audio_config.aes_key, audio_config.aes_iv_mask); | 55 decryptor_.Initialize(audio_config.aes_key, audio_config.aes_iv_mask); | 
| 52 rtcp_.SetTargetDelay(target_delay_delta_); | 56 rtcp_.SetTargetDelay(target_delay_delta_); | 
| 53 cast_environment_->Logging()->AddRawEventSubscriber(&event_subscriber_); | 57 cast_environment_->Logging()->AddRawEventSubscriber(&event_subscriber_); | 
| 54 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_)); | 
| 55 } | 59 } | 
| 56 | 60 | 
| 57 AudioReceiver::~AudioReceiver() { | 61 AudioReceiver::~AudioReceiver() { | 
| 58 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 62 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 
| (...skipping 15 matching lines...) Expand all Loading... | |
| 74 ScheduleNextRtcpReport(); | 78 ScheduleNextRtcpReport(); | 
| 75 ScheduleNextCastMessage(); | 79 ScheduleNextCastMessage(); | 
| 76 } | 80 } | 
| 77 | 81 | 
| 78 void AudioReceiver::OnReceivedPayloadData(const uint8* payload_data, | 82 void AudioReceiver::OnReceivedPayloadData(const uint8* payload_data, | 
| 79 size_t payload_size, | 83 size_t payload_size, | 
| 80 const RtpCastHeader& rtp_header) { | 84 const RtpCastHeader& rtp_header) { | 
| 81 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 85 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 
| 82 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 86 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 
| 83 | 87 | 
| 84 frame_id_to_rtp_timestamp_[rtp_header.frame_id & 0xff] = | |
| 85 rtp_header.webrtc.header.timestamp; | |
| 86 cast_environment_->Logging()->InsertPacketEvent( | |
| 87 now, kAudioPacketReceived, rtp_header.webrtc.header.timestamp, | |
| 88 rtp_header.frame_id, rtp_header.packet_id, rtp_header.max_packet_id, | |
| 89 payload_size); | |
| 90 | |
| 91 // TODO(pwestin): update this as video to refresh over time. | 88 // TODO(pwestin): update this as video to refresh over time. | 
| 92 if (time_first_incoming_packet_.is_null()) { | 89 if (time_first_incoming_packet_.is_null()) { | 
| 93 InitializeTimers(); | 90 InitializeTimers(); | 
| 94 first_incoming_rtp_timestamp_ = rtp_header.webrtc.header.timestamp; | 91 first_incoming_rtp_timestamp_ = rtp_header.webrtc.header.timestamp; | 
| 95 time_first_incoming_packet_ = now; | 92 time_first_incoming_packet_ = now; | 
| 96 } | 93 } | 
| 97 | 94 | 
| 95 frame_id_to_rtp_timestamp_[rtp_header.frame_id & 0xff] = | |
| 96 rtp_header.webrtc.header.timestamp; | |
| 97 cast_environment_->Logging()->InsertPacketEvent( | |
| 98 now, kAudioPacketReceived, rtp_header.webrtc.header.timestamp, | |
| 99 rtp_header.frame_id, rtp_header.packet_id, rtp_header.max_packet_id, | |
| 100 payload_size); | |
| 101 | |
| 98 bool duplicate = false; | 102 bool duplicate = false; | 
| 99 const bool complete = | 103 const bool complete = | 
| 100 framer_.InsertPacket(payload_data, payload_size, rtp_header, &duplicate); | 104 framer_.InsertPacket(payload_data, payload_size, rtp_header, &duplicate); | 
| 101 if (duplicate) { | 105 if (duplicate) { | 
| 102 cast_environment_->Logging()->InsertPacketEvent( | 106 cast_environment_->Logging()->InsertPacketEvent( | 
| 103 now, kDuplicateAudioPacketReceived, rtp_header.webrtc.header.timestamp, | 107 now, | 
| 104 rtp_header.frame_id, rtp_header.packet_id, rtp_header.max_packet_id, | 108 kDuplicateAudioPacketReceived, | 
| 109 rtp_header.webrtc.header.timestamp, | |
| 110 rtp_header.frame_id, | |
| 111 rtp_header.packet_id, | |
| 112 rtp_header.max_packet_id, | |
| 105 payload_size); | 113 payload_size); | 
| 106 // Duplicate packets are ignored. | 114 // Duplicate packets are ignored. | 
| 107 return; | 115 return; | 
| 108 } | 116 } | 
| 109 if (!complete) | 117 if (!complete) | 
| 110 return; | 118 return; | 
| 111 | 119 | 
| 112 EmitAvailableEncodedFrames(); | 120 EmitAvailableEncodedFrames(); | 
| 113 } | 121 } | 
| 114 | 122 | 
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 190 } | 198 } | 
| 191 | 199 | 
| 192 // If |framer_| has a frame ready that is out of sequence, examine the | 200 // If |framer_| has a frame ready that is out of sequence, examine the | 
| 193 // playout time to determine whether it's acceptable to continue, thereby | 201 // playout time to determine whether it's acceptable to continue, thereby | 
| 194 // skipping one or more frames. Skip if the missing frame wouldn't complete | 202 // skipping one or more frames. Skip if the missing frame wouldn't complete | 
| 195 // playing before the start of playback of the available frame. | 203 // playing before the start of playback of the available frame. | 
| 196 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 204 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 
| 197 const base::TimeTicks playout_time = | 205 const base::TimeTicks playout_time = | 
| 198 GetPlayoutTime(now, encoded_frame->rtp_timestamp); | 206 GetPlayoutTime(now, encoded_frame->rtp_timestamp); | 
| 199 if (!is_consecutively_next_frame) { | 207 if (!is_consecutively_next_frame) { | 
| 208 // TODO(miu): Also account for expected decode time here? | |
| 200 const base::TimeTicks earliest_possible_end_time_of_missing_frame = | 209 const base::TimeTicks earliest_possible_end_time_of_missing_frame = | 
| 201 now + base::TimeDelta::FromMilliseconds(kTypicalAudioFrameDurationMs); | 210 now + base::TimeDelta::FromMilliseconds(kTypicalAudioFrameDurationMs); | 
| 202 if (earliest_possible_end_time_of_missing_frame < playout_time) { | 211 if (earliest_possible_end_time_of_missing_frame < playout_time) { | 
| 203 VLOG(1) << "Wait for next consecutive frame instead of skipping."; | 212 VLOG(1) << "Wait for next consecutive frame instead of skipping."; | 
| 204 if (!is_waiting_for_consecutive_frame_) { | 213 if (!is_waiting_for_consecutive_frame_) { | 
| 205 is_waiting_for_consecutive_frame_ = true; | 214 is_waiting_for_consecutive_frame_ = true; | 
| 206 cast_environment_->PostDelayedTask( | 215 cast_environment_->PostDelayedTask( | 
| 207 CastEnvironment::MAIN, | 216 CastEnvironment::MAIN, | 
| 208 FROM_HERE, | 217 FROM_HERE, | 
| 209 base::Bind(&AudioReceiver::EmitAvailableEncodedFramesAfterWaiting, | 218 base::Bind(&AudioReceiver::EmitAvailableEncodedFramesAfterWaiting, | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 242 | 251 | 
| 243 void AudioReceiver::EmitAvailableEncodedFramesAfterWaiting() { | 252 void AudioReceiver::EmitAvailableEncodedFramesAfterWaiting() { | 
| 244 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 253 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 
| 245 DCHECK(is_waiting_for_consecutive_frame_); | 254 DCHECK(is_waiting_for_consecutive_frame_); | 
| 246 is_waiting_for_consecutive_frame_ = false; | 255 is_waiting_for_consecutive_frame_ = false; | 
| 247 EmitAvailableEncodedFrames(); | 256 EmitAvailableEncodedFrames(); | 
| 248 } | 257 } | 
| 249 | 258 | 
| 250 void AudioReceiver::IncomingPacket(scoped_ptr<Packet> packet) { | 259 void AudioReceiver::IncomingPacket(scoped_ptr<Packet> packet) { | 
| 251 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 260 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 
| 252 bool rtcp_packet = Rtcp::IsRtcpPacket(&packet->front(), packet->size()); | 261 if (Rtcp::IsRtcpPacket(&packet->front(), packet->size())) { | 
| 253 if (!rtcp_packet) { | 262 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); | 
| 263 } else { | |
| 254 ReceivedPacket(&packet->front(), packet->size()); | 264 ReceivedPacket(&packet->front(), packet->size()); | 
| 255 } else { | |
| 256 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); | |
| 257 } | 265 } | 
| 258 } | 266 } | 
| 259 | 267 | 
| 260 void AudioReceiver::SetTargetDelay(base::TimeDelta target_delay) { | 268 void AudioReceiver::SetTargetDelay(base::TimeDelta target_delay) { | 
| 261 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 269 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 
| 262 target_delay_delta_ = target_delay; | 270 target_delay_delta_ = target_delay; | 
| 263 rtcp_.SetTargetDelay(target_delay_delta_); | 271 rtcp_.SetTargetDelay(target_delay_delta_); | 
| 264 } | 272 } | 
| 265 | 273 | 
| 266 void AudioReceiver::CastFeedback(const RtcpCastMessage& cast_message) { | 274 void AudioReceiver::CastFeedback(const RtcpCastMessage& cast_message) { | 
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 334 | 342 | 
| 335 void AudioReceiver::ScheduleNextRtcpReport() { | 343 void AudioReceiver::ScheduleNextRtcpReport() { | 
| 336 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 344 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 
| 337 base::TimeDelta time_to_send = rtcp_.TimeToSendNextRtcpReport() - | 345 base::TimeDelta time_to_send = rtcp_.TimeToSendNextRtcpReport() - | 
| 338 cast_environment_->Clock()->NowTicks(); | 346 cast_environment_->Clock()->NowTicks(); | 
| 339 | 347 | 
| 340 time_to_send = std::max( | 348 time_to_send = std::max( | 
| 341 time_to_send, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | 349 time_to_send, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | 
| 342 | 350 | 
| 343 cast_environment_->PostDelayedTask( | 351 cast_environment_->PostDelayedTask( | 
| 344 CastEnvironment::MAIN, FROM_HERE, | 352 CastEnvironment::MAIN, | 
| 353 FROM_HERE, | |
| 345 base::Bind(&AudioReceiver::SendNextRtcpReport, | 354 base::Bind(&AudioReceiver::SendNextRtcpReport, | 
| 346 weak_factory_.GetWeakPtr()), | 355 weak_factory_.GetWeakPtr()), | 
| 347 time_to_send); | 356 time_to_send); | 
| 348 } | 357 } | 
| 349 | 358 | 
| 350 void AudioReceiver::SendNextRtcpReport() { | 359 void AudioReceiver::SendNextRtcpReport() { | 
| 351 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 360 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 
| 352 // TODO(pwestin): add logging. | 361 // TODO(pwestin): add logging. | 
| 353 rtcp_.SendRtcpFromRtpReceiver(NULL, NULL); | 362 rtcp_.SendRtcpFromRtpReceiver(NULL, NULL); | 
| 354 ScheduleNextRtcpReport(); | 363 ScheduleNextRtcpReport(); | 
| 355 } | 364 } | 
| 356 | 365 | 
| 357 // Cast messages should be sent within a maximum interval. Schedule a call | 366 // Cast messages should be sent within a maximum interval. Schedule a call | 
| 358 // if not triggered elsewhere, e.g. by the cast message_builder. | 367 // if not triggered elsewhere, e.g. by the cast message_builder. | 
| 359 void AudioReceiver::ScheduleNextCastMessage() { | 368 void AudioReceiver::ScheduleNextCastMessage() { | 
| 360 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 369 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 
| 361 base::TimeTicks send_time; | 370 base::TimeTicks send_time; | 
| 362 framer_.TimeToSendNextCastMessage(&send_time); | 371 framer_.TimeToSendNextCastMessage(&send_time); | 
| 363 base::TimeDelta time_to_send = | 372 base::TimeDelta time_to_send = | 
| 364 send_time - cast_environment_->Clock()->NowTicks(); | 373 send_time - cast_environment_->Clock()->NowTicks(); | 
| 365 time_to_send = std::max( | 374 time_to_send = std::max( | 
| 366 time_to_send, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | 375 time_to_send, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | 
| 367 cast_environment_->PostDelayedTask( | 376 cast_environment_->PostDelayedTask( | 
| 368 CastEnvironment::MAIN, FROM_HERE, | 377 CastEnvironment::MAIN, | 
| 378 FROM_HERE, | |
| 369 base::Bind(&AudioReceiver::SendNextCastMessage, | 379 base::Bind(&AudioReceiver::SendNextCastMessage, | 
| 370 weak_factory_.GetWeakPtr()), | 380 weak_factory_.GetWeakPtr()), | 
| 371 time_to_send); | 381 time_to_send); | 
| 372 } | 382 } | 
| 373 | 383 | 
| 374 void AudioReceiver::SendNextCastMessage() { | 384 void AudioReceiver::SendNextCastMessage() { | 
| 375 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 385 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 
| 376 // Will only send a message if it is time. | 386 framer_.SendCastMessage(); // Will only send a message if it is time. | 
| 377 framer_.SendCastMessage(); | |
| 378 ScheduleNextCastMessage(); | 387 ScheduleNextCastMessage(); | 
| 379 } | 388 } | 
| 380 | 389 | 
| 381 } // namespace cast | 390 } // namespace cast | 
| 382 } // namespace media | 391 } // namespace media | 
| OLD | NEW |