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 "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() == kAesBlockSize * 2 && | |
| 104 audio_config.aes_key.size() == kAesBlockSize * 2) { | |
|
wtc
2013/11/07 01:00:36
Block size and key size are different quantities,
pwestin
2013/11/07 17:16:04
Done.
| |
| 105 iv_mask_ = ConvertFromBase16String(audio_config.aes_iv_mask); | |
| 106 crypto::SymmetricKey* key = crypto::SymmetricKey::Import( | |
| 107 crypto::SymmetricKey::AES, | |
| 108 ConvertFromBase16String(audio_config.aes_key)); | |
| 109 decryptor_.reset(new crypto::Encryptor()); | |
| 110 decryptor_->Init(key, crypto::Encryptor::CTR, std::string()); | |
| 111 } else if (audio_config.aes_iv_mask.size() != 0 || | |
| 112 audio_config.aes_iv_mask.size() != 0) { | |
|
wtc
2013/11/07 01:00:36
BUG: the second one should test audio_config.aes_k
pwestin
2013/11/07 17:16:04
Done.
| |
| 113 DCHECK(false) << "Invalid crypto configuration"; | |
| 114 } | |
| 115 | |
| 102 rtp_receiver_.reset(new RtpReceiver(cast_environment->Clock(), | 116 rtp_receiver_.reset(new RtpReceiver(cast_environment->Clock(), |
| 103 &audio_config, | 117 &audio_config, |
| 104 NULL, | 118 NULL, |
| 105 incoming_payload_callback_.get())); | 119 incoming_payload_callback_.get())); |
| 106 rtp_audio_receiver_statistics_.reset( | 120 rtp_audio_receiver_statistics_.reset( |
| 107 new LocalRtpReceiverStatistics(rtp_receiver_.get())); | 121 new LocalRtpReceiverStatistics(rtp_receiver_.get())); |
| 108 base::TimeDelta rtcp_interval_delta = | 122 base::TimeDelta rtcp_interval_delta = |
| 109 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval); | 123 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval); |
| 110 rtcp_.reset(new Rtcp(cast_environment->Clock(), | 124 rtcp_.reset(new Rtcp(cast_environment->Clock(), |
| 111 NULL, | 125 NULL, |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 128 size_t payload_size, | 142 size_t payload_size, |
| 129 const RtpCastHeader& rtp_header) { | 143 const RtpCastHeader& rtp_header) { |
| 130 // TODO(pwestin): update this as video to refresh over time. | 144 // TODO(pwestin): update this as video to refresh over time. |
| 131 if (time_first_incoming_packet_.is_null()) { | 145 if (time_first_incoming_packet_.is_null()) { |
| 132 first_incoming_rtp_timestamp_ = rtp_header.webrtc.header.timestamp; | 146 first_incoming_rtp_timestamp_ = rtp_header.webrtc.header.timestamp; |
| 133 time_first_incoming_packet_ = cast_environment_->Clock()->NowTicks(); | 147 time_first_incoming_packet_ = cast_environment_->Clock()->NowTicks(); |
| 134 } | 148 } |
| 135 | 149 |
| 136 if (audio_decoder_) { | 150 if (audio_decoder_) { |
| 137 DCHECK(!audio_buffer_) << "Invalid internal state"; | 151 DCHECK(!audio_buffer_) << "Invalid internal state"; |
| 138 audio_decoder_->IncomingParsedRtpPacket(payload_data, payload_size, | 152 if (decryptor_) { |
| 139 rtp_header); | 153 // TODO(pwestin): we need to change to 32 bits frame id. |
| 154 decryptor_->SetCounter(GetAesNounce(rtp_header.frame_id, iv_mask_)); | |
| 155 std::string plaintext; | |
| 156 if (decryptor_->Decrypt( | |
| 157 base::StringPiece(reinterpret_cast<const char*>(payload_data), | |
|
Alpha Left Google
2013/11/07 01:10:11
nit: indent 4 spaces.
pwestin
2013/11/07 17:16:04
Done.
| |
| 158 payload_size), | |
| 159 &plaintext)) { | |
|
Alpha Left Google
2013/11/07 01:10:11
nit: indent 4 spaces as well.
pwestin
2013/11/07 17:16:04
Done.
| |
| 160 audio_decoder_->IncomingParsedRtpPacket( | |
| 161 reinterpret_cast<const uint8*>(plaintext.data()), plaintext.size(), | |
| 162 rtp_header); | |
| 163 } else { | |
| 164 DCHECK(false) << "Decryption error"; | |
| 165 return; | |
| 166 } | |
| 167 } else { | |
| 168 audio_decoder_->IncomingParsedRtpPacket(payload_data, payload_size, | |
| 169 rtp_header); | |
| 170 } | |
| 140 return; | 171 return; |
| 141 } | 172 } |
| 142 DCHECK(audio_buffer_) << "Invalid internal state"; | 173 DCHECK(audio_buffer_) << "Invalid internal state"; |
| 143 DCHECK(!audio_decoder_) << "Invalid internal state"; | 174 DCHECK(!audio_decoder_) << "Invalid internal state"; |
| 144 bool complete = audio_buffer_->InsertPacket(payload_data, payload_size, | 175 bool complete = audio_buffer_->InsertPacket(payload_data, payload_size, |
| 145 rtp_header); | 176 rtp_header); |
| 146 if (!complete) return; // Audio frame not complete; wait for more packets. | 177 if (!complete) return; // Audio frame not complete; wait for more packets. |
| 147 if (queued_encoded_callbacks_.empty()) return; // No pending callback. | 178 if (queued_encoded_callbacks_.empty()) return; // No pending callback. |
| 148 | 179 |
| 149 AudioFrameEncodedCallback callback = queued_encoded_callbacks_.front(); | 180 AudioFrameEncodedCallback callback = queued_encoded_callbacks_.front(); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 202 | 233 |
| 203 if (!audio_buffer_->GetEncodedAudioFrame(encoded_frame.get(), | 234 if (!audio_buffer_->GetEncodedAudioFrame(encoded_frame.get(), |
| 204 &rtp_timestamp, &next_frame)) { | 235 &rtp_timestamp, &next_frame)) { |
| 205 // We have no audio frames. Wait for new packet(s). | 236 // We have no audio frames. Wait for new packet(s). |
| 206 // Since the application can post multiple AudioFrameEncodedCallback and | 237 // Since the application can post multiple AudioFrameEncodedCallback and |
| 207 // we only check the next frame to play out we might have multiple timeout | 238 // 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. | 239 // 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"; | 240 VLOG(1) << "Failed to retrieved a complete frame at this point in time"; |
| 210 return; | 241 return; |
| 211 } | 242 } |
| 243 | |
| 244 if (decryptor_) { | |
| 245 EncodedAudioFrame* decrypted_audio_frame = new EncodedAudioFrame(); | |
|
Alpha Left Google
2013/11/07 01:10:11
We should use a scoped_ptr<T> here.
pwestin
2013/11/07 17:16:04
Done.
| |
| 246 if (DecryptAudioFrame(encoded_frame.get(), decrypted_audio_frame)) { | |
| 247 encoded_frame.reset(decrypted_audio_frame); | |
| 248 } else { | |
| 249 DCHECK(false) << "Decryption error"; | |
| 250 delete decrypted_audio_frame; | |
| 251 return; | |
| 252 } | |
| 253 } | |
| 254 | |
| 212 if (PostEncodedAudioFrame(queued_encoded_callbacks_.front(), rtp_timestamp, | 255 if (PostEncodedAudioFrame(queued_encoded_callbacks_.front(), rtp_timestamp, |
| 213 next_frame, &encoded_frame)) { | 256 next_frame, &encoded_frame)) { |
| 214 // Call succeed remove callback from list. | 257 // Call succeed remove callback from list. |
| 215 queued_encoded_callbacks_.pop_front(); | 258 queued_encoded_callbacks_.pop_front(); |
| 216 } | 259 } |
| 217 } | 260 } |
| 218 | 261 |
| 219 void AudioReceiver::GetEncodedAudioFrame( | 262 void AudioReceiver::GetEncodedAudioFrame( |
| 220 const AudioFrameEncodedCallback& callback) { | 263 const AudioFrameEncodedCallback& callback) { |
| 221 DCHECK(audio_buffer_) << "Invalid function call in this configuration"; | 264 DCHECK(audio_buffer_) << "Invalid function call in this configuration"; |
| 222 | 265 |
| 223 uint32 rtp_timestamp = 0; | 266 uint32 rtp_timestamp = 0; |
| 224 bool next_frame = false; | 267 bool next_frame = false; |
| 225 scoped_ptr<EncodedAudioFrame> encoded_frame(new EncodedAudioFrame()); | 268 scoped_ptr<EncodedAudioFrame> encoded_frame(new EncodedAudioFrame()); |
| 226 | 269 |
| 227 if (!audio_buffer_->GetEncodedAudioFrame(encoded_frame.get(), | 270 if (!audio_buffer_->GetEncodedAudioFrame(encoded_frame.get(), |
| 228 &rtp_timestamp, &next_frame)) { | 271 &rtp_timestamp, &next_frame)) { |
| 229 // We have no audio frames. Wait for new packet(s). | 272 // We have no audio frames. Wait for new packet(s). |
| 230 VLOG(1) << "Wait for more audio packets in frame"; | 273 VLOG(1) << "Wait for more audio packets in frame"; |
| 231 queued_encoded_callbacks_.push_back(callback); | 274 queued_encoded_callbacks_.push_back(callback); |
| 232 return; | 275 return; |
| 233 } | 276 } |
| 277 if (decryptor_) { | |
| 278 EncodedAudioFrame* decrypted_audio_frame = new EncodedAudioFrame(); | |
|
Alpha Left Google
2013/11/07 01:10:11
Use scoped_ptr<T>.
pwestin
2013/11/07 17:16:04
Done.
| |
| 279 if (DecryptAudioFrame(encoded_frame.get(), decrypted_audio_frame)) { | |
| 280 encoded_frame.reset(decrypted_audio_frame); | |
| 281 } else { | |
| 282 DCHECK(false) << "Decryption error"; | |
| 283 delete decrypted_audio_frame; | |
| 284 return; | |
| 285 } | |
| 286 } | |
| 234 if (!PostEncodedAudioFrame(callback, rtp_timestamp, next_frame, | 287 if (!PostEncodedAudioFrame(callback, rtp_timestamp, next_frame, |
| 235 &encoded_frame)) { | 288 &encoded_frame)) { |
| 236 // We have an audio frame; however we are missing packets and we have time | 289 // We have an audio frame; however we are missing packets and we have time |
| 237 // to wait for new packet(s). | 290 // to wait for new packet(s). |
| 238 queued_encoded_callbacks_.push_back(callback); | 291 queued_encoded_callbacks_.push_back(callback); |
| 239 } | 292 } |
| 240 } | 293 } |
| 241 | 294 |
| 242 bool AudioReceiver::PostEncodedAudioFrame( | 295 bool AudioReceiver::PostEncodedAudioFrame( |
| 243 const AudioFrameEncodedCallback& callback, | 296 const AudioFrameEncodedCallback& callback, |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 307 base::TimeDelta()); | 360 base::TimeDelta()); |
| 308 } | 361 } |
| 309 } | 362 } |
| 310 // This can fail if we have not received any RTCP packets in a long time. | 363 // This can fail if we have not received any RTCP packets in a long time. |
| 311 return rtcp_->RtpTimestampInSenderTime(frequency_, rtp_timestamp, | 364 return rtcp_->RtpTimestampInSenderTime(frequency_, rtp_timestamp, |
| 312 &rtp_timestamp_in_ticks) ? | 365 &rtp_timestamp_in_ticks) ? |
| 313 rtp_timestamp_in_ticks + time_offset_ + target_delay_delta_ : | 366 rtp_timestamp_in_ticks + time_offset_ + target_delay_delta_ : |
| 314 now; | 367 now; |
| 315 } | 368 } |
| 316 | 369 |
| 370 bool AudioReceiver::DecryptAudioFrame(const EncodedAudioFrame* encrypted_frame, | |
| 371 EncodedAudioFrame* audio_frame) { | |
| 372 DCHECK(decryptor_) << "Invalid state"; | |
| 373 | |
| 374 DCHECK(false); | |
|
Alpha Left Google
2013/11/07 01:10:11
Why?
pwestin
2013/11/07 17:16:04
No idea how that ended up there
| |
| 375 | |
| 376 // TODO(pwestin): the frame id must be a 32 bit number. | |
| 377 decryptor_->SetCounter(GetAesNounce(audio_frame->frame_id, iv_mask_)); | |
| 378 | |
| 379 audio_frame->codec = encrypted_frame->codec; | |
| 380 audio_frame->frame_id = encrypted_frame->frame_id; | |
| 381 | |
| 382 return decryptor_->Decrypt(encrypted_frame->data, &audio_frame->data); | |
| 383 } | |
| 384 | |
| 317 void AudioReceiver::ScheduleNextRtcpReport() { | 385 void AudioReceiver::ScheduleNextRtcpReport() { |
| 318 base::TimeDelta time_to_send = rtcp_->TimeToSendNextRtcpReport() - | 386 base::TimeDelta time_to_send = rtcp_->TimeToSendNextRtcpReport() - |
| 319 cast_environment_->Clock()->NowTicks(); | 387 cast_environment_->Clock()->NowTicks(); |
| 320 | 388 |
| 321 time_to_send = std::max(time_to_send, | 389 time_to_send = std::max(time_to_send, |
| 322 base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | 390 base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); |
| 323 | 391 |
| 324 cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE, | 392 cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE, |
| 325 base::Bind(&AudioReceiver::SendNextRtcpReport, | 393 base::Bind(&AudioReceiver::SendNextRtcpReport, |
| 326 weak_factory_.GetWeakPtr()), time_to_send); | 394 weak_factory_.GetWeakPtr()), time_to_send); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 349 } | 417 } |
| 350 | 418 |
| 351 void AudioReceiver::SendNextCastMessage() { | 419 void AudioReceiver::SendNextCastMessage() { |
| 352 DCHECK(audio_buffer_) << "Invalid function call in this configuration"; | 420 DCHECK(audio_buffer_) << "Invalid function call in this configuration"; |
| 353 audio_buffer_->SendCastMessage(); // Will only send a message if it is time. | 421 audio_buffer_->SendCastMessage(); // Will only send a message if it is time. |
| 354 ScheduleNextCastMessage(); | 422 ScheduleNextCastMessage(); |
| 355 } | 423 } |
| 356 | 424 |
| 357 } // namespace cast | 425 } // namespace cast |
| 358 } // namespace media | 426 } // namespace media |
| OLD | NEW |