• 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_encoder.h"
6 
7 #include <algorithm>
8 
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/sys_byteorder.h"
14 #include "base/time/time.h"
15 #include "media/base/audio_bus.h"
16 #include "media/cast/cast_defines.h"
17 #include "media/cast/cast_environment.h"
18 #include "third_party/opus/src/include/opus.h"
19 
20 namespace media {
21 namespace cast {
22 
LogAudioEncodedEvent(CastEnvironment * const cast_environment,const base::TimeTicks & recorded_time)23 void LogAudioEncodedEvent(CastEnvironment* const cast_environment,
24                           const base::TimeTicks& recorded_time) {
25   // TODO(mikhal): Resolve timestamp calculation for audio.
26   cast_environment->Logging()->InsertFrameEvent(kAudioFrameEncoded,
27       GetVideoRtpTimestamp(recorded_time), kFrameIdUnknown);
28 }
29 
30 // Base class that handles the common problem of feeding one or more AudioBus'
31 // data into a 10 ms buffer and then, once the buffer is full, encoding the
32 // signal and emitting an EncodedAudioFrame via the FrameEncodedCallback.
33 //
34 // Subclasses complete the implementation by handling the actual encoding
35 // details.
36 class AudioEncoder::ImplBase {
37  public:
ImplBase(CastEnvironment * cast_environment,AudioCodec codec,int num_channels,int sampling_rate,const FrameEncodedCallback & callback)38   ImplBase(CastEnvironment* cast_environment,
39            AudioCodec codec, int num_channels, int sampling_rate,
40            const FrameEncodedCallback& callback)
41       : cast_environment_(cast_environment),
42         codec_(codec), num_channels_(num_channels),
43         samples_per_10ms_(sampling_rate / 100),
44         callback_(callback),
45         buffer_fill_end_(0),
46         frame_id_(0) {
47     CHECK_GT(num_channels_, 0);
48     CHECK_GT(samples_per_10ms_, 0);
49     CHECK_EQ(sampling_rate % 100, 0);
50     CHECK_LE(samples_per_10ms_ * num_channels_,
51              EncodedAudioFrame::kMaxNumberOfSamples);
52   }
53 
~ImplBase()54   virtual ~ImplBase() {}
55 
EncodeAudio(const AudioBus * audio_bus,const base::TimeTicks & recorded_time,const base::Closure & done_callback)56   void EncodeAudio(const AudioBus* audio_bus,
57                    const base::TimeTicks& recorded_time,
58                    const base::Closure& done_callback) {
59     int src_pos = 0;
60     while (src_pos < audio_bus->frames()) {
61       const int num_samples_to_xfer =
62           std::min(samples_per_10ms_ - buffer_fill_end_,
63                    audio_bus->frames() - src_pos);
64       DCHECK_EQ(audio_bus->channels(), num_channels_);
65       TransferSamplesIntoBuffer(
66           audio_bus, src_pos, buffer_fill_end_, num_samples_to_xfer);
67       src_pos += num_samples_to_xfer;
68       buffer_fill_end_ += num_samples_to_xfer;
69 
70       if (src_pos == audio_bus->frames()) {
71         cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
72                                     done_callback);
73         // Note: |audio_bus| is now invalid..
74       }
75 
76       if (buffer_fill_end_ == samples_per_10ms_) {
77         scoped_ptr<EncodedAudioFrame> audio_frame(new EncodedAudioFrame());
78         audio_frame->codec = codec_;
79         audio_frame->frame_id = frame_id_++;
80         audio_frame->samples = samples_per_10ms_;
81         if (EncodeFromFilledBuffer(&audio_frame->data)) {
82           // Compute an offset to determine the recorded time for the first
83           // audio sample in the buffer.
84           const base::TimeDelta buffer_time_offset =
85               (buffer_fill_end_ - src_pos) *
86               base::TimeDelta::FromMilliseconds(10) / samples_per_10ms_;
87           // TODO(miu): Consider batching EncodedAudioFrames so we only post a
88           // at most one task for each call to this method.
89           cast_environment_->PostTask(
90               CastEnvironment::MAIN, FROM_HERE,
91               base::Bind(callback_, base::Passed(&audio_frame),
92                          recorded_time - buffer_time_offset));
93         }
94         buffer_fill_end_ = 0;
95       }
96     }
97   }
98 
99  protected:
100   virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus,
101                                          int source_offset,
102                                          int buffer_fill_offset,
103                                          int num_samples) = 0;
104   virtual bool EncodeFromFilledBuffer(std::string* out) = 0;
105 
106   CastEnvironment* const cast_environment_;
107   const AudioCodec codec_;
108   const int num_channels_;
109   const int samples_per_10ms_;
110   const FrameEncodedCallback callback_;
111 
112  private:
113   // In the case where a call to EncodeAudio() cannot completely fill the
114   // buffer, this points to the position at which to populate data in a later
115   // call.
116   int buffer_fill_end_;
117 
118   // A counter used to label EncodedAudioFrames.
119   uint32 frame_id_;
120 
121  private:
122   DISALLOW_COPY_AND_ASSIGN(ImplBase);
123 };
124 
125 class AudioEncoder::OpusImpl : public AudioEncoder::ImplBase {
126  public:
OpusImpl(CastEnvironment * cast_environment,int num_channels,int sampling_rate,int bitrate,const FrameEncodedCallback & callback)127   OpusImpl(CastEnvironment* cast_environment,
128            int num_channels, int sampling_rate, int bitrate,
129            const FrameEncodedCallback& callback)
130       : ImplBase(cast_environment, kOpus, num_channels, sampling_rate,
131                  callback),
132         encoder_memory_(new uint8[opus_encoder_get_size(num_channels)]),
133         opus_encoder_(reinterpret_cast<OpusEncoder*>(encoder_memory_.get())),
134         buffer_(new float[num_channels * samples_per_10ms_]) {
135     CHECK_EQ(opus_encoder_init(opus_encoder_, sampling_rate, num_channels,
136                                OPUS_APPLICATION_AUDIO),
137              OPUS_OK);
138     if (bitrate <= 0) {
139       // Note: As of 2013-10-31, the encoder in "auto bitrate" mode would use a
140       // variable bitrate up to 102kbps for 2-channel, 48 kHz audio and a 10 ms
141       // frame size.  The opus library authors may, of course, adjust this in
142       // later versions.
143       bitrate = OPUS_AUTO;
144     }
145     CHECK_EQ(opus_encoder_ctl(opus_encoder_, OPUS_SET_BITRATE(bitrate)),
146              OPUS_OK);
147   }
148 
~OpusImpl()149   virtual ~OpusImpl() {}
150 
151  private:
TransferSamplesIntoBuffer(const AudioBus * audio_bus,int source_offset,int buffer_fill_offset,int num_samples)152   virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus,
153                                          int source_offset,
154                                          int buffer_fill_offset,
155                                          int num_samples) OVERRIDE {
156     // Opus requires channel-interleaved samples in a single array.
157     for (int ch = 0; ch < audio_bus->channels(); ++ch) {
158       const float* src = audio_bus->channel(ch) + source_offset;
159       const float* const src_end = src + num_samples;
160       float* dest = buffer_.get() + buffer_fill_offset * num_channels_ + ch;
161       for (; src < src_end; ++src, dest += num_channels_)
162         *dest = *src;
163     }
164   }
165 
EncodeFromFilledBuffer(std::string * out)166   virtual bool EncodeFromFilledBuffer(std::string* out) OVERRIDE {
167     out->resize(kOpusMaxPayloadSize);
168     const opus_int32 result = opus_encode_float(
169         opus_encoder_, buffer_.get(), samples_per_10ms_,
170         reinterpret_cast<uint8*>(&out->at(0)), kOpusMaxPayloadSize);
171     if (result > 1) {
172       out->resize(result);
173       return true;
174     } else if (result < 0) {
175       LOG(ERROR) << "Error code from opus_encode_float(): " << result;
176       return false;
177     } else {
178       // Do nothing: The documentation says that a return value of zero or
179       // one byte means the packet does not need to be transmitted.
180       return false;
181     }
182   }
183 
184   const scoped_ptr<uint8[]> encoder_memory_;
185   OpusEncoder* const opus_encoder_;
186   const scoped_ptr<float[]> buffer_;
187 
188   // This is the recommended value, according to documentation in
189   // third_party/opus/src/include/opus.h, so that the Opus encoder does not
190   // degrade the audio due to memory constraints.
191   //
192   // Note: Whereas other RTP implementations do not, the cast library is
193   // perfectly capable of transporting larger than MTU-sized audio frames.
194   static const int kOpusMaxPayloadSize = 4000;
195 
196   DISALLOW_COPY_AND_ASSIGN(OpusImpl);
197 };
198 
199 class AudioEncoder::Pcm16Impl : public AudioEncoder::ImplBase {
200  public:
Pcm16Impl(CastEnvironment * cast_environment,int num_channels,int sampling_rate,const FrameEncodedCallback & callback)201   Pcm16Impl(CastEnvironment* cast_environment,
202             int num_channels, int sampling_rate,
203             const FrameEncodedCallback& callback)
204       : ImplBase(cast_environment, kPcm16, num_channels, sampling_rate,
205                  callback),
206         buffer_(new int16[num_channels * samples_per_10ms_]) {}
207 
~Pcm16Impl()208   virtual ~Pcm16Impl() {}
209 
210  private:
TransferSamplesIntoBuffer(const AudioBus * audio_bus,int source_offset,int buffer_fill_offset,int num_samples)211   virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus,
212                                          int source_offset,
213                                          int buffer_fill_offset,
214                                          int num_samples) OVERRIDE {
215     audio_bus->ToInterleavedPartial(
216         source_offset, num_samples, sizeof(int16),
217         buffer_.get() + buffer_fill_offset * num_channels_);
218   }
219 
EncodeFromFilledBuffer(std::string * out)220   virtual bool EncodeFromFilledBuffer(std::string* out) OVERRIDE {
221     // Output 16-bit PCM integers in big-endian byte order.
222     out->resize(num_channels_ * samples_per_10ms_ * sizeof(int16));
223     const int16* src = buffer_.get();
224     const int16* const src_end = src + num_channels_ * samples_per_10ms_;
225     uint16* dest = reinterpret_cast<uint16*>(&out->at(0));
226     for (; src < src_end; ++src, ++dest)
227       *dest = base::HostToNet16(*src);
228     return true;
229   }
230 
231  private:
232   const scoped_ptr<int16[]> buffer_;
233 
234   DISALLOW_COPY_AND_ASSIGN(Pcm16Impl);
235 };
236 
AudioEncoder(const scoped_refptr<CastEnvironment> & cast_environment,const AudioSenderConfig & audio_config,const FrameEncodedCallback & frame_encoded_callback)237 AudioEncoder::AudioEncoder(
238     const scoped_refptr<CastEnvironment>& cast_environment,
239     const AudioSenderConfig& audio_config,
240     const FrameEncodedCallback& frame_encoded_callback)
241     : cast_environment_(cast_environment) {
242   // Note: It doesn't matter which thread constructs AudioEncoder, just so long
243   // as all calls to InsertAudio() are by the same thread.
244   insert_thread_checker_.DetachFromThread();
245 
246   switch (audio_config.codec) {
247     case kOpus:
248       impl_.reset(new OpusImpl(
249           cast_environment, audio_config.channels, audio_config.frequency,
250           audio_config.bitrate, frame_encoded_callback));
251       break;
252     case kPcm16:
253       impl_.reset(new Pcm16Impl(
254           cast_environment, audio_config.channels, audio_config.frequency,
255           frame_encoded_callback));
256       break;
257     default:
258       NOTREACHED() << "Unsupported or unspecified codec for audio encoder";
259       break;
260   }
261 }
262 
~AudioEncoder()263 AudioEncoder::~AudioEncoder() {}
264 
InsertAudio(const AudioBus * audio_bus,const base::TimeTicks & recorded_time,const base::Closure & done_callback)265 void AudioEncoder::InsertAudio(
266     const AudioBus* audio_bus,
267     const base::TimeTicks& recorded_time,
268     const base::Closure& done_callback) {
269   DCHECK(insert_thread_checker_.CalledOnValidThread());
270   if (!impl_) {
271     NOTREACHED();
272     cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
273                                 done_callback);
274     return;
275   }
276   cast_environment_->PostTask(CastEnvironment::AUDIO_ENCODER, FROM_HERE,
277       base::Bind(&AudioEncoder::EncodeAudio, this, audio_bus, recorded_time,
278                  done_callback));
279 }
280 
EncodeAudio(const AudioBus * audio_bus,const base::TimeTicks & recorded_time,const base::Closure & done_callback)281 void AudioEncoder::EncodeAudio(
282     const AudioBus* audio_bus,
283     const base::TimeTicks& recorded_time,
284     const base::Closure& done_callback) {
285   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::AUDIO_ENCODER));
286   impl_->EncodeAudio(audio_bus, recorded_time, done_callback);
287   cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE,
288       base::Bind(LogAudioEncodedEvent, cast_environment_, recorded_time));
289 }
290 
291 }  // namespace cast
292 }  // namespace media
293