Remove Unused AsTextButtonBorder RTTI helper.
[chromium-blink-merge.git] / media / cast / audio_sender / audio_encoder.cc
blob2363619750d6d462c428946cc13b9d28a2c27802
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.
5 #include "media/cast/audio_sender/audio_encoder.h"
7 #include <algorithm>
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"
20 namespace media {
21 namespace cast {
23 // Base class that handles the common problem of feeding one or more AudioBus'
24 // data into a 10 ms buffer and then, once the buffer is full, encoding the
25 // signal and emitting an EncodedAudioFrame via the FrameEncodedCallback.
27 // Subclasses complete the implementation by handling the actual encoding
28 // details.
29 class AudioEncoder::ImplBase : public base::SupportsWeakPtr<ImplBase> {
30 public:
31 ImplBase(CastEnvironment* cast_environment,
32 transport::AudioCodec codec,
33 int num_channels,
34 int sampling_rate,
35 const FrameEncodedCallback& callback)
36 : cast_environment_(cast_environment),
37 codec_(codec),
38 num_channels_(num_channels),
39 samples_per_10ms_(sampling_rate / 100),
40 callback_(callback),
41 buffer_fill_end_(0),
42 frame_id_(0),
43 rtp_timestamp_(0),
44 weak_factory_(this) {
45 DCHECK_GT(num_channels_, 0);
46 DCHECK_GT(samples_per_10ms_, 0);
47 DCHECK_EQ(sampling_rate % 100, 0);
48 DCHECK_LE(samples_per_10ms_ * num_channels_,
49 transport::EncodedAudioFrame::kMaxNumberOfSamples);
51 if (num_channels_ <= 0 || samples_per_10ms_ <= 0 ||
52 sampling_rate % 100 != 0 ||
53 samples_per_10ms_ * num_channels_ >
54 transport::EncodedAudioFrame::kMaxNumberOfSamples) {
55 initialization_status_ = STATUS_INVALID_AUDIO_CONFIGURATION;
56 } else {
57 initialization_status_ = STATUS_INITIALIZED;
61 virtual ~ImplBase() {}
63 CastInitializationStatus InitializationResult() const {
64 return initialization_status_;
67 void LogAudioFrameEvent(uint32 rtp_timestamp,
68 uint32 frame_id,
69 CastLoggingEvent type) {
70 cast_environment_->Logging()->InsertFrameEvent(
71 cast_environment_->Clock()->NowTicks(), type, rtp_timestamp, frame_id);
74 void EncodeAudio(const AudioBus* audio_bus,
75 const base::TimeTicks& recorded_time,
76 const base::Closure& done_callback) {
77 int src_pos = 0;
78 int packet_count = 0;
79 while (audio_bus && src_pos < audio_bus->frames()) {
80 const int num_samples_to_xfer = std::min(
81 samples_per_10ms_ - buffer_fill_end_, audio_bus->frames() - src_pos);
82 DCHECK_EQ(audio_bus->channels(), num_channels_);
83 TransferSamplesIntoBuffer(
84 audio_bus, src_pos, buffer_fill_end_, num_samples_to_xfer);
85 src_pos += num_samples_to_xfer;
86 buffer_fill_end_ += num_samples_to_xfer;
88 if (src_pos == audio_bus->frames()) {
89 cast_environment_->PostTask(
90 CastEnvironment::MAIN, FROM_HERE, done_callback);
91 // Note: |audio_bus| is invalid once done_callback is invoked.
92 audio_bus = NULL;
95 if (buffer_fill_end_ == samples_per_10ms_) {
96 scoped_ptr<transport::EncodedAudioFrame> audio_frame(
97 new transport::EncodedAudioFrame());
98 audio_frame->codec = codec_;
99 audio_frame->frame_id = frame_id_++;
100 rtp_timestamp_ += samples_per_10ms_;
101 audio_frame->rtp_timestamp = rtp_timestamp_;
103 // Update logging.
104 cast_environment_->PostTask(CastEnvironment::MAIN,
105 FROM_HERE,
106 base::Bind(&ImplBase::LogAudioFrameEvent,
107 weak_factory_.GetWeakPtr(),
108 audio_frame->rtp_timestamp,
109 audio_frame->frame_id,
110 kAudioFrameReceived));
112 if (EncodeFromFilledBuffer(&audio_frame->data)) {
113 // Update logging.
114 cast_environment_->PostTask(CastEnvironment::MAIN,
115 FROM_HERE,
116 base::Bind(&ImplBase::LogAudioFrameEvent,
117 weak_factory_.GetWeakPtr(),
118 audio_frame->rtp_timestamp,
119 audio_frame->frame_id,
120 kAudioFrameEncoded));
121 // Compute an offset to determine the recorded time for the first
122 // audio sample in the buffer.
123 const base::TimeDelta buffer_time_offset =
124 (buffer_fill_end_ - src_pos) *
125 base::TimeDelta::FromMilliseconds(10) / samples_per_10ms_;
126 // TODO(miu): Consider batching EncodedAudioFrames so we only post a
127 // at most one task for each call to this method.
128 // Postpone every packet by 10mS with respect to the previous. Playout
129 // is postponed already by 10mS, and this will better correlate with
130 // the pacer's expectations.
131 //TODO(mikhal): Turn this into a list of packets.
132 // Update the end2end allowed error once this is fixed.
133 cast_environment_->PostDelayedTask(
134 CastEnvironment::MAIN,
135 FROM_HERE,
136 base::Bind(callback_,
137 base::Passed(&audio_frame),
138 recorded_time - buffer_time_offset),
139 base::TimeDelta::FromMilliseconds(packet_count * 10));
140 ++packet_count;
142 buffer_fill_end_ = 0;
147 protected:
148 virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus,
149 int source_offset,
150 int buffer_fill_offset,
151 int num_samples) = 0;
152 virtual bool EncodeFromFilledBuffer(std::string* out) = 0;
154 CastEnvironment* const cast_environment_;
155 const transport::AudioCodec codec_;
156 const int num_channels_;
157 const int samples_per_10ms_;
158 const FrameEncodedCallback callback_;
159 CastInitializationStatus initialization_status_;
161 private:
162 // In the case where a call to EncodeAudio() cannot completely fill the
163 // buffer, this points to the position at which to populate data in a later
164 // call.
165 int buffer_fill_end_;
167 // A counter used to label EncodedAudioFrames.
168 uint32 frame_id_;
170 // For audio, rtp_timestamp is computed as the sum of the audio samples seen
171 // so far.
172 uint32 rtp_timestamp_;
174 base::WeakPtrFactory<ImplBase> weak_factory_;
176 private:
177 DISALLOW_COPY_AND_ASSIGN(ImplBase);
180 class AudioEncoder::OpusImpl : public AudioEncoder::ImplBase {
181 public:
182 OpusImpl(CastEnvironment* cast_environment,
183 int num_channels,
184 int sampling_rate,
185 int bitrate,
186 const FrameEncodedCallback& callback)
187 : ImplBase(cast_environment,
188 transport::kOpus,
189 num_channels,
190 sampling_rate,
191 callback),
192 encoder_memory_(new uint8[opus_encoder_get_size(num_channels)]),
193 opus_encoder_(reinterpret_cast<OpusEncoder*>(encoder_memory_.get())),
194 buffer_(new float[num_channels * samples_per_10ms_]) {
195 if (ImplBase::initialization_status_ != STATUS_INITIALIZED) {
196 return;
199 CHECK_EQ(
200 opus_encoder_init(
201 opus_encoder_, sampling_rate, num_channels, OPUS_APPLICATION_AUDIO),
202 OPUS_OK);
203 if (bitrate <= 0) {
204 // Note: As of 2013-10-31, the encoder in "auto bitrate" mode would use a
205 // variable bitrate up to 102kbps for 2-channel, 48 kHz audio and a 10 ms
206 // frame size. The opus library authors may, of course, adjust this in
207 // later versions.
208 bitrate = OPUS_AUTO;
210 CHECK_EQ(opus_encoder_ctl(opus_encoder_, OPUS_SET_BITRATE(bitrate)),
211 OPUS_OK);
214 virtual ~OpusImpl() {}
216 private:
217 virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus,
218 int source_offset,
219 int buffer_fill_offset,
220 int num_samples) OVERRIDE {
221 // Opus requires channel-interleaved samples in a single array.
222 for (int ch = 0; ch < audio_bus->channels(); ++ch) {
223 const float* src = audio_bus->channel(ch) + source_offset;
224 const float* const src_end = src + num_samples;
225 float* dest = buffer_.get() + buffer_fill_offset * num_channels_ + ch;
226 for (; src < src_end; ++src, dest += num_channels_)
227 *dest = *src;
231 virtual bool EncodeFromFilledBuffer(std::string* out) OVERRIDE {
232 out->resize(kOpusMaxPayloadSize);
233 const opus_int32 result =
234 opus_encode_float(opus_encoder_,
235 buffer_.get(),
236 samples_per_10ms_,
237 reinterpret_cast<uint8*>(&out->at(0)),
238 kOpusMaxPayloadSize);
239 if (result > 1) {
240 out->resize(result);
241 return true;
242 } else if (result < 0) {
243 LOG(ERROR) << "Error code from opus_encode_float(): " << result;
244 return false;
245 } else {
246 // Do nothing: The documentation says that a return value of zero or
247 // one byte means the packet does not need to be transmitted.
248 return false;
252 const scoped_ptr<uint8[]> encoder_memory_;
253 OpusEncoder* const opus_encoder_;
254 const scoped_ptr<float[]> buffer_;
256 // This is the recommended value, according to documentation in
257 // third_party/opus/src/include/opus.h, so that the Opus encoder does not
258 // degrade the audio due to memory constraints.
260 // Note: Whereas other RTP implementations do not, the cast library is
261 // perfectly capable of transporting larger than MTU-sized audio frames.
262 static const int kOpusMaxPayloadSize = 4000;
264 DISALLOW_COPY_AND_ASSIGN(OpusImpl);
267 class AudioEncoder::Pcm16Impl : public AudioEncoder::ImplBase {
268 public:
269 Pcm16Impl(CastEnvironment* cast_environment,
270 int num_channels,
271 int sampling_rate,
272 const FrameEncodedCallback& callback)
273 : ImplBase(cast_environment,
274 transport::kPcm16,
275 num_channels,
276 sampling_rate,
277 callback),
278 buffer_(new int16[num_channels * samples_per_10ms_]) {}
280 virtual ~Pcm16Impl() {}
282 private:
283 virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus,
284 int source_offset,
285 int buffer_fill_offset,
286 int num_samples) OVERRIDE {
287 audio_bus->ToInterleavedPartial(
288 source_offset,
289 num_samples,
290 sizeof(int16),
291 buffer_.get() + buffer_fill_offset * num_channels_);
294 virtual bool EncodeFromFilledBuffer(std::string* out) OVERRIDE {
295 // Output 16-bit PCM integers in big-endian byte order.
296 out->resize(num_channels_ * samples_per_10ms_ * sizeof(int16));
297 const int16* src = buffer_.get();
298 const int16* const src_end = src + num_channels_ * samples_per_10ms_;
299 uint16* dest = reinterpret_cast<uint16*>(&out->at(0));
300 for (; src < src_end; ++src, ++dest)
301 *dest = base::HostToNet16(*src);
302 return true;
305 private:
306 const scoped_ptr<int16[]> buffer_;
308 DISALLOW_COPY_AND_ASSIGN(Pcm16Impl);
311 AudioEncoder::AudioEncoder(
312 const scoped_refptr<CastEnvironment>& cast_environment,
313 const AudioSenderConfig& audio_config,
314 const FrameEncodedCallback& frame_encoded_callback)
315 : cast_environment_(cast_environment) {
316 // Note: It doesn't matter which thread constructs AudioEncoder, just so long
317 // as all calls to InsertAudio() are by the same thread.
318 insert_thread_checker_.DetachFromThread();
320 switch (audio_config.codec) {
321 case transport::kOpus:
322 impl_.reset(new OpusImpl(cast_environment,
323 audio_config.channels,
324 audio_config.frequency,
325 audio_config.bitrate,
326 frame_encoded_callback));
327 break;
328 case transport::kPcm16:
329 impl_.reset(new Pcm16Impl(cast_environment,
330 audio_config.channels,
331 audio_config.frequency,
332 frame_encoded_callback));
333 break;
334 default:
335 NOTREACHED() << "Unsupported or unspecified codec for audio encoder";
336 break;
340 AudioEncoder::~AudioEncoder() {}
342 CastInitializationStatus AudioEncoder::InitializationResult() const {
343 if (impl_) {
344 return impl_->InitializationResult();
346 return STATUS_UNSUPPORTED_AUDIO_CODEC;
349 void AudioEncoder::InsertAudio(const AudioBus* audio_bus,
350 const base::TimeTicks& recorded_time,
351 const base::Closure& done_callback) {
352 DCHECK(insert_thread_checker_.CalledOnValidThread());
353 if (!impl_) {
354 NOTREACHED();
355 cast_environment_->PostTask(
356 CastEnvironment::MAIN, FROM_HERE, done_callback);
357 return;
359 cast_environment_->PostTask(CastEnvironment::AUDIO_ENCODER,
360 FROM_HERE,
361 base::Bind(&AudioEncoder::EncodeAudio,
362 this,
363 audio_bus,
364 recorded_time,
365 done_callback));
368 void AudioEncoder::EncodeAudio(const AudioBus* audio_bus,
369 const base::TimeTicks& recorded_time,
370 const base::Closure& done_callback) {
371 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::AUDIO_ENCODER));
372 impl_->EncodeAudio(audio_bus, recorded_time, done_callback);
375 } // namespace cast
376 } // namespace media