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 14namespace 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). 22class 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 50VirtualAudioInputStream::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 70VirtualAudioInputStream::~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 83bool VirtualAudioInputStream::Open() { 84 DCHECK(thread_checker_.CalledOnValidThread()); 85 memset(buffer_.get(), 0, params_.GetBytesPerBuffer()); 86 return true; 87} 88 89void 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 96void VirtualAudioInputStream::Stop() { 97 DCHECK(thread_checker_.CalledOnValidThread()); 98 fake_consumer_.Stop(); 99 callback_ = NULL; 100} 101 102void 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 122void 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 135void 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 145void 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 160double VirtualAudioInputStream::GetMaxVolume() { 161 return 1.0; 162} 163 164void VirtualAudioInputStream::SetVolume(double volume) {} 165 166double VirtualAudioInputStream::GetVolume() { 167 return 1.0; 168} 169 170void VirtualAudioInputStream::SetAutomaticGainControl(bool enabled) {} 171 172bool VirtualAudioInputStream::GetAutomaticGainControl() { 173 return false; 174} 175 176} // namespace media 177