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 "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "crypto/symmetric_key.h" | |
10 #include "media/cast/audio_receiver/audio_decoder.h" | 11 #include "media/cast/audio_receiver/audio_decoder.h" |
11 #include "media/cast/framer/framer.h" | 12 #include "media/cast/framer/framer.h" |
12 #include "media/cast/rtcp/rtcp.h" | 13 #include "media/cast/rtcp/rtcp.h" |
13 #include "media/cast/rtp_receiver/rtp_receiver.h" | 14 #include "media/cast/rtp_receiver/rtp_receiver.h" |
14 | 15 |
15 // Max time we wait until an audio frame is due to be played out is released. | 16 // Max time we wait until an audio frame is due to be played out is released. |
16 static const int64 kMaxAudioFrameWaitMs = 20; | 17 static const int64 kMaxAudioFrameWaitMs = 20; |
17 static const int64 kMinSchedulingDelayMs = 1; | 18 static const int64 kMinSchedulingDelayMs = 1; |
18 | 19 |
19 namespace media { | 20 namespace media { |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
92 incoming_payload_feedback_.reset(new LocalRtpAudioFeedback(this)); | 93 incoming_payload_feedback_.reset(new LocalRtpAudioFeedback(this)); |
93 if (audio_config.use_external_decoder) { | 94 if (audio_config.use_external_decoder) { |
94 audio_buffer_.reset(new Framer(cast_environment->Clock(), | 95 audio_buffer_.reset(new Framer(cast_environment->Clock(), |
95 incoming_payload_feedback_.get(), | 96 incoming_payload_feedback_.get(), |
96 audio_config.incoming_ssrc, | 97 audio_config.incoming_ssrc, |
97 true, | 98 true, |
98 0)); | 99 0)); |
99 } else { | 100 } else { |
100 audio_decoder_ = new AudioDecoder(audio_config); | 101 audio_decoder_ = new AudioDecoder(audio_config); |
101 } | 102 } |
103 if (audio_config.aes_iv_mask.size() == kAesKeySize && | |
104 audio_config.aes_key.size() == kAesKeySize) { | |
105 iv_mask_ = audio_config.aes_iv_mask; | |
106 crypto::SymmetricKey* key = crypto::SymmetricKey::Import( | |
107 crypto::SymmetricKey::AES, audio_config.aes_key); | |
108 decryptor_.reset(new crypto::Encryptor()); | |
109 decryptor_->Init(key, crypto::Encryptor::CTR, std::string()); | |
110 } else if (audio_config.aes_iv_mask.size() != 0 || | |
111 audio_config.aes_key.size() != 0) { | |
112 DCHECK(false) << "Invalid crypto configuration"; | |
113 } | |
114 | |
102 rtp_receiver_.reset(new RtpReceiver(cast_environment->Clock(), | 115 rtp_receiver_.reset(new RtpReceiver(cast_environment->Clock(), |
103 &audio_config, | 116 &audio_config, |
104 NULL, | 117 NULL, |
105 incoming_payload_callback_.get())); | 118 incoming_payload_callback_.get())); |
106 rtp_audio_receiver_statistics_.reset( | 119 rtp_audio_receiver_statistics_.reset( |
107 new LocalRtpReceiverStatistics(rtp_receiver_.get())); | 120 new LocalRtpReceiverStatistics(rtp_receiver_.get())); |
108 base::TimeDelta rtcp_interval_delta = | 121 base::TimeDelta rtcp_interval_delta = |
109 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval); | 122 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval); |
110 rtcp_.reset(new Rtcp(cast_environment->Clock(), | 123 rtcp_.reset(new Rtcp(cast_environment->Clock(), |
111 NULL, | 124 NULL, |
(...skipping 16 matching lines...) Expand all Loading... | |
128 size_t payload_size, | 141 size_t payload_size, |
129 const RtpCastHeader& rtp_header) { | 142 const RtpCastHeader& rtp_header) { |
130 // TODO(pwestin): update this as video to refresh over time. | 143 // TODO(pwestin): update this as video to refresh over time. |
131 if (time_first_incoming_packet_.is_null()) { | 144 if (time_first_incoming_packet_.is_null()) { |
132 first_incoming_rtp_timestamp_ = rtp_header.webrtc.header.timestamp; | 145 first_incoming_rtp_timestamp_ = rtp_header.webrtc.header.timestamp; |
133 time_first_incoming_packet_ = cast_environment_->Clock()->NowTicks(); | 146 time_first_incoming_packet_ = cast_environment_->Clock()->NowTicks(); |
134 } | 147 } |
135 | 148 |
136 if (audio_decoder_) { | 149 if (audio_decoder_) { |
137 DCHECK(!audio_buffer_) << "Invalid internal state"; | 150 DCHECK(!audio_buffer_) << "Invalid internal state"; |
138 audio_decoder_->IncomingParsedRtpPacket(payload_data, payload_size, | 151 if (decryptor_) { |
139 rtp_header); | 152 // TODO(pwestin): we need to change to 32 bits frame id. |
153 decryptor_->SetCounter(GetAesNounce(rtp_header.frame_id, iv_mask_)); | |
wtc
2013/11/13 20:57:17
GetAesNounce seems to be a typo. Should it be GetA
pwestin
2013/11/15 19:38:17
Done.
| |
154 std::string plaintext; | |
155 if (!decryptor_->Decrypt(base::StringPiece(reinterpret_cast<const char*>( | |
156 payload_data), payload_size), &plaintext)) { | |
157 DCHECK(false) << "Decryption error"; | |
wtc
2013/11/13 20:57:17
This should be a LOG statement rather than a DCHEC
pwestin
2013/11/15 19:38:17
Done.
| |
158 return; | |
159 } | |
160 audio_decoder_->IncomingParsedRtpPacket( | |
161 reinterpret_cast<const uint8*>(plaintext.data()), plaintext.size(), | |
162 rtp_header); | |
163 } else { | |
164 audio_decoder_->IncomingParsedRtpPacket(payload_data, payload_size, | |
165 rtp_header); | |
wtc
2013/11/13 20:57:17
Nit: ideally, this code should look like:
if (a
pwestin
2013/11/15 19:38:17
Done.
| |
166 } | |
140 return; | 167 return; |
141 } | 168 } |
142 DCHECK(audio_buffer_) << "Invalid internal state"; | 169 DCHECK(audio_buffer_) << "Invalid internal state"; |
143 DCHECK(!audio_decoder_) << "Invalid internal state"; | 170 DCHECK(!audio_decoder_) << "Invalid internal state"; |
144 bool complete = audio_buffer_->InsertPacket(payload_data, payload_size, | 171 bool complete = audio_buffer_->InsertPacket(payload_data, payload_size, |
145 rtp_header); | 172 rtp_header); |
146 if (!complete) return; // Audio frame not complete; wait for more packets. | 173 if (!complete) return; // Audio frame not complete; wait for more packets. |
147 if (queued_encoded_callbacks_.empty()) return; // No pending callback. | 174 if (queued_encoded_callbacks_.empty()) return; // No pending callback. |
148 | 175 |
149 AudioFrameEncodedCallback callback = queued_encoded_callbacks_.front(); | 176 AudioFrameEncodedCallback callback = queued_encoded_callbacks_.front(); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
202 | 229 |
203 if (!audio_buffer_->GetEncodedAudioFrame(encoded_frame.get(), | 230 if (!audio_buffer_->GetEncodedAudioFrame(encoded_frame.get(), |
204 &rtp_timestamp, &next_frame)) { | 231 &rtp_timestamp, &next_frame)) { |
205 // We have no audio frames. Wait for new packet(s). | 232 // We have no audio frames. Wait for new packet(s). |
206 // Since the application can post multiple AudioFrameEncodedCallback and | 233 // Since the application can post multiple AudioFrameEncodedCallback and |
207 // we only check the next frame to play out we might have multiple timeout | 234 // we only check the next frame to play out we might have multiple timeout |
208 // events firing after each other; however this should be a rare event. | 235 // events firing after each other; however this should be a rare event. |
209 VLOG(1) << "Failed to retrieved a complete frame at this point in time"; | 236 VLOG(1) << "Failed to retrieved a complete frame at this point in time"; |
210 return; | 237 return; |
211 } | 238 } |
239 | |
240 if (decryptor_) { | |
241 if (!DecryptAudioFrame(&encoded_frame)) { | |
242 DCHECK(false) << "Decryption error"; | |
wtc
2013/11/13 20:57:17
This should be a LOG statement rather than a DCHEC
pwestin
2013/11/15 19:38:17
Done.
| |
243 return; | |
244 } | |
245 } | |
246 | |
212 if (PostEncodedAudioFrame(queued_encoded_callbacks_.front(), rtp_timestamp, | 247 if (PostEncodedAudioFrame(queued_encoded_callbacks_.front(), rtp_timestamp, |
213 next_frame, &encoded_frame)) { | 248 next_frame, &encoded_frame)) { |
214 // Call succeed remove callback from list. | 249 // Call succeed remove callback from list. |
215 queued_encoded_callbacks_.pop_front(); | 250 queued_encoded_callbacks_.pop_front(); |
216 } | 251 } |
217 } | 252 } |
218 | 253 |
219 void AudioReceiver::GetEncodedAudioFrame( | 254 void AudioReceiver::GetEncodedAudioFrame( |
220 const AudioFrameEncodedCallback& callback) { | 255 const AudioFrameEncodedCallback& callback) { |
221 DCHECK(audio_buffer_) << "Invalid function call in this configuration"; | 256 DCHECK(audio_buffer_) << "Invalid function call in this configuration"; |
222 | 257 |
223 uint32 rtp_timestamp = 0; | 258 uint32 rtp_timestamp = 0; |
224 bool next_frame = false; | 259 bool next_frame = false; |
225 scoped_ptr<EncodedAudioFrame> encoded_frame(new EncodedAudioFrame()); | 260 scoped_ptr<EncodedAudioFrame> encoded_frame(new EncodedAudioFrame()); |
226 | 261 |
227 if (!audio_buffer_->GetEncodedAudioFrame(encoded_frame.get(), | 262 if (!audio_buffer_->GetEncodedAudioFrame(encoded_frame.get(), |
228 &rtp_timestamp, &next_frame)) { | 263 &rtp_timestamp, &next_frame)) { |
229 // We have no audio frames. Wait for new packet(s). | 264 // We have no audio frames. Wait for new packet(s). |
230 VLOG(1) << "Wait for more audio packets in frame"; | 265 VLOG(1) << "Wait for more audio packets in frame"; |
231 queued_encoded_callbacks_.push_back(callback); | 266 queued_encoded_callbacks_.push_back(callback); |
232 return; | 267 return; |
233 } | 268 } |
269 if (decryptor_) { | |
270 if (!DecryptAudioFrame(&encoded_frame)) { | |
271 DCHECK(false) << "Decryption error"; | |
272 return; | |
wtc
2013/11/13 20:57:17
Do we need to do
queued_encoded_callbacks_.pus
pwestin
2013/11/15 19:38:17
Done.
| |
273 } | |
274 } | |
234 if (!PostEncodedAudioFrame(callback, rtp_timestamp, next_frame, | 275 if (!PostEncodedAudioFrame(callback, rtp_timestamp, next_frame, |
235 &encoded_frame)) { | 276 &encoded_frame)) { |
236 // We have an audio frame; however we are missing packets and we have time | 277 // We have an audio frame; however we are missing packets and we have time |
237 // to wait for new packet(s). | 278 // to wait for new packet(s). |
238 queued_encoded_callbacks_.push_back(callback); | 279 queued_encoded_callbacks_.push_back(callback); |
239 } | 280 } |
240 } | 281 } |
241 | 282 |
242 bool AudioReceiver::PostEncodedAudioFrame( | 283 bool AudioReceiver::PostEncodedAudioFrame( |
243 const AudioFrameEncodedCallback& callback, | 284 const AudioFrameEncodedCallback& callback, |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
307 base::TimeDelta()); | 348 base::TimeDelta()); |
308 } | 349 } |
309 } | 350 } |
310 // This can fail if we have not received any RTCP packets in a long time. | 351 // This can fail if we have not received any RTCP packets in a long time. |
311 return rtcp_->RtpTimestampInSenderTime(frequency_, rtp_timestamp, | 352 return rtcp_->RtpTimestampInSenderTime(frequency_, rtp_timestamp, |
312 &rtp_timestamp_in_ticks) ? | 353 &rtp_timestamp_in_ticks) ? |
313 rtp_timestamp_in_ticks + time_offset_ + target_delay_delta_ : | 354 rtp_timestamp_in_ticks + time_offset_ + target_delay_delta_ : |
314 now; | 355 now; |
315 } | 356 } |
316 | 357 |
358 bool AudioReceiver::DecryptAudioFrame( | |
359 scoped_ptr<EncodedAudioFrame>* audio_frame) { | |
360 DCHECK(decryptor_) << "Invalid state"; | |
361 | |
362 scoped_ptr<EncodedAudioFrame> decrypted_audio_frame( | |
363 new EncodedAudioFrame()); | |
wtc
2013/11/13 20:57:17
I think we just need a std::string for the decrypt
pwestin
2013/11/15 19:38:17
Done.
| |
364 | |
365 // TODO(pwestin): the frame id must be a 32 bit number. | |
366 decryptor_->SetCounter(GetAesNounce((*audio_frame)->frame_id, iv_mask_)); | |
367 | |
368 if (!decryptor_->Decrypt((*audio_frame)->data, | |
369 &decrypted_audio_frame->data)) { | |
370 return false; | |
371 } | |
372 decrypted_audio_frame->codec = (*audio_frame)->codec; | |
373 decrypted_audio_frame->frame_id = (*audio_frame)->frame_id; | |
wtc
2013/11/13 20:57:17
Do we need to copy the "samples" field?
pwestin
2013/11/15 19:38:17
Done.
| |
374 | |
375 audio_frame->swap(decrypted_audio_frame); | |
376 return true; | |
377 } | |
378 | |
317 void AudioReceiver::ScheduleNextRtcpReport() { | 379 void AudioReceiver::ScheduleNextRtcpReport() { |
318 base::TimeDelta time_to_send = rtcp_->TimeToSendNextRtcpReport() - | 380 base::TimeDelta time_to_send = rtcp_->TimeToSendNextRtcpReport() - |
319 cast_environment_->Clock()->NowTicks(); | 381 cast_environment_->Clock()->NowTicks(); |
320 | 382 |
321 time_to_send = std::max(time_to_send, | 383 time_to_send = std::max(time_to_send, |
322 base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | 384 base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); |
323 | 385 |
324 cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE, | 386 cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE, |
325 base::Bind(&AudioReceiver::SendNextRtcpReport, | 387 base::Bind(&AudioReceiver::SendNextRtcpReport, |
326 weak_factory_.GetWeakPtr()), time_to_send); | 388 weak_factory_.GetWeakPtr()), time_to_send); |
(...skipping 22 matching lines...) Expand all Loading... | |
349 } | 411 } |
350 | 412 |
351 void AudioReceiver::SendNextCastMessage() { | 413 void AudioReceiver::SendNextCastMessage() { |
352 DCHECK(audio_buffer_) << "Invalid function call in this configuration"; | 414 DCHECK(audio_buffer_) << "Invalid function call in this configuration"; |
353 audio_buffer_->SendCastMessage(); // Will only send a message if it is time. | 415 audio_buffer_->SendCastMessage(); // Will only send a message if it is time. |
354 ScheduleNextCastMessage(); | 416 ScheduleNextCastMessage(); |
355 } | 417 } |
356 | 418 |
357 } // namespace cast | 419 } // namespace cast |
358 } // namespace media | 420 } // namespace media |
OLD | NEW |