diff options
Diffstat (limited to 'media/cast/audio_receiver/audio_receiver.cc')
-rw-r--r-- | media/cast/audio_receiver/audio_receiver.cc | 113 |
1 files changed, 100 insertions, 13 deletions
diff --git a/media/cast/audio_receiver/audio_receiver.cc b/media/cast/audio_receiver/audio_receiver.cc index c3dc3937b9..01e0026eb0 100644 --- a/media/cast/audio_receiver/audio_receiver.cc +++ b/media/cast/audio_receiver/audio_receiver.cc @@ -7,6 +7,8 @@ #include "base/bind.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" +#include "crypto/encryptor.h" +#include "crypto/symmetric_key.h" #include "media/cast/audio_receiver/audio_decoder.h" #include "media/cast/framer/framer.h" #include "media/cast/rtcp/rtcp.h" @@ -19,7 +21,6 @@ static const int64 kMinSchedulingDelayMs = 1; namespace media { namespace cast { - // Local implementation of RtpData (defined in rtp_rtcp_defines.h). // Used to pass payload data into the audio receiver. class LocalRtpAudioData : public RtpData { @@ -80,7 +81,6 @@ AudioReceiver::AudioReceiver(scoped_refptr<CastEnvironment> cast_environment, PacedPacketSender* const packet_sender) : cast_environment_(cast_environment), codec_(audio_config.codec), - incoming_ssrc_(audio_config.incoming_ssrc), frequency_(audio_config.frequency), audio_buffer_(), audio_decoder_(), @@ -97,8 +97,20 @@ AudioReceiver::AudioReceiver(scoped_refptr<CastEnvironment> cast_environment, true, 0)); } else { - audio_decoder_ = new AudioDecoder(audio_config); + audio_decoder_.reset(new AudioDecoder(audio_config)); + } + if (audio_config.aes_iv_mask.size() == kAesKeySize && + audio_config.aes_key.size() == kAesKeySize) { + iv_mask_ = audio_config.aes_iv_mask; + crypto::SymmetricKey* key = crypto::SymmetricKey::Import( + crypto::SymmetricKey::AES, audio_config.aes_key); + decryptor_.reset(new crypto::Encryptor()); + decryptor_->Init(key, crypto::Encryptor::CTR, std::string()); + } else if (audio_config.aes_iv_mask.size() != 0 || + audio_config.aes_key.size() != 0) { + DCHECK(false) << "Invalid crypto configuration"; } + rtp_receiver_.reset(new RtpReceiver(cast_environment->Clock(), &audio_config, NULL, @@ -107,36 +119,61 @@ AudioReceiver::AudioReceiver(scoped_refptr<CastEnvironment> cast_environment, new LocalRtpReceiverStatistics(rtp_receiver_.get())); base::TimeDelta rtcp_interval_delta = base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval); - rtcp_.reset(new Rtcp(cast_environment->Clock(), + rtcp_.reset(new Rtcp(cast_environment, NULL, packet_sender, NULL, rtp_audio_receiver_statistics_.get(), audio_config.rtcp_mode, rtcp_interval_delta, - false, audio_config.feedback_ssrc, + audio_config.incoming_ssrc, audio_config.rtcp_c_name)); - rtcp_->SetRemoteSSRC(audio_config.incoming_ssrc); - ScheduleNextRtcpReport(); - ScheduleNextCastMessage(); } AudioReceiver::~AudioReceiver() {} +void AudioReceiver::InitializeTimers() { + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); + ScheduleNextRtcpReport(); + ScheduleNextCastMessage(); +} + void AudioReceiver::IncomingParsedRtpPacket(const uint8* payload_data, size_t payload_size, const RtpCastHeader& rtp_header) { + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); + cast_environment_->Logging()->InsertPacketEvent(kPacketReceived, + rtp_header.webrtc.header.timestamp, rtp_header.frame_id, + rtp_header.packet_id, rtp_header.max_packet_id, payload_size); + // TODO(pwestin): update this as video to refresh over time. + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); if (time_first_incoming_packet_.is_null()) { + InitializeTimers(); first_incoming_rtp_timestamp_ = rtp_header.webrtc.header.timestamp; time_first_incoming_packet_ = cast_environment_->Clock()->NowTicks(); } if (audio_decoder_) { DCHECK(!audio_buffer_) << "Invalid internal state"; - audio_decoder_->IncomingParsedRtpPacket(payload_data, payload_size, - rtp_header); + std::string plaintext(reinterpret_cast<const char*>(payload_data), + payload_size); + if (decryptor_) { + plaintext.clear(); + if (!decryptor_->SetCounter(GetAesNonce(rtp_header.frame_id, iv_mask_))) { + NOTREACHED() << "Failed to set counter"; + return; + } + if (!decryptor_->Decrypt(base::StringPiece(reinterpret_cast<const char*>( + payload_data), payload_size), &plaintext)) { + VLOG(0) << "Decryption error"; + return; + } + } + audio_decoder_->IncomingParsedRtpPacket( + reinterpret_cast<const uint8*>(plaintext.data()), plaintext.size(), + rtp_header); return; } DCHECK(audio_buffer_) << "Invalid internal state"; @@ -155,11 +192,13 @@ void AudioReceiver::IncomingParsedRtpPacket(const uint8* payload_data, void AudioReceiver::GetRawAudioFrame(int number_of_10ms_blocks, int desired_frequency, const AudioFrameDecodedCallback& callback) { + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); DCHECK(audio_decoder_) << "Invalid function call in this configuration"; + // TODO(pwestin): we can skip this function by posting direct to the decoder. cast_environment_->PostTask(CastEnvironment::AUDIO_DECODER, FROM_HERE, base::Bind(&AudioReceiver::DecodeAudioFrameThread, - weak_factory_.GetWeakPtr(), + base::Unretained(this), number_of_10ms_blocks, desired_frequency, callback)); @@ -178,12 +217,17 @@ void AudioReceiver::DecodeAudioFrameThread( desired_frequency, audio_frame.get(), &rtp_timestamp)) { + // TODO(pwestin): This looks wrong, we would loose the pending call to + // the application provided callback. return; } base::TimeTicks now = cast_environment_->Clock()->NowTicks(); base::TimeTicks playout_time; playout_time = GetPlayoutTime(now, rtp_timestamp); + cast_environment_->Logging()->InsertFrameEventWithDelay(kAudioPlayoutDelay, + rtp_timestamp, kFrameIdUnknown, playout_time - now); + // Frame is ready - Send back to the main thread. cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, base::Bind(callback, @@ -191,6 +235,7 @@ void AudioReceiver::DecodeAudioFrameThread( } void AudioReceiver::PlayoutTimeout() { + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); DCHECK(audio_buffer_) << "Invalid function call in this configuration"; if (queued_encoded_callbacks_.empty()) { // Already released by incoming packet. @@ -209,6 +254,12 @@ void AudioReceiver::PlayoutTimeout() { VLOG(1) << "Failed to retrieved a complete frame at this point in time"; return; } + + if (decryptor_ && !DecryptAudioFrame(&encoded_frame)) { + // Logging already done. + return; + } + if (PostEncodedAudioFrame(queued_encoded_callbacks_.front(), rtp_timestamp, next_frame, &encoded_frame)) { // Call succeed remove callback from list. @@ -218,6 +269,7 @@ void AudioReceiver::PlayoutTimeout() { void AudioReceiver::GetEncodedAudioFrame( const AudioFrameEncodedCallback& callback) { + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); DCHECK(audio_buffer_) << "Invalid function call in this configuration"; uint32 rtp_timestamp = 0; @@ -231,6 +283,11 @@ void AudioReceiver::GetEncodedAudioFrame( queued_encoded_callbacks_.push_back(callback); return; } + if (decryptor_ && !DecryptAudioFrame(&encoded_frame)) { + // Logging already done. + queued_encoded_callbacks_.push_back(callback); + return; + } if (!PostEncodedAudioFrame(callback, rtp_timestamp, next_frame, &encoded_frame)) { // We have an audio frame; however we are missing packets and we have time @@ -244,7 +301,9 @@ bool AudioReceiver::PostEncodedAudioFrame( uint32 rtp_timestamp, bool next_frame, scoped_ptr<EncodedAudioFrame>* encoded_frame) { + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); DCHECK(audio_buffer_) << "Invalid function call in this configuration"; + base::TimeTicks now = cast_environment_->Clock()->NowTicks(); base::TimeTicks playout_time = GetPlayoutTime(now, rtp_timestamp); base::TimeDelta time_until_playout = playout_time - now; @@ -270,6 +329,7 @@ bool AudioReceiver::PostEncodedAudioFrame( void AudioReceiver::IncomingPacket(const uint8* packet, size_t length, const base::Closure callback) { + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); bool rtcp_packet = Rtcp::IsRtcpPacket(packet, length); if (!rtcp_packet) { rtp_receiver_->ReceivedPacket(packet, length); @@ -280,11 +340,13 @@ void AudioReceiver::IncomingPacket(const uint8* packet, size_t length, } void AudioReceiver::CastFeedback(const RtcpCastMessage& cast_message) { - rtcp_->SendRtcpCast(cast_message); + // TODO(pwestin): add logging. + rtcp_->SendRtcpFromRtpReceiver(&cast_message, NULL); } base::TimeTicks AudioReceiver::GetPlayoutTime(base::TimeTicks now, uint32 rtp_timestamp) { + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); // Senders time in ms when this frame was recorded. // Note: the senders clock and our local clock might not be synced. base::TimeTicks rtp_timestamp_in_ticks; @@ -314,7 +376,28 @@ base::TimeTicks AudioReceiver::GetPlayoutTime(base::TimeTicks now, now; } +bool AudioReceiver::DecryptAudioFrame( + scoped_ptr<EncodedAudioFrame>* audio_frame) { + DCHECK(decryptor_) << "Invalid state"; + + if (!decryptor_->SetCounter(GetAesNonce((*audio_frame)->frame_id, + iv_mask_))) { + NOTREACHED() << "Failed to set counter"; + return false; + } + std::string decrypted_audio_data; + if (!decryptor_->Decrypt((*audio_frame)->data, &decrypted_audio_data)) { + VLOG(0) << "Decryption error"; + // Give up on this frame, release it from jitter buffer. + audio_buffer_->ReleaseFrame((*audio_frame)->frame_id); + return false; + } + (*audio_frame)->data.swap(decrypted_audio_data); + return true; +} + void AudioReceiver::ScheduleNextRtcpReport() { + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); base::TimeDelta time_to_send = rtcp_->TimeToSendNextRtcpReport() - cast_environment_->Clock()->NowTicks(); @@ -327,13 +410,16 @@ void AudioReceiver::ScheduleNextRtcpReport() { } void AudioReceiver::SendNextRtcpReport() { - rtcp_->SendRtcpReport(incoming_ssrc_); + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); + // TODO(pwestin): add logging. + rtcp_->SendRtcpFromRtpReceiver(NULL, NULL); ScheduleNextRtcpReport(); } // Cast messages should be sent within a maximum interval. Schedule a call // if not triggered elsewhere, e.g. by the cast message_builder. void AudioReceiver::ScheduleNextCastMessage() { + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); if (audio_buffer_) { base::TimeTicks send_time; audio_buffer_->TimeToSendNextCastMessage(&send_time); @@ -349,6 +435,7 @@ void AudioReceiver::ScheduleNextCastMessage() { } void AudioReceiver::SendNextCastMessage() { + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); DCHECK(audio_buffer_) << "Invalid function call in this configuration"; audio_buffer_->SendCastMessage(); // Will only send a message if it is time. ScheduleNextCastMessage(); |