Chromium Code Reviews| 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_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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 168 // TODO(miu): We should only be peeking at the metadata, and not copying the | 157 // TODO(miu): We should only be peeking at the metadata, and not copying the |
| 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 } |
| 167 if (!is_consecutively_next_frame && | |
|
hubbe
2014/05/14 23:12:23
Hmm, I think the framer should not return non-deco
miu
2014/05/16 22:45:47
Done.
| |
| 168 !transport::CanDropFramesForCodec(codec_)) { | |
| 169 VLOG(1) << "Wait for the next frame in sequence (codec requirement)."; | |
| 170 return; // OnReceivedPayloadData() will invoke this method in the future. | |
| 171 } | |
| 172 | |
| 173 const base::TimeTicks playout_time = | |
| 174 GetPlayoutTime(encoded_frame->rtp_timestamp); | |
| 178 | 175 |
| 179 // If |framer_| has a frame ready that is out of sequence, examine the | 176 // 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 | 177 // 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 | 178 // skipping one or more frames. Skip if the missing frame wouldn't complete |
| 182 // playing before the start of playback of the available frame. | 179 // 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) { | 180 if (!is_consecutively_next_frame) { |
| 181 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | |
| 187 // TODO(miu): Also account for expected decode time here? | 182 // TODO(miu): Also account for expected decode time here? |
| 188 const base::TimeTicks earliest_possible_end_time_of_missing_frame = | 183 const base::TimeTicks earliest_possible_end_time_of_missing_frame = |
| 189 now + base::TimeDelta::FromMilliseconds(kTypicalAudioFrameDurationMs); | 184 now + base::TimeDelta::FromMilliseconds(kTypicalAudioFrameDurationMs); |
| 190 if (earliest_possible_end_time_of_missing_frame < playout_time) { | 185 if (earliest_possible_end_time_of_missing_frame < playout_time) { |
| 191 VLOG(1) << "Wait for next consecutive frame instead of skipping."; | 186 VLOG(1) << "Wait for next consecutive frame instead of skipping."; |
| 192 if (!is_waiting_for_consecutive_frame_) { | 187 RetryEmitAfterWaiting(playout_time - now); |
|
miu
2014/05/13 23:19:03
Explanation for "unnecessary factoring" here: I ha
| |
| 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; | 188 return; |
| 202 } | 189 } |
| 203 } | 190 } |
| 204 | 191 |
| 205 // Decrypt the payload data in the frame, if crypto is being used. | 192 // Decrypt the payload data in the frame, if crypto is being used. |
| 206 if (decryptor_.initialized()) { | 193 if (decryptor_.initialized()) { |
| 207 std::string decrypted_audio_data; | 194 std::string decrypted_audio_data; |
| 208 if (!decryptor_.Decrypt(encoded_frame->frame_id, | 195 if (!decryptor_.Decrypt(encoded_frame->frame_id, |
| 209 encoded_frame->data, | 196 encoded_frame->data, |
| 210 &decrypted_audio_data)) { | 197 &decrypted_audio_data)) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 221 framer_.ReleaseFrame(encoded_frame->frame_id); | 208 framer_.ReleaseFrame(encoded_frame->frame_id); |
| 222 cast_environment_->PostTask(CastEnvironment::MAIN, | 209 cast_environment_->PostTask(CastEnvironment::MAIN, |
| 223 FROM_HERE, | 210 FROM_HERE, |
| 224 base::Bind(frame_request_queue_.front(), | 211 base::Bind(frame_request_queue_.front(), |
| 225 base::Passed(&encoded_frame), | 212 base::Passed(&encoded_frame), |
| 226 playout_time)); | 213 playout_time)); |
| 227 frame_request_queue_.pop_front(); | 214 frame_request_queue_.pop_front(); |
| 228 } | 215 } |
| 229 } | 216 } |
| 230 | 217 |
| 218 void AudioReceiver::RetryEmitAfterWaiting(base::TimeDelta wait_time) { | |
| 219 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
| 220 if (is_waiting_to_emit_frames_) | |
| 221 return; | |
| 222 is_waiting_to_emit_frames_ = true; | |
| 223 cast_environment_->PostDelayedTask( | |
| 224 CastEnvironment::MAIN, | |
| 225 FROM_HERE, | |
| 226 base::Bind(&AudioReceiver::EmitAvailableEncodedFramesAfterWaiting, | |
| 227 weak_factory_.GetWeakPtr()), | |
| 228 wait_time); | |
| 229 } | |
| 230 | |
| 231 void AudioReceiver::EmitAvailableEncodedFramesAfterWaiting() { | 231 void AudioReceiver::EmitAvailableEncodedFramesAfterWaiting() { |
| 232 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 232 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 233 DCHECK(is_waiting_for_consecutive_frame_); | 233 DCHECK(is_waiting_to_emit_frames_); |
| 234 is_waiting_for_consecutive_frame_ = false; | 234 is_waiting_to_emit_frames_ = false; |
| 235 EmitAvailableEncodedFrames(); | 235 EmitAvailableEncodedFrames(); |
| 236 } | 236 } |
| 237 | 237 |
| 238 base::TimeTicks AudioReceiver::GetPlayoutTime(uint32 rtp_timestamp) const { | |
| 239 base::TimeTicks capture_time = rtcp_.ToApproximateCaptureTime(rtp_timestamp, | |
| 240 frequency_); | |
| 241 | |
| 242 // HACK: The sender should have provided Sender Reports which allow this | |
| 243 // receiver to map RTP timestamps back to the time the frame was captured on | |
| 244 // the sender. It should have done this before sending the first frame, but | |
| 245 // the spec does not currently require this. Therefore, if the data is | |
| 246 // missing, this receiver is forced to take a guess. | |
| 247 // | |
| 248 // The guess is based on a number of assumptions which in many environments | |
| 249 // will be completely wrong: | |
| 250 // 1. The difference between the sender clock and receiver clock (relative | |
| 251 // to NTP epoch) is very close to zero. | |
| 252 // 2. The amount of time the sender took to encode/process the frame before | |
| 253 // transport is approximately 1/2 the amount of time between frames. | |
| 254 // 3. Perfect network conditions (i.e., negligible latency, no packet loss, | |
| 255 // frames are arriving in-order, etc.). | |
| 256 if (capture_time.is_null()) { | |
| 257 VLOG(1) << ("Guessing playout time because sender has not yet sent lip " | |
| 258 "sync info. Expect jank in the near future!"); | |
| 259 capture_time = cast_environment_->Clock()->NowTicks() - | |
| 260 (base::TimeDelta::FromMilliseconds(kTypicalAudioFrameDurationMs) / 2); | |
| 261 } | |
| 262 | |
| 263 return capture_time + target_playout_delay_; | |
| 264 } | |
| 265 | |
| 238 void AudioReceiver::IncomingPacket(scoped_ptr<Packet> packet) { | 266 void AudioReceiver::IncomingPacket(scoped_ptr<Packet> packet) { |
| 239 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 267 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 240 if (Rtcp::IsRtcpPacket(&packet->front(), packet->size())) { | 268 if (Rtcp::IsRtcpPacket(&packet->front(), packet->size())) { |
| 241 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); | 269 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); |
| 242 } else { | 270 } else { |
| 243 ReceivedPacket(&packet->front(), packet->size()); | 271 ReceivedPacket(&packet->front(), packet->size()); |
| 244 } | 272 } |
| 245 } | 273 if (!reports_are_scheduled_) { |
| 246 | 274 ScheduleNextRtcpReport(); |
| 247 void AudioReceiver::SetTargetDelay(base::TimeDelta target_delay) { | 275 ScheduleNextCastMessage(); |
| 248 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 276 reports_are_scheduled_ = true; |
| 249 target_delay_delta_ = target_delay; | 277 } |
| 250 rtcp_.SetTargetDelay(target_delay_delta_); | |
| 251 } | 278 } |
| 252 | 279 |
| 253 void AudioReceiver::CastFeedback(const RtcpCastMessage& cast_message) { | 280 void AudioReceiver::CastFeedback(const RtcpCastMessage& cast_message) { |
| 254 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 281 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 255 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 282 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
| 256 RtpTimestamp rtp_timestamp = | 283 RtpTimestamp rtp_timestamp = |
| 257 frame_id_to_rtp_timestamp_[cast_message.ack_frame_id_ & 0xff]; | 284 frame_id_to_rtp_timestamp_[cast_message.ack_frame_id_ & 0xff]; |
| 258 cast_environment_->Logging()->InsertFrameEvent( | 285 cast_environment_->Logging()->InsertFrameEvent( |
| 259 now, FRAME_ACK_SENT, AUDIO_EVENT, rtp_timestamp, | 286 now, FRAME_ACK_SENT, AUDIO_EVENT, rtp_timestamp, |
| 260 cast_message.ack_frame_id_); | 287 cast_message.ack_frame_id_); |
| 261 | 288 |
| 262 ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events; | 289 ReceiverRtcpEventSubscriber::RtcpEventMultiMap rtcp_events; |
| 263 event_subscriber_.GetRtcpEventsAndReset(&rtcp_events); | 290 event_subscriber_.GetRtcpEventsAndReset(&rtcp_events); |
| 264 rtcp_.SendRtcpFromRtpReceiver(&cast_message, &rtcp_events); | 291 rtcp_.SendRtcpFromRtpReceiver(&cast_message, &rtcp_events); |
| 265 } | 292 } |
| 266 | 293 |
| 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() { | 294 void AudioReceiver::ScheduleNextRtcpReport() { |
| 326 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 295 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 327 base::TimeDelta time_to_send = rtcp_.TimeToSendNextRtcpReport() - | 296 base::TimeDelta time_to_send = rtcp_.TimeToSendNextRtcpReport() - |
| 328 cast_environment_->Clock()->NowTicks(); | 297 cast_environment_->Clock()->NowTicks(); |
| 329 | 298 |
| 330 time_to_send = std::max( | 299 time_to_send = std::max( |
| 331 time_to_send, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | 300 time_to_send, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); |
| 332 | 301 |
| 333 cast_environment_->PostDelayedTask( | 302 cast_environment_->PostDelayedTask( |
| 334 CastEnvironment::MAIN, | 303 CastEnvironment::MAIN, |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 364 } | 333 } |
| 365 | 334 |
| 366 void AudioReceiver::SendNextCastMessage() { | 335 void AudioReceiver::SendNextCastMessage() { |
| 367 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 336 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 368 framer_.SendCastMessage(); // Will only send a message if it is time. | 337 framer_.SendCastMessage(); // Will only send a message if it is time. |
| 369 ScheduleNextCastMessage(); | 338 ScheduleNextCastMessage(); |
| 370 } | 339 } |
| 371 | 340 |
| 372 } // namespace cast | 341 } // namespace cast |
| 373 } // namespace media | 342 } // namespace media |
| OLD | NEW |