Home | History | Annotate | Download | only in receiver
      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.
      4 
      5 #include "media/cast/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            Codec 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<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 Codec 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                  CODEC_AUDIO_OPUS,
    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                  CODEC_AUDIO_PCM16,
    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     int channels,
    204     int sampling_rate,
    205     Codec codec)
    206     : cast_environment_(cast_environment) {
    207   switch (codec) {
    208     case CODEC_AUDIO_OPUS:
    209       impl_ = new OpusImpl(cast_environment, channels, sampling_rate);
    210       break;
    211     case CODEC_AUDIO_PCM16:
    212       impl_ = new Pcm16Impl(cast_environment, channels, sampling_rate);
    213       break;
    214     default:
    215       NOTREACHED() << "Unknown or unspecified codec.";
    216       break;
    217   }
    218 }
    219 
    220 AudioDecoder::~AudioDecoder() {}
    221 
    222 CastInitializationStatus AudioDecoder::InitializationResult() const {
    223   if (impl_.get())
    224     return impl_->InitializationResult();
    225   return STATUS_UNSUPPORTED_AUDIO_CODEC;
    226 }
    227 
    228 void AudioDecoder::DecodeFrame(
    229     scoped_ptr<EncodedFrame> encoded_frame,
    230     const DecodeFrameCallback& callback) {
    231   DCHECK(encoded_frame.get());
    232   DCHECK(!callback.is_null());
    233   if (!impl_.get() ||
    234       impl_->InitializationResult() != STATUS_AUDIO_INITIALIZED) {
    235     callback.Run(make_scoped_ptr<AudioBus>(NULL), false);
    236     return;
    237   }
    238   cast_environment_->PostTask(CastEnvironment::AUDIO,
    239                               FROM_HERE,
    240                               base::Bind(&AudioDecoder::ImplBase::DecodeFrame,
    241                                          impl_,
    242                                          base::Passed(&encoded_frame),
    243                                          callback));
    244 }
    245 
    246 }  // namespace cast
    247 }  // namespace media
    248