Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / cast / receiver / audio_decoder.cc
blobf8a40be841ca21d4c2d9a38f4b541ffef3f85bfa
1 // Copyright 2014 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/receiver/audio_decoder.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/sys_byteorder.h"
12 #include "media/cast/cast_defines.h"
13 #include "third_party/opus/src/include/opus.h"
15 namespace media {
16 namespace cast {
18 // Base class that handles the common problem of detecting dropped frames, and
19 // then invoking the Decode() method implemented by the subclasses to convert
20 // the encoded payload data into usable audio data.
21 class AudioDecoder::ImplBase
22 : public base::RefCountedThreadSafe<AudioDecoder::ImplBase> {
23 public:
24 ImplBase(const scoped_refptr<CastEnvironment>& cast_environment,
25 Codec codec,
26 int num_channels,
27 int sampling_rate)
28 : cast_environment_(cast_environment),
29 codec_(codec),
30 num_channels_(num_channels),
31 operational_status_(STATUS_UNINITIALIZED),
32 seen_first_frame_(false) {
33 if (num_channels_ <= 0 || sampling_rate <= 0 || sampling_rate % 100 != 0)
34 operational_status_ = STATUS_INVALID_CONFIGURATION;
37 OperationalStatus InitializationResult() const {
38 return operational_status_;
41 void DecodeFrame(scoped_ptr<EncodedFrame> encoded_frame,
42 const DecodeFrameCallback& callback) {
43 DCHECK_EQ(operational_status_, STATUS_INITIALIZED);
45 static_assert(sizeof(encoded_frame->frame_id) == sizeof(last_frame_id_),
46 "size of frame_id types do not match");
47 bool is_continuous = true;
48 if (seen_first_frame_) {
49 const uint32 frames_ahead = encoded_frame->frame_id - last_frame_id_;
50 if (frames_ahead > 1) {
51 RecoverBecauseFramesWereDropped();
52 is_continuous = false;
54 } else {
55 seen_first_frame_ = true;
57 last_frame_id_ = encoded_frame->frame_id;
59 scoped_ptr<AudioBus> decoded_audio = Decode(
60 encoded_frame->mutable_bytes(),
61 static_cast<int>(encoded_frame->data.size()));
62 cast_environment_->PostTask(CastEnvironment::MAIN,
63 FROM_HERE,
64 base::Bind(callback,
65 base::Passed(&decoded_audio),
66 is_continuous));
69 protected:
70 friend class base::RefCountedThreadSafe<ImplBase>;
71 virtual ~ImplBase() {}
73 virtual void RecoverBecauseFramesWereDropped() {}
75 // Note: Implementation of Decode() is allowed to mutate |data|.
76 virtual scoped_ptr<AudioBus> Decode(uint8* data, int len) = 0;
78 const scoped_refptr<CastEnvironment> cast_environment_;
79 const Codec codec_;
80 const int num_channels_;
82 // Subclass' ctor is expected to set this to STATUS_INITIALIZED.
83 OperationalStatus operational_status_;
85 private:
86 bool seen_first_frame_;
87 uint32 last_frame_id_;
89 DISALLOW_COPY_AND_ASSIGN(ImplBase);
92 class AudioDecoder::OpusImpl : public AudioDecoder::ImplBase {
93 public:
94 OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment,
95 int num_channels,
96 int sampling_rate)
97 : ImplBase(cast_environment,
98 CODEC_AUDIO_OPUS,
99 num_channels,
100 sampling_rate),
101 decoder_memory_(new uint8[opus_decoder_get_size(num_channels)]),
102 opus_decoder_(reinterpret_cast<OpusDecoder*>(decoder_memory_.get())),
103 max_samples_per_frame_(
104 kOpusMaxFrameDurationMillis * sampling_rate / 1000),
105 buffer_(new float[max_samples_per_frame_ * num_channels]) {
106 if (ImplBase::operational_status_ != STATUS_UNINITIALIZED)
107 return;
108 if (opus_decoder_init(opus_decoder_, sampling_rate, num_channels) !=
109 OPUS_OK) {
110 ImplBase::operational_status_ = STATUS_INVALID_CONFIGURATION;
111 return;
113 ImplBase::operational_status_ = STATUS_INITIALIZED;
116 private:
117 ~OpusImpl() final {}
119 void RecoverBecauseFramesWereDropped() final {
120 // Passing NULL for the input data notifies the decoder of frame loss.
121 const opus_int32 result =
122 opus_decode_float(
123 opus_decoder_, NULL, 0, buffer_.get(), max_samples_per_frame_, 0);
124 DCHECK_GE(result, 0);
127 scoped_ptr<AudioBus> Decode(uint8* data, int len) final {
128 scoped_ptr<AudioBus> audio_bus;
129 const opus_int32 num_samples_decoded = opus_decode_float(
130 opus_decoder_, data, len, buffer_.get(), max_samples_per_frame_, 0);
131 if (num_samples_decoded <= 0)
132 return audio_bus.Pass(); // Decode error.
134 // Copy interleaved samples from |buffer_| into a new AudioBus (where
135 // samples are stored in planar format, for each channel).
136 audio_bus = AudioBus::Create(num_channels_, num_samples_decoded).Pass();
137 // TODO(miu): This should be moved into AudioBus::FromInterleaved().
138 for (int ch = 0; ch < num_channels_; ++ch) {
139 const float* src = buffer_.get() + ch;
140 const float* const src_end = src + num_samples_decoded * num_channels_;
141 float* dest = audio_bus->channel(ch);
142 for (; src < src_end; src += num_channels_, ++dest)
143 *dest = *src;
145 return audio_bus.Pass();
148 const scoped_ptr<uint8[]> decoder_memory_;
149 OpusDecoder* const opus_decoder_;
150 const int max_samples_per_frame_;
151 const scoped_ptr<float[]> buffer_;
153 // According to documentation in third_party/opus/src/include/opus.h, we must
154 // provide enough space in |buffer_| to contain 120ms of samples. At 48 kHz,
155 // then, that means 5760 samples times the number of channels.
156 static const int kOpusMaxFrameDurationMillis = 120;
158 DISALLOW_COPY_AND_ASSIGN(OpusImpl);
161 class AudioDecoder::Pcm16Impl : public AudioDecoder::ImplBase {
162 public:
163 Pcm16Impl(const scoped_refptr<CastEnvironment>& cast_environment,
164 int num_channels,
165 int sampling_rate)
166 : ImplBase(cast_environment,
167 CODEC_AUDIO_PCM16,
168 num_channels,
169 sampling_rate) {
170 if (ImplBase::operational_status_ != STATUS_UNINITIALIZED)
171 return;
172 ImplBase::operational_status_ = STATUS_INITIALIZED;
175 private:
176 ~Pcm16Impl() final {}
178 scoped_ptr<AudioBus> Decode(uint8* data, int len) final {
179 scoped_ptr<AudioBus> audio_bus;
180 const int num_samples = len / sizeof(int16) / num_channels_;
181 if (num_samples <= 0)
182 return audio_bus.Pass();
184 int16* const pcm_data = reinterpret_cast<int16*>(data);
185 #if defined(ARCH_CPU_LITTLE_ENDIAN)
186 // Convert endianness.
187 const int num_elements = num_samples * num_channels_;
188 for (int i = 0; i < num_elements; ++i)
189 pcm_data[i] = static_cast<int16>(base::NetToHost16(pcm_data[i]));
190 #endif
191 audio_bus = AudioBus::Create(num_channels_, num_samples).Pass();
192 audio_bus->FromInterleaved(pcm_data, num_samples, sizeof(int16));
193 return audio_bus.Pass();
196 DISALLOW_COPY_AND_ASSIGN(Pcm16Impl);
199 AudioDecoder::AudioDecoder(
200 const scoped_refptr<CastEnvironment>& cast_environment,
201 int channels,
202 int sampling_rate,
203 Codec codec)
204 : cast_environment_(cast_environment) {
205 switch (codec) {
206 case CODEC_AUDIO_OPUS:
207 impl_ = new OpusImpl(cast_environment, channels, sampling_rate);
208 break;
209 case CODEC_AUDIO_PCM16:
210 impl_ = new Pcm16Impl(cast_environment, channels, sampling_rate);
211 break;
212 default:
213 NOTREACHED() << "Unknown or unspecified codec.";
214 break;
218 AudioDecoder::~AudioDecoder() {}
220 OperationalStatus AudioDecoder::InitializationResult() const {
221 if (impl_.get())
222 return impl_->InitializationResult();
223 return STATUS_UNSUPPORTED_CODEC;
226 void AudioDecoder::DecodeFrame(
227 scoped_ptr<EncodedFrame> encoded_frame,
228 const DecodeFrameCallback& callback) {
229 DCHECK(encoded_frame.get());
230 DCHECK(!callback.is_null());
231 if (!impl_.get() || impl_->InitializationResult() != STATUS_INITIALIZED) {
232 callback.Run(make_scoped_ptr<AudioBus>(NULL), false);
233 return;
235 cast_environment_->PostTask(CastEnvironment::AUDIO,
236 FROM_HERE,
237 base::Bind(&AudioDecoder::ImplBase::DecodeFrame,
238 impl_,
239 base::Passed(&encoded_frame),
240 callback));
243 } // namespace cast
244 } // namespace media