| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 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. | |
| 4 | |
| 5 #include "media/cast/audio_receiver/audio_decoder.h" | |
| 6 | |
| 7 #include "base/bind.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" | |
| 15 | |
| 16 namespace media { | |
| 17 namespace cast { | |
| 18 | |
| 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> { | |
| 24 public: | |
| 25 ImplBase(const scoped_refptr<CastEnvironment>& cast_environment, | |
| 26 transport::AudioCodec codec, | |
| 27 int num_channels, | |
| 28 int sampling_rate) | |
| 29 : cast_environment_(cast_environment), | |
| 30 codec_(codec), | |
| 31 num_channels_(num_channels), | |
| 32 cast_initialization_status_(STATUS_AUDIO_UNINITIALIZED), | |
| 33 seen_first_frame_(false) { | |
| 34 if (num_channels_ <= 0 || sampling_rate <= 0 || sampling_rate % 100 != 0) | |
| 35 cast_initialization_status_ = STATUS_INVALID_AUDIO_CONFIGURATION; | |
| 36 } | |
| 37 | |
| 38 CastInitializationStatus InitializationResult() const { | |
| 39 return cast_initialization_status_; | |
| 40 } | |
| 41 | |
| 42 void DecodeFrame(scoped_ptr<transport::EncodedFrame> encoded_frame, | |
| 43 const DecodeFrameCallback& callback) { | |
| 44 DCHECK_EQ(cast_initialization_status_, STATUS_AUDIO_INITIALIZED); | |
| 45 | |
| 46 COMPILE_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; | |
| 54 } | |
| 55 } else { | |
| 56 seen_first_frame_ = true; | |
| 57 } | |
| 58 last_frame_id_ = encoded_frame->frame_id; | |
| 59 | |
| 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, | |
| 64 FROM_HERE, | |
| 65 base::Bind(callback, | |
| 66 base::Passed(&decoded_audio), | |
| 67 is_continuous)); | |
| 68 } | |
| 69 | |
| 70 protected: | |
| 71 friend class base::RefCountedThreadSafe<ImplBase>; | |
| 72 virtual ~ImplBase() {} | |
| 73 | |
| 74 virtual void RecoverBecauseFramesWereDropped() {} | |
| 75 | |
| 76 // Note: Implementation of Decode() is allowed to mutate |data|. | |
| 77 virtual scoped_ptr<AudioBus> Decode(uint8* data, int len) = 0; | |
| 78 | |
| 79 const scoped_refptr<CastEnvironment> cast_environment_; | |
| 80 const transport::AudioCodec codec_; | |
| 81 const int num_channels_; | |
| 82 | |
| 83 // Subclass' ctor is expected to set this to STATUS_AUDIO_INITIALIZED. | |
| 84 CastInitializationStatus cast_initialization_status_; | |
| 85 | |
| 86 private: | |
| 87 bool seen_first_frame_; | |
| 88 uint32 last_frame_id_; | |
| 89 | |
| 90 DISALLOW_COPY_AND_ASSIGN(ImplBase); | |
| 91 }; | |
| 92 | |
| 93 class AudioDecoder::OpusImpl : public AudioDecoder::ImplBase { | |
| 94 public: | |
| 95 OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment, | |
| 96 int num_channels, | |
| 97 int sampling_rate) | |
| 98 : ImplBase(cast_environment, | |
| 99 transport::kOpus, | |
| 100 num_channels, | |
| 101 sampling_rate), | |
| 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::cast_initialization_status_ != STATUS_AUDIO_UNINITIALIZED) | |
| 108 return; | |
| 109 if (opus_decoder_init(opus_decoder_, sampling_rate, num_channels) != | |
| 110 OPUS_OK) { | |
| 111 ImplBase::cast_initialization_status_ = | |
| 112 STATUS_INVALID_AUDIO_CONFIGURATION; | |
| 113 return; | |
| 114 } | |
| 115 ImplBase::cast_initialization_status_ = STATUS_AUDIO_INITIALIZED; | |
| 116 } | |
| 117 | |
| 118 private: | |
| 119 virtual ~OpusImpl() {} | |
| 120 | |
| 121 virtual void RecoverBecauseFramesWereDropped() OVERRIDE { | |
| 122 // Passing NULL for the input data notifies the decoder of frame loss. | |
| 123 const opus_int32 result = | |
| 124 opus_decode_float( | |
| 125 opus_decoder_, NULL, 0, buffer_.get(), max_samples_per_frame_, 0); | |
| 126 DCHECK_GE(result, 0); | |
| 127 } | |
| 128 | |
| 129 virtual scoped_ptr<AudioBus> Decode(uint8* data, int len) OVERRIDE { | |
| 130 scoped_ptr<AudioBus> audio_bus; | |
| 131 const opus_int32 num_samples_decoded = opus_decode_float( | |
| 132 opus_decoder_, data, len, buffer_.get(), max_samples_per_frame_, 0); | |
| 133 if (num_samples_decoded <= 0) | |
| 134 return audio_bus.Pass(); // Decode error. | |
| 135 | |
| 136 // Copy interleaved samples from |buffer_| into a new AudioBus (where | |
| 137 // samples are stored in planar format, for each channel). | |
| 138 audio_bus = AudioBus::Create(num_channels_, num_samples_decoded).Pass(); | |
| 139 // TODO(miu): This should be moved into AudioBus::FromInterleaved(). | |
| 140 for (int ch = 0; ch < num_channels_; ++ch) { | |
| 141 const float* src = buffer_.get() + ch; | |
| 142 const float* const src_end = src + num_samples_decoded * num_channels_; | |
| 143 float* dest = audio_bus->channel(ch); | |
| 144 for (; src < src_end; src += num_channels_, ++dest) | |
| 145 *dest = *src; | |
| 146 } | |
| 147 return audio_bus.Pass(); | |
| 148 } | |
| 149 | |
| 150 const scoped_ptr<uint8[]> decoder_memory_; | |
| 151 OpusDecoder* const opus_decoder_; | |
| 152 const int max_samples_per_frame_; | |
| 153 const scoped_ptr<float[]> buffer_; | |
| 154 | |
| 155 // According to documentation in third_party/opus/src/include/opus.h, we must | |
| 156 // provide enough space in |buffer_| to contain 120ms of samples. At 48 kHz, | |
| 157 // then, that means 5760 samples times the number of channels. | |
| 158 static const int kOpusMaxFrameDurationMillis = 120; | |
| 159 | |
| 160 DISALLOW_COPY_AND_ASSIGN(OpusImpl); | |
| 161 }; | |
| 162 | |
| 163 class AudioDecoder::Pcm16Impl : public AudioDecoder::ImplBase { | |
| 164 public: | |
| 165 Pcm16Impl(const scoped_refptr<CastEnvironment>& cast_environment, | |
| 166 int num_channels, | |
| 167 int sampling_rate) | |
| 168 : ImplBase(cast_environment, | |
| 169 transport::kPcm16, | |
| 170 num_channels, | |
| 171 sampling_rate) { | |
| 172 if (ImplBase::cast_initialization_status_ != STATUS_AUDIO_UNINITIALIZED) | |
| 173 return; | |
| 174 ImplBase::cast_initialization_status_ = STATUS_AUDIO_INITIALIZED; | |
| 175 } | |
| 176 | |
| 177 private: | |
| 178 virtual ~Pcm16Impl() {} | |
| 179 | |
| 180 virtual scoped_ptr<AudioBus> Decode(uint8* data, int len) OVERRIDE { | |
| 181 scoped_ptr<AudioBus> audio_bus; | |
| 182 const int num_samples = len / sizeof(int16) / num_channels_; | |
| 183 if (num_samples <= 0) | |
| 184 return audio_bus.Pass(); | |
| 185 | |
| 186 int16* const pcm_data = reinterpret_cast<int16*>(data); | |
| 187 #if defined(ARCH_CPU_LITTLE_ENDIAN) | |
| 188 // Convert endianness. | |
| 189 const int num_elements = num_samples * num_channels_; | |
| 190 for (int i = 0; i < num_elements; ++i) | |
| 191 pcm_data[i] = static_cast<int16>(base::NetToHost16(pcm_data[i])); | |
| 192 #endif | |
| 193 audio_bus = AudioBus::Create(num_channels_, num_samples).Pass(); | |
| 194 audio_bus->FromInterleaved(pcm_data, num_samples, sizeof(int16)); | |
| 195 return audio_bus.Pass(); | |
| 196 } | |
| 197 | |
| 198 DISALLOW_COPY_AND_ASSIGN(Pcm16Impl); | |
| 199 }; | |
| 200 | |
| 201 AudioDecoder::AudioDecoder( | |
| 202 const scoped_refptr<CastEnvironment>& cast_environment, | |
| 203 const FrameReceiverConfig& audio_config) | |
| 204 : cast_environment_(cast_environment) { | |
| 205 switch (audio_config.codec.audio) { | |
| 206 case transport::kOpus: | |
| 207 impl_ = new OpusImpl(cast_environment, | |
| 208 audio_config.channels, | |
| 209 audio_config.frequency); | |
| 210 break; | |
| 211 case transport::kPcm16: | |
| 212 impl_ = new Pcm16Impl(cast_environment, | |
| 213 audio_config.channels, | |
| 214 audio_config.frequency); | |
| 215 break; | |
| 216 default: | |
| 217 NOTREACHED() << "Unknown or unspecified codec."; | |
| 218 break; | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 AudioDecoder::~AudioDecoder() {} | |
| 223 | |
| 224 CastInitializationStatus AudioDecoder::InitializationResult() const { | |
| 225 if (impl_) | |
| 226 return impl_->InitializationResult(); | |
| 227 return STATUS_UNSUPPORTED_AUDIO_CODEC; | |
| 228 } | |
| 229 | |
| 230 void AudioDecoder::DecodeFrame( | |
| 231 scoped_ptr<transport::EncodedFrame> encoded_frame, | |
| 232 const DecodeFrameCallback& callback) { | |
| 233 DCHECK(encoded_frame.get()); | |
| 234 DCHECK(!callback.is_null()); | |
| 235 if (!impl_ || impl_->InitializationResult() != STATUS_AUDIO_INITIALIZED) { | |
| 236 callback.Run(make_scoped_ptr<AudioBus>(NULL), false); | |
| 237 return; | |
| 238 } | |
| 239 cast_environment_->PostTask(CastEnvironment::AUDIO, | |
| 240 FROM_HERE, | |
| 241 base::Bind(&AudioDecoder::ImplBase::DecodeFrame, | |
| 242 impl_, | |
| 243 base::Passed(&encoded_frame), | |
| 244 callback)); | |
| 245 } | |
| 246 | |
| 247 } // namespace cast | |
| 248 } // namespace media | |
| OLD | NEW |