Home | History | Annotate | Download | only in audio
      1 // Copyright (c) 2012 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/audio/virtual_audio_input_stream.h"
      6 
      7 #include <algorithm>
      8 #include <utility>
      9 
     10 #include "base/bind.h"
     11 #include "base/single_thread_task_runner.h"
     12 #include "media/audio/virtual_audio_output_stream.h"
     13 
     14 namespace media {
     15 
     16 // LoopbackAudioConverter works similar to AudioConverter and converts input
     17 // streams to different audio parameters. Then, the LoopbackAudioConverter can
     18 // be used as an input to another AudioConverter. This allows us to
     19 // use converted audio from AudioOutputStreams as input to an AudioConverter.
     20 // For example, this allows converting multiple streams into a common format and
     21 // using the converted audio as input to another AudioConverter (i.e. a mixer).
     22 class LoopbackAudioConverter : public AudioConverter::InputCallback {
     23  public:
     24   LoopbackAudioConverter(const AudioParameters& input_params,
     25                          const AudioParameters& output_params)
     26       : audio_converter_(input_params, output_params, false) {}
     27 
     28   virtual ~LoopbackAudioConverter() {}
     29 
     30   void AddInput(AudioConverter::InputCallback* input) {
     31     audio_converter_.AddInput(input);
     32   }
     33 
     34   void RemoveInput(AudioConverter::InputCallback* input) {
     35     audio_converter_.RemoveInput(input);
     36   }
     37 
     38  private:
     39   virtual double ProvideInput(AudioBus* audio_bus,
     40                               base::TimeDelta buffer_delay) OVERRIDE {
     41     audio_converter_.Convert(audio_bus);
     42     return 1.0;
     43   }
     44 
     45   AudioConverter audio_converter_;
     46 
     47   DISALLOW_COPY_AND_ASSIGN(LoopbackAudioConverter);
     48 };
     49 
     50 VirtualAudioInputStream::VirtualAudioInputStream(
     51     const AudioParameters& params,
     52     const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
     53     const AfterCloseCallback& after_close_cb)
     54     : worker_task_runner_(worker_task_runner),
     55       after_close_cb_(after_close_cb),
     56       callback_(NULL),
     57       buffer_(new uint8[params.GetBytesPerBuffer()]),
     58       params_(params),
     59       mixer_(params_, params_, false),
     60       num_attached_output_streams_(0),
     61       fake_consumer_(worker_task_runner_, params_) {
     62   DCHECK(params_.IsValid());
     63   DCHECK(worker_task_runner_.get());
     64 
     65   // VAIS can be constructed on any thread, but will DCHECK that all
     66   // AudioInputStream methods are called from the same thread.
     67   thread_checker_.DetachFromThread();
     68 }
     69 
     70 VirtualAudioInputStream::~VirtualAudioInputStream() {
     71   DCHECK(!callback_);
     72 
     73   // Sanity-check: Contract for Add/RemoveOutputStream() requires that all
     74   // output streams be removed before VirtualAudioInputStream is destroyed.
     75   DCHECK_EQ(0, num_attached_output_streams_);
     76 
     77   for (AudioConvertersMap::iterator it = converters_.begin();
     78        it != converters_.end(); ++it) {
     79     delete it->second;
     80   }
     81 }
     82 
     83 bool VirtualAudioInputStream::Open() {
     84   DCHECK(thread_checker_.CalledOnValidThread());
     85   memset(buffer_.get(), 0, params_.GetBytesPerBuffer());
     86   return true;
     87 }
     88 
     89 void VirtualAudioInputStream::Start(AudioInputCallback* callback) {
     90   DCHECK(thread_checker_.CalledOnValidThread());
     91   callback_ = callback;
     92   fake_consumer_.Start(base::Bind(
     93       &VirtualAudioInputStream::PumpAudio, base::Unretained(this)));
     94 }
     95 
     96 void VirtualAudioInputStream::Stop() {
     97   DCHECK(thread_checker_.CalledOnValidThread());
     98   fake_consumer_.Stop();
     99   callback_ = NULL;
    100 }
    101 
    102 void VirtualAudioInputStream::AddOutputStream(
    103     VirtualAudioOutputStream* stream, const AudioParameters& output_params) {
    104   DCHECK(thread_checker_.CalledOnValidThread());
    105 
    106   base::AutoLock scoped_lock(converter_network_lock_);
    107 
    108   AudioConvertersMap::iterator converter = converters_.find(output_params);
    109   if (converter == converters_.end()) {
    110     std::pair<AudioConvertersMap::iterator, bool> result = converters_.insert(
    111         std::make_pair(output_params,
    112                        new LoopbackAudioConverter(output_params, params_)));
    113     converter = result.first;
    114 
    115     // Add to main mixer if we just added a new AudioTransform.
    116     mixer_.AddInput(converter->second);
    117   }
    118   converter->second->AddInput(stream);
    119   ++num_attached_output_streams_;
    120 }
    121 
    122 void VirtualAudioInputStream::RemoveOutputStream(
    123     VirtualAudioOutputStream* stream, const AudioParameters& output_params) {
    124   DCHECK(thread_checker_.CalledOnValidThread());
    125 
    126   base::AutoLock scoped_lock(converter_network_lock_);
    127 
    128   DCHECK(converters_.find(output_params) != converters_.end());
    129   converters_[output_params]->RemoveInput(stream);
    130 
    131   --num_attached_output_streams_;
    132   DCHECK_LE(0, num_attached_output_streams_);
    133 }
    134 
    135 void VirtualAudioInputStream::PumpAudio(AudioBus* audio_bus) {
    136   DCHECK(worker_task_runner_->BelongsToCurrentThread());
    137 
    138   {
    139     base::AutoLock scoped_lock(converter_network_lock_);
    140     mixer_.Convert(audio_bus);
    141   }
    142   callback_->OnData(this, audio_bus, params_.GetBytesPerBuffer(), 1.0);
    143 }
    144 
    145 void VirtualAudioInputStream::Close() {
    146   DCHECK(thread_checker_.CalledOnValidThread());
    147 
    148   Stop();  // Make sure callback_ is no longer being used.
    149 
    150   // If a non-null AfterCloseCallback was provided to the constructor, invoke it
    151   // here.  The callback is moved to a stack-local first since |this| could be
    152   // destroyed during Run().
    153   if (!after_close_cb_.is_null()) {
    154     const AfterCloseCallback cb = after_close_cb_;
    155     after_close_cb_.Reset();
    156     cb.Run(this);
    157   }
    158 }
    159 
    160 double VirtualAudioInputStream::GetMaxVolume() {
    161   return 1.0;
    162 }
    163 
    164 void VirtualAudioInputStream::SetVolume(double volume) {}
    165 
    166 double VirtualAudioInputStream::GetVolume() {
    167   return 1.0;
    168 }
    169 
    170 void VirtualAudioInputStream::SetAutomaticGainControl(bool enabled) {}
    171 
    172 bool VirtualAudioInputStream::GetAutomaticGainControl() {
    173   return false;
    174 }
    175 
    176 bool VirtualAudioInputStream::IsMuted() {
    177   return false;
    178 }
    179 
    180 }  // namespace media
    181