OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/cast/receiver/audio_decoder.h" | 5 #include "media/cast/receiver/audio_decoder.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/location.h" | 9 #include "base/location.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
12 #include "base/sys_byteorder.h" | 12 #include "base/sys_byteorder.h" |
13 #include "media/cast/cast_defines.h" | 13 #include "media/cast/cast_defines.h" |
14 #include "third_party/opus/src/include/opus.h" | 14 #include "third_party/opus/src/include/opus.h" |
15 | 15 |
16 namespace media { | 16 namespace media { |
17 namespace cast { | 17 namespace cast { |
18 | 18 |
19 // Base class that handles the common problem of detecting dropped frames, and | 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 | 20 // then invoking the Decode() method implemented by the subclasses to convert |
21 // the encoded payload data into usable audio data. | 21 // the encoded payload data into usable audio data. |
22 class AudioDecoder::ImplBase | 22 class AudioDecoder::ImplBase |
23 : public base::RefCountedThreadSafe<AudioDecoder::ImplBase> { | 23 : public base::RefCountedThreadSafe<AudioDecoder::ImplBase> { |
24 public: | 24 public: |
25 ImplBase(const scoped_refptr<CastEnvironment>& cast_environment, | 25 ImplBase(const scoped_refptr<CastEnvironment>& cast_environment, |
26 transport::Codec codec, | 26 Codec codec, |
27 int num_channels, | 27 int num_channels, |
28 int sampling_rate) | 28 int sampling_rate) |
29 : cast_environment_(cast_environment), | 29 : cast_environment_(cast_environment), |
30 codec_(codec), | 30 codec_(codec), |
31 num_channels_(num_channels), | 31 num_channels_(num_channels), |
32 cast_initialization_status_(STATUS_AUDIO_UNINITIALIZED), | 32 cast_initialization_status_(STATUS_AUDIO_UNINITIALIZED), |
33 seen_first_frame_(false) { | 33 seen_first_frame_(false) { |
34 if (num_channels_ <= 0 || sampling_rate <= 0 || sampling_rate % 100 != 0) | 34 if (num_channels_ <= 0 || sampling_rate <= 0 || sampling_rate % 100 != 0) |
35 cast_initialization_status_ = STATUS_INVALID_AUDIO_CONFIGURATION; | 35 cast_initialization_status_ = STATUS_INVALID_AUDIO_CONFIGURATION; |
36 } | 36 } |
37 | 37 |
38 CastInitializationStatus InitializationResult() const { | 38 CastInitializationStatus InitializationResult() const { |
39 return cast_initialization_status_; | 39 return cast_initialization_status_; |
40 } | 40 } |
41 | 41 |
42 void DecodeFrame(scoped_ptr<transport::EncodedFrame> encoded_frame, | 42 void DecodeFrame(scoped_ptr<EncodedFrame> encoded_frame, |
43 const DecodeFrameCallback& callback) { | 43 const DecodeFrameCallback& callback) { |
44 DCHECK_EQ(cast_initialization_status_, STATUS_AUDIO_INITIALIZED); | 44 DCHECK_EQ(cast_initialization_status_, STATUS_AUDIO_INITIALIZED); |
45 | 45 |
46 COMPILE_ASSERT(sizeof(encoded_frame->frame_id) == sizeof(last_frame_id_), | 46 COMPILE_ASSERT(sizeof(encoded_frame->frame_id) == sizeof(last_frame_id_), |
47 size_of_frame_id_types_do_not_match); | 47 size_of_frame_id_types_do_not_match); |
48 bool is_continuous = true; | 48 bool is_continuous = true; |
49 if (seen_first_frame_) { | 49 if (seen_first_frame_) { |
50 const uint32 frames_ahead = encoded_frame->frame_id - last_frame_id_; | 50 const uint32 frames_ahead = encoded_frame->frame_id - last_frame_id_; |
51 if (frames_ahead > 1) { | 51 if (frames_ahead > 1) { |
52 RecoverBecauseFramesWereDropped(); | 52 RecoverBecauseFramesWereDropped(); |
(...skipping 17 matching lines...) Expand all Loading... |
70 protected: | 70 protected: |
71 friend class base::RefCountedThreadSafe<ImplBase>; | 71 friend class base::RefCountedThreadSafe<ImplBase>; |
72 virtual ~ImplBase() {} | 72 virtual ~ImplBase() {} |
73 | 73 |
74 virtual void RecoverBecauseFramesWereDropped() {} | 74 virtual void RecoverBecauseFramesWereDropped() {} |
75 | 75 |
76 // Note: Implementation of Decode() is allowed to mutate |data|. | 76 // Note: Implementation of Decode() is allowed to mutate |data|. |
77 virtual scoped_ptr<AudioBus> Decode(uint8* data, int len) = 0; | 77 virtual scoped_ptr<AudioBus> Decode(uint8* data, int len) = 0; |
78 | 78 |
79 const scoped_refptr<CastEnvironment> cast_environment_; | 79 const scoped_refptr<CastEnvironment> cast_environment_; |
80 const transport::Codec codec_; | 80 const Codec codec_; |
81 const int num_channels_; | 81 const int num_channels_; |
82 | 82 |
83 // Subclass' ctor is expected to set this to STATUS_AUDIO_INITIALIZED. | 83 // Subclass' ctor is expected to set this to STATUS_AUDIO_INITIALIZED. |
84 CastInitializationStatus cast_initialization_status_; | 84 CastInitializationStatus cast_initialization_status_; |
85 | 85 |
86 private: | 86 private: |
87 bool seen_first_frame_; | 87 bool seen_first_frame_; |
88 uint32 last_frame_id_; | 88 uint32 last_frame_id_; |
89 | 89 |
90 DISALLOW_COPY_AND_ASSIGN(ImplBase); | 90 DISALLOW_COPY_AND_ASSIGN(ImplBase); |
91 }; | 91 }; |
92 | 92 |
93 class AudioDecoder::OpusImpl : public AudioDecoder::ImplBase { | 93 class AudioDecoder::OpusImpl : public AudioDecoder::ImplBase { |
94 public: | 94 public: |
95 OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment, | 95 OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment, |
96 int num_channels, | 96 int num_channels, |
97 int sampling_rate) | 97 int sampling_rate) |
98 : ImplBase(cast_environment, | 98 : ImplBase(cast_environment, |
99 transport::CODEC_AUDIO_OPUS, | 99 CODEC_AUDIO_OPUS, |
100 num_channels, | 100 num_channels, |
101 sampling_rate), | 101 sampling_rate), |
102 decoder_memory_(new uint8[opus_decoder_get_size(num_channels)]), | 102 decoder_memory_(new uint8[opus_decoder_get_size(num_channels)]), |
103 opus_decoder_(reinterpret_cast<OpusDecoder*>(decoder_memory_.get())), | 103 opus_decoder_(reinterpret_cast<OpusDecoder*>(decoder_memory_.get())), |
104 max_samples_per_frame_( | 104 max_samples_per_frame_( |
105 kOpusMaxFrameDurationMillis * sampling_rate / 1000), | 105 kOpusMaxFrameDurationMillis * sampling_rate / 1000), |
106 buffer_(new float[max_samples_per_frame_ * num_channels]) { | 106 buffer_(new float[max_samples_per_frame_ * num_channels]) { |
107 if (ImplBase::cast_initialization_status_ != STATUS_AUDIO_UNINITIALIZED) | 107 if (ImplBase::cast_initialization_status_ != STATUS_AUDIO_UNINITIALIZED) |
108 return; | 108 return; |
109 if (opus_decoder_init(opus_decoder_, sampling_rate, num_channels) != | 109 if (opus_decoder_init(opus_decoder_, sampling_rate, num_channels) != |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 | 159 |
160 DISALLOW_COPY_AND_ASSIGN(OpusImpl); | 160 DISALLOW_COPY_AND_ASSIGN(OpusImpl); |
161 }; | 161 }; |
162 | 162 |
163 class AudioDecoder::Pcm16Impl : public AudioDecoder::ImplBase { | 163 class AudioDecoder::Pcm16Impl : public AudioDecoder::ImplBase { |
164 public: | 164 public: |
165 Pcm16Impl(const scoped_refptr<CastEnvironment>& cast_environment, | 165 Pcm16Impl(const scoped_refptr<CastEnvironment>& cast_environment, |
166 int num_channels, | 166 int num_channels, |
167 int sampling_rate) | 167 int sampling_rate) |
168 : ImplBase(cast_environment, | 168 : ImplBase(cast_environment, |
169 transport::CODEC_AUDIO_PCM16, | 169 CODEC_AUDIO_PCM16, |
170 num_channels, | 170 num_channels, |
171 sampling_rate) { | 171 sampling_rate) { |
172 if (ImplBase::cast_initialization_status_ != STATUS_AUDIO_UNINITIALIZED) | 172 if (ImplBase::cast_initialization_status_ != STATUS_AUDIO_UNINITIALIZED) |
173 return; | 173 return; |
174 ImplBase::cast_initialization_status_ = STATUS_AUDIO_INITIALIZED; | 174 ImplBase::cast_initialization_status_ = STATUS_AUDIO_INITIALIZED; |
175 } | 175 } |
176 | 176 |
177 private: | 177 private: |
178 virtual ~Pcm16Impl() {} | 178 virtual ~Pcm16Impl() {} |
179 | 179 |
(...skipping 15 matching lines...) Expand all Loading... |
195 return audio_bus.Pass(); | 195 return audio_bus.Pass(); |
196 } | 196 } |
197 | 197 |
198 DISALLOW_COPY_AND_ASSIGN(Pcm16Impl); | 198 DISALLOW_COPY_AND_ASSIGN(Pcm16Impl); |
199 }; | 199 }; |
200 | 200 |
201 AudioDecoder::AudioDecoder( | 201 AudioDecoder::AudioDecoder( |
202 const scoped_refptr<CastEnvironment>& cast_environment, | 202 const scoped_refptr<CastEnvironment>& cast_environment, |
203 int channels, | 203 int channels, |
204 int sampling_rate, | 204 int sampling_rate, |
205 transport::Codec codec) | 205 Codec codec) |
206 : cast_environment_(cast_environment) { | 206 : cast_environment_(cast_environment) { |
207 switch (codec) { | 207 switch (codec) { |
208 case transport::CODEC_AUDIO_OPUS: | 208 case CODEC_AUDIO_OPUS: |
209 impl_ = new OpusImpl(cast_environment, channels, sampling_rate); | 209 impl_ = new OpusImpl(cast_environment, channels, sampling_rate); |
210 break; | 210 break; |
211 case transport::CODEC_AUDIO_PCM16: | 211 case CODEC_AUDIO_PCM16: |
212 impl_ = new Pcm16Impl(cast_environment, channels, sampling_rate); | 212 impl_ = new Pcm16Impl(cast_environment, channels, sampling_rate); |
213 break; | 213 break; |
214 default: | 214 default: |
215 NOTREACHED() << "Unknown or unspecified codec."; | 215 NOTREACHED() << "Unknown or unspecified codec."; |
216 break; | 216 break; |
217 } | 217 } |
218 } | 218 } |
219 | 219 |
220 AudioDecoder::~AudioDecoder() {} | 220 AudioDecoder::~AudioDecoder() {} |
221 | 221 |
222 CastInitializationStatus AudioDecoder::InitializationResult() const { | 222 CastInitializationStatus AudioDecoder::InitializationResult() const { |
223 if (impl_) | 223 if (impl_) |
224 return impl_->InitializationResult(); | 224 return impl_->InitializationResult(); |
225 return STATUS_UNSUPPORTED_AUDIO_CODEC; | 225 return STATUS_UNSUPPORTED_AUDIO_CODEC; |
226 } | 226 } |
227 | 227 |
228 void AudioDecoder::DecodeFrame( | 228 void AudioDecoder::DecodeFrame( |
229 scoped_ptr<transport::EncodedFrame> encoded_frame, | 229 scoped_ptr<EncodedFrame> encoded_frame, |
230 const DecodeFrameCallback& callback) { | 230 const DecodeFrameCallback& callback) { |
231 DCHECK(encoded_frame.get()); | 231 DCHECK(encoded_frame.get()); |
232 DCHECK(!callback.is_null()); | 232 DCHECK(!callback.is_null()); |
233 if (!impl_ || impl_->InitializationResult() != STATUS_AUDIO_INITIALIZED) { | 233 if (!impl_ || impl_->InitializationResult() != STATUS_AUDIO_INITIALIZED) { |
234 callback.Run(make_scoped_ptr<AudioBus>(NULL), false); | 234 callback.Run(make_scoped_ptr<AudioBus>(NULL), false); |
235 return; | 235 return; |
236 } | 236 } |
237 cast_environment_->PostTask(CastEnvironment::AUDIO, | 237 cast_environment_->PostTask(CastEnvironment::AUDIO, |
238 FROM_HERE, | 238 FROM_HERE, |
239 base::Bind(&AudioDecoder::ImplBase::DecodeFrame, | 239 base::Bind(&AudioDecoder::ImplBase::DecodeFrame, |
240 impl_, | 240 impl_, |
241 base::Passed(&encoded_frame), | 241 base::Passed(&encoded_frame), |
242 callback)); | 242 callback)); |
243 } | 243 } |
244 | 244 |
245 } // namespace cast | 245 } // namespace cast |
246 } // namespace media | 246 } // namespace media |
OLD | NEW |