12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/virtual_audio_input_stream.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <utility> 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/single_thread_task_runner.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/virtual_audio_output_stream.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace media { 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// LoopbackAudioConverter works similar to AudioConverter and converts input 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// streams to different audio parameters. Then, the LoopbackAudioConverter can 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// be used as an input to another AudioConverter. This allows us to 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// use converted audio from AudioOutputStreams as input to an AudioConverter. 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// For example, this allows converting multiple streams into a common format and 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// using the converted audio as input to another AudioConverter (i.e. a mixer). 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class LoopbackAudioConverter : public AudioConverter::InputCallback { 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LoopbackAudioConverter(const AudioParameters& input_params, 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const AudioParameters& output_params) 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : audio_converter_(input_params, output_params, false) {} 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~LoopbackAudioConverter() {} 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void AddInput(AudioConverter::InputCallback* input) { 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) audio_converter_.AddInput(input); 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void RemoveInput(AudioConverter::InputCallback* input) { 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) audio_converter_.RemoveInput(input); 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual double ProvideInput(AudioBus* audio_bus, 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TimeDelta buffer_delay) OVERRIDE { 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) audio_converter_.Convert(audio_bus); 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 1.0; 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AudioConverter audio_converter_; 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(LoopbackAudioConverter); 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)VirtualAudioInputStream::VirtualAudioInputStream( 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const AudioParameters& params, 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner, 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const AfterCloseCallback& after_close_cb) 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : worker_task_runner_(worker_task_runner), 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) after_close_cb_(after_close_cb), 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_(NULL), 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) buffer_(new uint8[params.GetBytesPerBuffer()]), 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) params_(params), 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mixer_(params_, params_, false), 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) num_attached_output_streams_(0), 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) fake_consumer_(worker_task_runner_, params_) { 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(params_.IsValid()); 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(worker_task_runner_.get()); 64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // VAIS can be constructed on any thread, but will DCHECK that all 66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // AudioInputStream methods are called from the same thread. 67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch thread_checker_.DetachFromThread(); 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)VirtualAudioInputStream::~VirtualAudioInputStream() { 71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(!callback_); 72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Sanity-check: Contract for Add/RemoveOutputStream() requires that all 74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // output streams be removed before VirtualAudioInputStream is destroyed. 75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK_EQ(0, num_attached_output_streams_); 76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (AudioConvertersMap::iterator it = converters_.begin(); 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) it != converters_.end(); ++it) { 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete it->second; 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool VirtualAudioInputStream::Open() { 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(thread_checker_.CalledOnValidThread()); 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) memset(buffer_.get(), 0, params_.GetBytesPerBuffer()); 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VirtualAudioInputStream::Start(AudioInputCallback* callback) { 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(thread_checker_.CalledOnValidThread()); 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) callback_ = callback; 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) fake_consumer_.Start(base::Bind( 93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch &VirtualAudioInputStream::PumpAudio, base::Unretained(this))); 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VirtualAudioInputStream::Stop() { 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(thread_checker_.CalledOnValidThread()); 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) fake_consumer_.Stop(); 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback_ = NULL; 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VirtualAudioInputStream::AddOutputStream( 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) VirtualAudioOutputStream* stream, const AudioParameters& output_params) { 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(thread_checker_.CalledOnValidThread()); 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::AutoLock scoped_lock(converter_network_lock_); 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AudioConvertersMap::iterator converter = converters_.find(output_params); 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (converter == converters_.end()) { 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::pair<AudioConvertersMap::iterator, bool> result = converters_.insert( 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::make_pair(output_params, 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new LoopbackAudioConverter(output_params, params_))); 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) converter = result.first; 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Add to main mixer if we just added a new AudioTransform. 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) mixer_.AddInput(converter->second); 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) converter->second->AddInput(stream); 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++num_attached_output_streams_; 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VirtualAudioInputStream::RemoveOutputStream( 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) VirtualAudioOutputStream* stream, const AudioParameters& output_params) { 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(thread_checker_.CalledOnValidThread()); 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::AutoLock scoped_lock(converter_network_lock_); 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(converters_.find(output_params) != converters_.end()); 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) converters_[output_params]->RemoveInput(stream); 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) --num_attached_output_streams_; 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_LE(0, num_attached_output_streams_); 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid VirtualAudioInputStream::PumpAudio(AudioBus* audio_bus) { 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(worker_task_runner_->BelongsToCurrentThread()); 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch { 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::AutoLock scoped_lock(converter_network_lock_); 140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch mixer_.Convert(audio_bus); 141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 1426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) callback_->OnData(this, audio_bus, params_.GetBytesPerBuffer(), 1.0); 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VirtualAudioInputStream::Close() { 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(thread_checker_.CalledOnValidThread()); 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Stop(); // Make sure callback_ is no longer being used. 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If a non-null AfterCloseCallback was provided to the constructor, invoke it 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // here. The callback is moved to a stack-local first since |this| could be 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // destroyed during Run(). 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!after_close_cb_.is_null()) { 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const AfterCloseCallback cb = after_close_cb_; 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) after_close_cb_.Reset(); 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cb.Run(this); 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)double VirtualAudioInputStream::GetMaxVolume() { 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 1.0; 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VirtualAudioInputStream::SetVolume(double volume) {} 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)double VirtualAudioInputStream::GetVolume() { 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 1.0; 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VirtualAudioInputStream::SetAutomaticGainControl(bool enabled) {} 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool VirtualAudioInputStream::GetAutomaticGainControl() { 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 176ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdochbool VirtualAudioInputStream::IsMuted() { 177ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch return false; 178ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch} 179ab8f6f0bd665d3c1ff476eb06c58c42630e462d4Ben Murdoch 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace media 181