| 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 |