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"
8 #include "base/bind_helpers.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/sys_byteorder.h"
13 #include "media/cast/cast_defines.h"
14 #include "third_party/opus/src/include/opus.h"
19 // Base class that handles the common problem of detecting dropped frames, and
20 // then invoking the Decode() method implemented by the subclasses to convert
21 // the encoded payload data into usable audio data.
22 class AudioDecoder::ImplBase
23 : public base::RefCountedThreadSafe
<AudioDecoder::ImplBase
> {
25 ImplBase(const scoped_refptr
<CastEnvironment
>& cast_environment
,
29 : cast_environment_(cast_environment
),
31 num_channels_(num_channels
),
32 operational_status_(STATUS_UNINITIALIZED
),
33 seen_first_frame_(false) {
34 if (num_channels_
<= 0 || sampling_rate
<= 0 || sampling_rate
% 100 != 0)
35 operational_status_
= STATUS_INVALID_CONFIGURATION
;
38 OperationalStatus
InitializationResult() const {
39 return operational_status_
;
42 void DecodeFrame(scoped_ptr
<EncodedFrame
> encoded_frame
,
43 const DecodeFrameCallback
& callback
) {
44 DCHECK_EQ(operational_status_
, STATUS_INITIALIZED
);
46 static_assert(sizeof(encoded_frame
->frame_id
) == sizeof(last_frame_id_
),
47 "size of frame_id types do not match");
48 bool is_continuous
= true;
49 if (seen_first_frame_
) {
50 const uint32 frames_ahead
= encoded_frame
->frame_id
- last_frame_id_
;
51 if (frames_ahead
> 1) {
52 RecoverBecauseFramesWereDropped();
53 is_continuous
= false;
56 seen_first_frame_
= true;
58 last_frame_id_
= encoded_frame
->frame_id
;
60 scoped_ptr
<AudioBus
> decoded_audio
= Decode(
61 encoded_frame
->mutable_bytes(),
62 static_cast<int>(encoded_frame
->data
.size()));
63 cast_environment_
->PostTask(CastEnvironment::MAIN
,
66 base::Passed(&decoded_audio
),
71 friend class base::RefCountedThreadSafe
<ImplBase
>;
72 virtual ~ImplBase() {}
74 virtual void RecoverBecauseFramesWereDropped() {}
76 // Note: Implementation of Decode() is allowed to mutate |data|.
77 virtual scoped_ptr
<AudioBus
> Decode(uint8
* data
, int len
) = 0;
79 const scoped_refptr
<CastEnvironment
> cast_environment_
;
81 const int num_channels_
;
83 // Subclass' ctor is expected to set this to STATUS_INITIALIZED.
84 OperationalStatus operational_status_
;
87 bool seen_first_frame_
;
88 uint32 last_frame_id_
;
90 DISALLOW_COPY_AND_ASSIGN(ImplBase
);
93 class AudioDecoder::OpusImpl
: public AudioDecoder::ImplBase
{
95 OpusImpl(const scoped_refptr
<CastEnvironment
>& cast_environment
,
98 : ImplBase(cast_environment
,
102 decoder_memory_(new uint8
[opus_decoder_get_size(num_channels
)]),
103 opus_decoder_(reinterpret_cast<OpusDecoder
*>(decoder_memory_
.get())),
104 max_samples_per_frame_(
105 kOpusMaxFrameDurationMillis
* sampling_rate
/ 1000),
106 buffer_(new float[max_samples_per_frame_
* num_channels
]) {
107 if (ImplBase::operational_status_
!= STATUS_UNINITIALIZED
)
109 if (opus_decoder_init(opus_decoder_
, sampling_rate
, num_channels
) !=
111 ImplBase::operational_status_
= STATUS_INVALID_CONFIGURATION
;
114 ImplBase::operational_status_
= STATUS_INITIALIZED
;
120 void RecoverBecauseFramesWereDropped() final
{
121 // Passing NULL for the input data notifies the decoder of frame loss.
122 const opus_int32 result
=
124 opus_decoder_
, NULL
, 0, buffer_
.get(), max_samples_per_frame_
, 0);
125 DCHECK_GE(result
, 0);
128 scoped_ptr
<AudioBus
> Decode(uint8
* data
, int len
) final
{
129 scoped_ptr
<AudioBus
> audio_bus
;
130 const opus_int32 num_samples_decoded
= opus_decode_float(
131 opus_decoder_
, data
, len
, buffer_
.get(), max_samples_per_frame_
, 0);
132 if (num_samples_decoded
<= 0)
133 return audio_bus
.Pass(); // Decode error.
135 // Copy interleaved samples from |buffer_| into a new AudioBus (where
136 // samples are stored in planar format, for each channel).
137 audio_bus
= AudioBus::Create(num_channels_
, num_samples_decoded
).Pass();
138 // TODO(miu): This should be moved into AudioBus::FromInterleaved().
139 for (int ch
= 0; ch
< num_channels_
; ++ch
) {
140 const float* src
= buffer_
.get() + ch
;
141 const float* const src_end
= src
+ num_samples_decoded
* num_channels_
;
142 float* dest
= audio_bus
->channel(ch
);
143 for (; src
< src_end
; src
+= num_channels_
, ++dest
)
146 return audio_bus
.Pass();
149 const scoped_ptr
<uint8
[]> decoder_memory_
;
150 OpusDecoder
* const opus_decoder_
;
151 const int max_samples_per_frame_
;
152 const scoped_ptr
<float[]> buffer_
;
154 // According to documentation in third_party/opus/src/include/opus.h, we must
155 // provide enough space in |buffer_| to contain 120ms of samples. At 48 kHz,
156 // then, that means 5760 samples times the number of channels.
157 static const int kOpusMaxFrameDurationMillis
= 120;
159 DISALLOW_COPY_AND_ASSIGN(OpusImpl
);
162 class AudioDecoder::Pcm16Impl
: public AudioDecoder::ImplBase
{
164 Pcm16Impl(const scoped_refptr
<CastEnvironment
>& cast_environment
,
167 : ImplBase(cast_environment
,
171 if (ImplBase::operational_status_
!= STATUS_UNINITIALIZED
)
173 ImplBase::operational_status_
= STATUS_INITIALIZED
;
177 ~Pcm16Impl() final
{}
179 scoped_ptr
<AudioBus
> Decode(uint8
* data
, int len
) final
{
180 scoped_ptr
<AudioBus
> audio_bus
;
181 const int num_samples
= len
/ sizeof(int16
) / num_channels_
;
182 if (num_samples
<= 0)
183 return audio_bus
.Pass();
185 int16
* const pcm_data
= reinterpret_cast<int16
*>(data
);
186 #if defined(ARCH_CPU_LITTLE_ENDIAN)
187 // Convert endianness.
188 const int num_elements
= num_samples
* num_channels_
;
189 for (int i
= 0; i
< num_elements
; ++i
)
190 pcm_data
[i
] = static_cast<int16
>(base::NetToHost16(pcm_data
[i
]));
192 audio_bus
= AudioBus::Create(num_channels_
, num_samples
).Pass();
193 audio_bus
->FromInterleaved(pcm_data
, num_samples
, sizeof(int16
));
194 return audio_bus
.Pass();
197 DISALLOW_COPY_AND_ASSIGN(Pcm16Impl
);
200 AudioDecoder::AudioDecoder(
201 const scoped_refptr
<CastEnvironment
>& cast_environment
,
205 : cast_environment_(cast_environment
) {
207 case CODEC_AUDIO_OPUS
:
208 impl_
= new OpusImpl(cast_environment
, channels
, sampling_rate
);
210 case CODEC_AUDIO_PCM16
:
211 impl_
= new Pcm16Impl(cast_environment
, channels
, sampling_rate
);
214 NOTREACHED() << "Unknown or unspecified codec.";
219 AudioDecoder::~AudioDecoder() {}
221 OperationalStatus
AudioDecoder::InitializationResult() const {
223 return impl_
->InitializationResult();
224 return STATUS_UNSUPPORTED_CODEC
;
227 void AudioDecoder::DecodeFrame(
228 scoped_ptr
<EncodedFrame
> encoded_frame
,
229 const DecodeFrameCallback
& callback
) {
230 DCHECK(encoded_frame
.get());
231 DCHECK(!callback
.is_null());
232 if (!impl_
.get() || impl_
->InitializationResult() != STATUS_INITIALIZED
) {
233 callback
.Run(make_scoped_ptr
<AudioBus
>(NULL
), false);
236 cast_environment_
->PostTask(CastEnvironment::AUDIO
,
238 base::Bind(&AudioDecoder::ImplBase::DecodeFrame
,
240 base::Passed(&encoded_frame
),