• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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