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
3 // found in the LICENSE file.
4
5 #include "media/cast/audio_sender/audio_sender.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "crypto/encryptor.h"
11 #include "crypto/symmetric_key.h"
12 #include "media/cast/audio_sender/audio_encoder.h"
13 #include "media/cast/cast_environment.h"
14 #include "media/cast/net/rtp_sender/rtp_sender.h"
15 #include "media/cast/rtcp/rtcp.h"
16
17 namespace media {
18 namespace cast {
19
20 const int64 kMinSchedulingDelayMs = 1;
21
22 class LocalRtcpAudioSenderFeedback : public RtcpSenderFeedback {
23 public:
LocalRtcpAudioSenderFeedback(AudioSender * audio_sender)24 explicit LocalRtcpAudioSenderFeedback(AudioSender* audio_sender)
25 : audio_sender_(audio_sender) {
26 }
27
OnReceivedCastFeedback(const RtcpCastMessage & cast_feedback)28 virtual void OnReceivedCastFeedback(
29 const RtcpCastMessage& cast_feedback) OVERRIDE {
30 if (!cast_feedback.missing_frames_and_packets_.empty()) {
31 audio_sender_->ResendPackets(cast_feedback.missing_frames_and_packets_);
32 }
33 VLOG(1) << "Received audio ACK "
34 << static_cast<int>(cast_feedback.ack_frame_id_);
35 }
36
37 private:
38 AudioSender* audio_sender_;
39 };
40
41 class LocalRtpSenderStatistics : public RtpSenderStatistics {
42 public:
LocalRtpSenderStatistics(RtpSender * rtp_sender)43 explicit LocalRtpSenderStatistics(RtpSender* rtp_sender)
44 : rtp_sender_(rtp_sender) {
45 }
46
GetStatistics(const base::TimeTicks & now,RtcpSenderInfo * sender_info)47 virtual void GetStatistics(const base::TimeTicks& now,
48 RtcpSenderInfo* sender_info) OVERRIDE {
49 rtp_sender_->RtpStatistics(now, sender_info);
50 }
51
52 private:
53 RtpSender* rtp_sender_;
54 };
55
AudioSender(scoped_refptr<CastEnvironment> cast_environment,const AudioSenderConfig & audio_config,PacedPacketSender * const paced_packet_sender)56 AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment,
57 const AudioSenderConfig& audio_config,
58 PacedPacketSender* const paced_packet_sender)
59 : cast_environment_(cast_environment),
60 rtp_sender_(cast_environment, &audio_config, NULL,
61 paced_packet_sender),
62 rtcp_feedback_(new LocalRtcpAudioSenderFeedback(this)),
63 rtp_audio_sender_statistics_(
64 new LocalRtpSenderStatistics(&rtp_sender_)),
65 rtcp_(cast_environment,
66 rtcp_feedback_.get(),
67 paced_packet_sender,
68 rtp_audio_sender_statistics_.get(),
69 NULL,
70 audio_config.rtcp_mode,
71 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval),
72 audio_config.sender_ssrc,
73 audio_config.incoming_feedback_ssrc,
74 audio_config.rtcp_c_name),
75 initialized_(false),
76 weak_factory_(this) {
77 if (audio_config.aes_iv_mask.size() == kAesKeySize &&
78 audio_config.aes_key.size() == kAesKeySize) {
79 iv_mask_ = audio_config.aes_iv_mask;
80 crypto::SymmetricKey* key = crypto::SymmetricKey::Import(
81 crypto::SymmetricKey::AES, audio_config.aes_key);
82 encryptor_.reset(new crypto::Encryptor());
83 encryptor_->Init(key, crypto::Encryptor::CTR, std::string());
84 } else if (audio_config.aes_iv_mask.size() != 0 ||
85 audio_config.aes_key.size() != 0) {
86 DCHECK(false) << "Invalid crypto configuration";
87 }
88 if (!audio_config.use_external_encoder) {
89 audio_encoder_ = new AudioEncoder(
90 cast_environment, audio_config,
91 base::Bind(&AudioSender::SendEncodedAudioFrame,
92 weak_factory_.GetWeakPtr()));
93 }
94 }
95
~AudioSender()96 AudioSender::~AudioSender() {}
97
InitializeTimers()98 void AudioSender::InitializeTimers() {
99 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
100 if (!initialized_) {
101 initialized_ = true;
102 ScheduleNextRtcpReport();
103 }
104 }
105
InsertAudio(const AudioBus * audio_bus,const base::TimeTicks & recorded_time,const base::Closure & done_callback)106 void AudioSender::InsertAudio(const AudioBus* audio_bus,
107 const base::TimeTicks& recorded_time,
108 const base::Closure& done_callback) {
109 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
110 DCHECK(audio_encoder_.get()) << "Invalid internal state";
111 // TODO(mikhal): Resolve calculation of the audio rtp_timestamp for logging.
112 // This is a tmp solution to allow the code to build.
113 cast_environment_->Logging()->InsertFrameEvent(kAudioFrameReceived,
114 GetVideoRtpTimestamp(recorded_time), kFrameIdUnknown);
115 audio_encoder_->InsertAudio(audio_bus, recorded_time, done_callback);
116 }
117
InsertCodedAudioFrame(const EncodedAudioFrame * audio_frame,const base::TimeTicks & recorded_time,const base::Closure callback)118 void AudioSender::InsertCodedAudioFrame(const EncodedAudioFrame* audio_frame,
119 const base::TimeTicks& recorded_time,
120 const base::Closure callback) {
121 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
122 DCHECK(audio_encoder_.get() == NULL) << "Invalid internal state";
123
124 cast_environment_->Logging()->InsertFrameEvent(kAudioFrameReceived,
125 GetVideoRtpTimestamp(recorded_time), kFrameIdUnknown);
126
127 if (encryptor_) {
128 EncodedAudioFrame encrypted_frame;
129 if (!EncryptAudioFrame(*audio_frame, &encrypted_frame)) {
130 // Logging already done.
131 return;
132 }
133 rtp_sender_.IncomingEncodedAudioFrame(&encrypted_frame, recorded_time);
134 } else {
135 rtp_sender_.IncomingEncodedAudioFrame(audio_frame, recorded_time);
136 }
137 callback.Run();
138 }
139
SendEncodedAudioFrame(scoped_ptr<EncodedAudioFrame> audio_frame,const base::TimeTicks & recorded_time)140 void AudioSender::SendEncodedAudioFrame(
141 scoped_ptr<EncodedAudioFrame> audio_frame,
142 const base::TimeTicks& recorded_time) {
143 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
144 InitializeTimers();
145 if (encryptor_) {
146 EncodedAudioFrame encrypted_frame;
147 if (!EncryptAudioFrame(*audio_frame.get(), &encrypted_frame)) {
148 // Logging already done.
149 return;
150 }
151 rtp_sender_.IncomingEncodedAudioFrame(&encrypted_frame, recorded_time);
152 } else {
153 rtp_sender_.IncomingEncodedAudioFrame(audio_frame.get(), recorded_time);
154 }
155 }
156
EncryptAudioFrame(const EncodedAudioFrame & audio_frame,EncodedAudioFrame * encrypted_frame)157 bool AudioSender::EncryptAudioFrame(const EncodedAudioFrame& audio_frame,
158 EncodedAudioFrame* encrypted_frame) {
159 DCHECK(encryptor_) << "Invalid state";
160
161 if (!encryptor_->SetCounter(GetAesNonce(audio_frame.frame_id, iv_mask_))) {
162 NOTREACHED() << "Failed to set counter";
163 return false;
164 }
165 if (!encryptor_->Encrypt(audio_frame.data, &encrypted_frame->data)) {
166 NOTREACHED() << "Encrypt error";
167 return false;
168 }
169 encrypted_frame->codec = audio_frame.codec;
170 encrypted_frame->frame_id = audio_frame.frame_id;
171 encrypted_frame->samples = audio_frame.samples;
172 return true;
173 }
174
ResendPackets(const MissingFramesAndPacketsMap & missing_frames_and_packets)175 void AudioSender::ResendPackets(
176 const MissingFramesAndPacketsMap& missing_frames_and_packets) {
177 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
178 rtp_sender_.ResendPackets(missing_frames_and_packets);
179 }
180
IncomingRtcpPacket(const uint8 * packet,size_t length,const base::Closure callback)181 void AudioSender::IncomingRtcpPacket(const uint8* packet, size_t length,
182 const base::Closure callback) {
183 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
184 rtcp_.IncomingRtcpPacket(packet, length);
185 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, callback);
186 }
187
ScheduleNextRtcpReport()188 void AudioSender::ScheduleNextRtcpReport() {
189 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
190 base::TimeDelta time_to_next =
191 rtcp_.TimeToSendNextRtcpReport() - cast_environment_->Clock()->NowTicks();
192
193 time_to_next = std::max(time_to_next,
194 base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
195
196 cast_environment_->PostDelayedTask(CastEnvironment::MAIN, FROM_HERE,
197 base::Bind(&AudioSender::SendRtcpReport, weak_factory_.GetWeakPtr()),
198 time_to_next);
199 }
200
SendRtcpReport()201 void AudioSender::SendRtcpReport() {
202 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
203 // We don't send audio logging messages since all captured audio frames will
204 // be sent.
205 rtcp_.SendRtcpFromRtpSender(NULL);
206 ScheduleNextRtcpReport();
207 }
208
209 } // namespace cast
210 } // namespace media
211