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 |