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/sys_byteorder.h"
12 #include "media/cast/cast_defines.h"
13 #include "third_party/opus/src/include/opus.h"
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
> {
24 ImplBase(const scoped_refptr
<CastEnvironment
>& cast_environment
,
28 : cast_environment_(cast_environment
),
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;
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
,
65 base::Passed(&decoded_audio
),
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_
;
80 const int num_channels_
;
82 // Subclass' ctor is expected to set this to STATUS_INITIALIZED.
83 OperationalStatus operational_status_
;
86 bool seen_first_frame_
;
87 uint32 last_frame_id_
;
89 DISALLOW_COPY_AND_ASSIGN(ImplBase
);
92 class AudioDecoder::OpusImpl
: public AudioDecoder::ImplBase
{
94 OpusImpl(const scoped_refptr
<CastEnvironment
>& cast_environment
,
97 : ImplBase(cast_environment
,
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
)
108 if (opus_decoder_init(opus_decoder_
, sampling_rate
, num_channels
) !=
110 ImplBase::operational_status_
= STATUS_INVALID_CONFIGURATION
;
113 ImplBase::operational_status_
= STATUS_INITIALIZED
;
119 void RecoverBecauseFramesWereDropped() final
{
120 // Passing NULL for the input data notifies the decoder of frame loss.
121 const opus_int32 result
=
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
)
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
{
163 Pcm16Impl(const scoped_refptr
<CastEnvironment
>& cast_environment
,
166 : ImplBase(cast_environment
,
170 if (ImplBase::operational_status_
!= STATUS_UNINITIALIZED
)
172 ImplBase::operational_status_
= STATUS_INITIALIZED
;
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
]));
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
,
204 : cast_environment_(cast_environment
) {
206 case CODEC_AUDIO_OPUS
:
207 impl_
= new OpusImpl(cast_environment
, channels
, sampling_rate
);
209 case CODEC_AUDIO_PCM16
:
210 impl_
= new Pcm16Impl(cast_environment
, channels
, sampling_rate
);
213 NOTREACHED() << "Unknown or unspecified codec.";
218 AudioDecoder::~AudioDecoder() {}
220 OperationalStatus
AudioDecoder::InitializationResult() const {
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);
235 cast_environment_
->PostTask(CastEnvironment::AUDIO
,
237 base::Bind(&AudioDecoder::ImplBase::DecodeFrame
,
239 base::Passed(&encoded_frame
),