| Index: media/audio/virtual_audio_input_stream.cc
|
| diff --git a/media/audio/virtual_audio_input_stream.cc b/media/audio/virtual_audio_input_stream.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..fe4e15b5c7b13f33dd93f0b468e513b97a1ced93
|
| --- /dev/null
|
| +++ b/media/audio/virtual_audio_input_stream.cc
|
| @@ -0,0 +1,192 @@
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "media/audio/virtual_audio_input_stream.h"
|
| +
|
| +#include <algorithm>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/message_loop.h"
|
| +#include "media/audio/virtual_audio_output_stream.h"
|
| +
|
| +namespace media {
|
| +
|
| +class MEDIA_EXPORT LoopbackAudioConverter
|
| + : public AudioConverter,
|
| + public AudioConverter::InputCallback {
|
| + public:
|
| + LoopbackAudioConverter(const AudioParameters& input_params,
|
| + const AudioParameters& output_params);
|
| + virtual ~LoopbackAudioConverter() {}
|
| +
|
| + private:
|
| + virtual double ProvideInput(
|
| + AudioBus* audio_bus, base::TimeDelta buffer_delay) OVERRIDE;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(LoopbackAudioConverter);
|
| +};
|
| +
|
| +AudioInputStream* VirtualAudioInputStream::MakeStream(
|
| + AudioManagerBase* manager, const AudioParameters& params) {
|
| + return new VirtualAudioInputStream(manager, params);
|
| +}
|
| +
|
| +VirtualAudioInputStream::VirtualAudioInputStream(AudioManagerBase* manager,
|
| + const AudioParameters& params)
|
| + : audio_manager_(manager),
|
| + callback_(NULL),
|
| + buffer_size_(params.GetBytesPerBuffer()),
|
| + buffer_(new uint8[buffer_size_]),
|
| + params_(params),
|
| + audio_bus_(AudioBus::Create(params_)),
|
| + mixer_(params_, params_, false) {
|
| +}
|
| +
|
| +VirtualAudioInputStream::~VirtualAudioInputStream() {
|
| + for (AudioTransformsMap::iterator it = transforms_.begin();
|
| + it != transforms_.end(); ++it) {
|
| + delete it->second;
|
| + }
|
| +}
|
| +
|
| +bool VirtualAudioInputStream::Open() {
|
| + memset(buffer_.get(), 0, buffer_size_);
|
| + return true;
|
| +}
|
| +
|
| +void VirtualAudioInputStream::Start(AudioInputCallback* callback) {
|
| + callback_ = callback;
|
| + on_more_data_cb_.Reset(base::Bind(
|
| + &VirtualAudioInputStream::DoCallback, base::Unretained(this)));
|
| + audio_manager_->GetMessageLoop()->PostTask(
|
| + FROM_HERE, on_more_data_cb_.callback());
|
| + // TODO(justinlin): AudioRendererHost()::StartDiverting();
|
| +}
|
| +
|
| +// TODO(justinlin): This will go away in favor of a better injection method.
|
| +void VirtualAudioInputStream::UpdateResamplersIfNecessary() {
|
| + const AudioManagerBase::AudioOutputStreamList& streams =
|
| + audio_manager_->GetVirtualAudioOutputStreams();
|
| +
|
| + // Check if anything in the output stream list was added.
|
| + std::set<AudioOutputStream*> new_streams;
|
| + std::set_difference(streams.begin(), streams.end(),
|
| + registered_streams_.begin(), registered_streams_.end(),
|
| + std::inserter(new_streams, new_streams.begin()));
|
| +
|
| + for (AudioManagerBase::AudioOutputStreamList::iterator it =
|
| + new_streams.begin(); it != new_streams.end(); ++it) {
|
| + registered_streams_.insert(*it);
|
| +
|
| + VirtualAudioOutputStream* virtual_output_stream =
|
| + static_cast<VirtualAudioOutputStream*>(*it);
|
| + const AudioParameters& virtual_output_stream_params =
|
| + virtual_output_stream->params();
|
| +
|
| + registered_streams_params_.insert(
|
| + std::make_pair(*it, virtual_output_stream_params));
|
| +
|
| + LoopbackAudioConverter* transform =
|
| + new LoopbackAudioConverter(virtual_output_stream_params, params_);
|
| + std::pair<AudioTransformsMap::iterator, bool> result =
|
| + transforms_.insert(std::make_pair(
|
| + virtual_output_stream_params, transform));
|
| +
|
| + // Add to mixer if we just created a new AudioTransform.
|
| + if (result.second) {
|
| + mixer_.AddInput(result.first->second);
|
| + } else {
|
| + delete transform;
|
| + transform = result.first->second;
|
| + }
|
| +
|
| + transform->AddInput(virtual_output_stream);
|
| + }
|
| +
|
| + // Remove any audio output streams that are now gone.
|
| + std::set<AudioOutputStream*> removed_streams;
|
| + std::set_difference(registered_streams_.begin(), registered_streams_.end(),
|
| + streams.begin(), streams.end(),
|
| + std::inserter(removed_streams, removed_streams.begin()));
|
| +
|
| + for (AudioManagerBase::AudioOutputStreamList::iterator it =
|
| + removed_streams.begin(); it != removed_streams.end(); ++it) {
|
| + registered_streams_.erase(*it);
|
| +
|
| + VirtualAudioOutputStream* virtual_output_stream =
|
| + static_cast<VirtualAudioOutputStream*>(*it);
|
| + const AudioParameters& virtual_output_stream_params =
|
| + registered_streams_params_[*it];
|
| + DCHECK(transforms_.find(virtual_output_stream_params) != transforms_.end());
|
| + transforms_[virtual_output_stream_params]->RemoveInput(
|
| + virtual_output_stream);
|
| +
|
| + registered_streams_params_.erase(*it);
|
| + }
|
| +}
|
| +
|
| +void VirtualAudioInputStream::DoCallback() {
|
| + DCHECK(callback_);
|
| + DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread());
|
| +
|
| + UpdateResamplersIfNecessary();
|
| +
|
| + int frames_received = params_.frames_per_buffer();
|
| + float frames_per_millisecond = params_.sample_rate() / static_cast<float>(
|
| + base::Time::kMillisecondsPerSecond);
|
| +
|
| + mixer_.Convert(audio_bus_.get());
|
| + audio_bus_->ToInterleaved(params_.frames_per_buffer(),
|
| + params_.bits_per_sample() / 8,
|
| + buffer_.get());
|
| +
|
| + callback_->OnData(this, buffer_.get(), buffer_size_, buffer_size_, 1.0);
|
| +
|
| + MessageLoop::current()->PostDelayedTask(
|
| + FROM_HERE, on_more_data_cb_.callback(),
|
| + base::TimeDelta::FromMilliseconds(
|
| + frames_received / frames_per_millisecond));
|
| +}
|
| +
|
| +void VirtualAudioInputStream::Stop() {
|
| + on_more_data_cb_.Cancel();
|
| + // TODO(justinlin): AudioRendererHost()::StopDiverting()
|
| +}
|
| +
|
| +void VirtualAudioInputStream::Close() {
|
| + if (callback_) {
|
| + callback_->OnClose(this);
|
| + callback_ = NULL;
|
| + }
|
| + audio_manager_->ReleaseInputStream(this);
|
| +}
|
| +
|
| +double VirtualAudioInputStream::GetMaxVolume() {
|
| + return 1.0;
|
| +}
|
| +
|
| +void VirtualAudioInputStream::SetVolume(double volume) {}
|
| +
|
| +double VirtualAudioInputStream::GetVolume() {
|
| + return 1.0;
|
| +}
|
| +
|
| +void VirtualAudioInputStream::SetAutomaticGainControl(bool enabled) {}
|
| +
|
| +bool VirtualAudioInputStream::GetAutomaticGainControl() {
|
| + return false;
|
| +}
|
| +
|
| +LoopbackAudioConverter::LoopbackAudioConverter(
|
| + const AudioParameters& input_params, const AudioParameters& output_params)
|
| + : AudioConverter(input_params, output_params, false) {
|
| +}
|
| +
|
| +double LoopbackAudioConverter::ProvideInput(
|
| + AudioBus* audio_bus, base::TimeDelta buffer_delay) {
|
| + Convert(audio_bus);
|
| + return 1.0;
|
| +}
|
| +
|
| +} // namespace media
|
|
|