virtual_audio_input_stream.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/message_loop.h" 12#include "base/message_loop_proxy.h" 13#include "media/audio/virtual_audio_output_stream.h" 14 15namespace media { 16 17// LoopbackAudioConverter works similar to AudioConverter and converts input 18// streams to different audio parameters. Then, the LoopbackAudioConverter can 19// be used as an input to another AudioConverter. This allows us to 20// use converted audio from AudioOutputStreams as input to an AudioConverter. 21// For example, this allows converting multiple streams into a common format and 22// using the converted audio as input to another AudioConverter (i.e. a mixer). 23class LoopbackAudioConverter : public AudioConverter::InputCallback { 24 public: 25 LoopbackAudioConverter(const AudioParameters& input_params, 26 const AudioParameters& output_params) 27 : audio_converter_(input_params, output_params, false) {} 28 29 virtual ~LoopbackAudioConverter() {} 30 31 void AddInput(AudioConverter::InputCallback* input) { 32 audio_converter_.AddInput(input); 33 } 34 35 void RemoveInput(AudioConverter::InputCallback* input) { 36 audio_converter_.RemoveInput(input); 37 } 38 39 private: 40 virtual double ProvideInput(AudioBus* audio_bus, 41 base::TimeDelta buffer_delay) OVERRIDE { 42 audio_converter_.Convert(audio_bus); 43 return 1.0; 44 } 45 46 AudioConverter audio_converter_; 47 48 DISALLOW_COPY_AND_ASSIGN(LoopbackAudioConverter); 49}; 50 51VirtualAudioInputStream::VirtualAudioInputStream( 52 const AudioParameters& params, base::MessageLoopProxy* message_loop, 53 const AfterCloseCallback& after_close_cb) 54 : message_loop_(message_loop), 55 after_close_cb_(after_close_cb), 56 callback_(NULL), 57 buffer_duration_(base::TimeDelta::FromMicroseconds( 58 params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond / 59 static_cast<float>(params.sample_rate()))), 60 buffer_(new uint8[params.GetBytesPerBuffer()]), 61 params_(params), 62 audio_bus_(AudioBus::Create(params_)), 63 mixer_(params_, params_, false), 64 num_attached_output_streams_(0) { 65 DCHECK(params_.IsValid()); 66 DCHECK(message_loop_); 67} 68 69VirtualAudioInputStream::~VirtualAudioInputStream() { 70 for (AudioConvertersMap::iterator it = converters_.begin(); 71 it != converters_.end(); ++it) 72 delete it->second; 73 74 DCHECK_EQ(0, num_attached_output_streams_); 75} 76 77bool VirtualAudioInputStream::Open() { 78 DCHECK(message_loop_->BelongsToCurrentThread()); 79 memset(buffer_.get(), 0, params_.GetBytesPerBuffer()); 80 return true; 81} 82 83void VirtualAudioInputStream::Start(AudioInputCallback* callback) { 84 DCHECK(message_loop_->BelongsToCurrentThread()); 85 callback_ = callback; 86 next_read_time_ = base::Time::Now(); 87 on_more_data_cb_.Reset(base::Bind(&VirtualAudioInputStream::ReadAudio, 88 base::Unretained(this))); 89 message_loop_->PostTask(FROM_HERE, on_more_data_cb_.callback()); 90} 91 92void VirtualAudioInputStream::Stop() { 93 DCHECK(message_loop_->BelongsToCurrentThread()); 94 on_more_data_cb_.Cancel(); 95} 96 97void VirtualAudioInputStream::AddOutputStream( 98 VirtualAudioOutputStream* stream, const AudioParameters& output_params) { 99 DCHECK(message_loop_->BelongsToCurrentThread()); 100 101 AudioConvertersMap::iterator converter = converters_.find(output_params); 102 if (converter == converters_.end()) { 103 std::pair<AudioConvertersMap::iterator, bool> result = converters_.insert( 104 std::make_pair(output_params, 105 new LoopbackAudioConverter(output_params, params_))); 106 converter = result.first; 107 108 // Add to main mixer if we just added a new AudioTransform. 109 mixer_.AddInput(converter->second); 110 } 111 converter->second->AddInput(stream); 112 ++num_attached_output_streams_; 113} 114 115void VirtualAudioInputStream::RemoveOutputStream( 116 VirtualAudioOutputStream* stream, const AudioParameters& output_params) { 117 DCHECK(message_loop_->BelongsToCurrentThread()); 118 119 DCHECK(converters_.find(output_params) != converters_.end()); 120 converters_[output_params]->RemoveInput(stream); 121 122 --num_attached_output_streams_; 123 DCHECK_LE(0, num_attached_output_streams_); 124} 125 126void VirtualAudioInputStream::ReadAudio() { 127 DCHECK(message_loop_->BelongsToCurrentThread()); 128 DCHECK(callback_); 129 130 mixer_.Convert(audio_bus_.get()); 131 audio_bus_->ToInterleaved(params_.frames_per_buffer(), 132 params_.bits_per_sample() / 8, 133 buffer_.get()); 134 135 callback_->OnData(this, 136 buffer_.get(), 137 params_.GetBytesPerBuffer(), 138 params_.GetBytesPerBuffer(), 139 1.0); 140 141 // Need to account for time spent here due to renderer side mixing as well as 142 // the imprecision of PostDelayedTask. 143 next_read_time_ += buffer_duration_; 144 base::Time now = base::Time::Now(); 145 base::TimeDelta delay = next_read_time_ - now; 146 if (delay < base::TimeDelta()) { 147 // Reset the next read time if we end up getting too far behind. We'll just 148 // slow down playback to avoid using up all the CPU. 149 delay = buffer_duration_; 150 next_read_time_ = now + buffer_duration_; 151 } 152 153 message_loop_->PostDelayedTask(FROM_HERE, 154 on_more_data_cb_.callback(), 155 delay); 156} 157 158void VirtualAudioInputStream::Close() { 159 DCHECK(message_loop_->BelongsToCurrentThread()); 160 161 if (callback_) { 162 DCHECK(on_more_data_cb_.IsCancelled()); 163 callback_->OnClose(this); 164 callback_ = NULL; 165 } 166 167 // If a non-null AfterCloseCallback was provided to the constructor, invoke it 168 // here. The callback is moved to a stack-local first since |this| could be 169 // destroyed during Run(). 170 if (!after_close_cb_.is_null()) { 171 const AfterCloseCallback cb = after_close_cb_; 172 after_close_cb_.Reset(); 173 cb.Run(this); 174 } 175} 176 177double VirtualAudioInputStream::GetMaxVolume() { 178 return 1.0; 179} 180 181void VirtualAudioInputStream::SetVolume(double volume) {} 182 183double VirtualAudioInputStream::GetVolume() { 184 return 1.0; 185} 186 187void VirtualAudioInputStream::SetAutomaticGainControl(bool enabled) {} 188 189bool VirtualAudioInputStream::GetAutomaticGainControl() { 190 return false; 191} 192 193} // namespace media 194