Chromium Code Reviews| Index: content/renderer/media/webrtc_local_audio_source_provider.cc |
| diff --git a/content/renderer/media/webrtc_local_audio_source_provider.cc b/content/renderer/media/webrtc_local_audio_source_provider.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..37cf12da4d417e9da03f50433a5dc62ea4d4d567 |
| --- /dev/null |
| +++ b/content/renderer/media/webrtc_local_audio_source_provider.cc |
| @@ -0,0 +1,148 @@ |
| +// Copyright 2013 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 "content/renderer/media/webrtc_local_audio_source_provider.h" |
| + |
| +#include "base/logging.h" |
| +#include "content/renderer/render_thread_impl.h" |
| +#include "media/audio/audio_parameters.h" |
| +#include "media/base/audio_fifo.h" |
| +#include "media/base/audio_hardware_config.h" |
| +#include "third_party/WebKit/public/web/WebAudioSourceProviderClient.h" |
| + |
| +using WebKit::WebVector; |
| + |
| +namespace content { |
| + |
| +static const size_t kMaxNumberOfBuffer = 10; |
| +static const size_t kWebAudioRenderBufferSize = 128; |
| + |
| +WebRtcLocalAudioSourceProvider::WebRtcLocalAudioSourceProvider() |
| + : audio_delay_ms_(0), |
| + volume_(1), |
| + key_pressed_(false), |
| + is_enabled_(false), |
| + use_sink_params_for_testing_(false) { |
|
tommi (sloooow) - chröme
2013/09/10 16:00:38
I don't like mixing test code and production code
no longer working on chromium
2013/09/11 10:22:07
How about now?
|
| +} |
| + |
| +WebRtcLocalAudioSourceProvider::~WebRtcLocalAudioSourceProvider() { |
| + if (audio_converter_.get()) |
| + audio_converter_->RemoveInput(this); |
| +} |
| + |
| +void WebRtcLocalAudioSourceProvider::Initialize( |
| + const media::AudioParameters& source_params) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + if (!use_sink_params_for_testing_) { |
| + // Use the native audio output hardware sample-rate for the sink. |
| + media::AudioHardwareConfig* hardware_config = |
| + RenderThreadImpl::current()->GetAudioHardwareConfig(); |
| + int sample_rate = hardware_config->GetOutputSampleRate(); |
| + sink_params_.Reset( |
| + source_params.format(), media::CHANNEL_LAYOUT_STEREO, 2, 0, |
| + sample_rate, source_params.bits_per_sample(), |
| + kWebAudioRenderBufferSize); |
| + } |
| + |
| + base::AutoLock auto_lock(lock_); |
| + source_params_ = source_params; |
| + // Create the audio converter with |disable_fifo| as false so that the |
| + // converter will request source_params.frames_per_buffer() each time. |
| + // This will not increase the complexity as there is only one client to |
| + // the converter. |
| + audio_converter_.reset( |
| + new media::AudioConverter(source_params, sink_params_, false)); |
| + audio_converter_->AddInput(this); |
| + fifo_.reset(new media::AudioFifo( |
| + source_params.channels(), |
| + kMaxNumberOfBuffer * source_params.frames_per_buffer())); |
| +} |
| + |
| +void WebRtcLocalAudioSourceProvider::DeliverData( |
| + media::AudioBus* audio_source, |
| + int audio_delay_milliseconds, |
| + int volume, |
| + bool key_pressed) { |
| + base::AutoLock auto_lock(lock_); |
| + if (!is_enabled_) |
| + return; |
| + |
| + DCHECK(fifo_.get()); |
| + |
| + if (fifo_->frames() + audio_source->frames() <= fifo_->max_frames()) { |
| + fifo_->Push(audio_source); |
| + } else { |
| + // This can happen if the data in FIFO is too slowed to be consumed or |
| + // WebAudio stops consuming data. |
| + DLOG(WARNING) << "Local source provicer FIFO is full" << fifo_->frames(); |
| + } |
| + |
| + // Cache the values for GetAudioProcessingParams(). |
| + last_fill_ = base::TimeTicks::Now(); |
| + audio_delay_ms_ = audio_delay_milliseconds; |
| + volume_ = volume; |
| + key_pressed_ = key_pressed; |
| +} |
| + |
| +void WebRtcLocalAudioSourceProvider::GetAudioProcessingParams( |
| + int* delay_ms, int* volume, bool* key_pressed) { |
| + int elapsed_ms = 0; |
| + if (!last_fill_.is_null()) { |
| + elapsed_ms = static_cast<int>( |
| + (base::TimeTicks::Now() - last_fill_).InMilliseconds()); |
| + } |
| + *delay_ms = audio_delay_ms_ + elapsed_ms + static_cast<int>( |
| + 1000 * fifo_->frames() / source_params_.sample_rate() + 0.5); |
| + *volume = volume_; |
| + *key_pressed = key_pressed_; |
| +} |
| + |
| +void WebRtcLocalAudioSourceProvider::setClient( |
| + WebKit::WebAudioSourceProviderClient* client) { |
| + NOTIMPLEMENTED(); |
| +} |
| + |
| +void WebRtcLocalAudioSourceProvider::provideInput( |
| + const WebVector<float*>& audio_data, size_t number_of_frames) { |
| + DCHECK_EQ(number_of_frames, kWebAudioRenderBufferSize); |
| + if (!bus_wrapper_ || |
| + static_cast<size_t>(bus_wrapper_->channels()) != audio_data.size()) { |
| + bus_wrapper_ = media::AudioBus::CreateWrapper(audio_data.size()); |
| + } |
| + |
| + bus_wrapper_->set_frames(number_of_frames); |
| + for (size_t i = 0; i < audio_data.size(); ++i) |
| + bus_wrapper_->SetChannelData(i, audio_data[i]); |
| + |
| + base::AutoLock auto_lock(lock_); |
| + DCHECK(audio_converter_.get()); |
| + DCHECK(fifo_.get()); |
| + is_enabled_ = true; |
| + audio_converter_->Convert(bus_wrapper_.get()); |
| +} |
| + |
| +double WebRtcLocalAudioSourceProvider::ProvideInput( |
| + media::AudioBus* audio_bus, base::TimeDelta buffer_delay) { |
| + if (fifo_->frames() >= audio_bus->frames()) { |
| + fifo_->Consume(audio_bus, 0, audio_bus->frames()); |
| + } else { |
| + audio_bus->Zero(); |
| + if (!last_fill_.is_null()) { |
| + DLOG(WARNING) << "Underrun, FIFO has data " << fifo_->frames() |
| + << " samples but " << audio_bus->frames() |
| + << " samples are needed"; |
| + } |
| + } |
| + |
| + return 1.0; |
| +} |
| + |
| +void WebRtcLocalAudioSourceProvider::SetSinkParamsForTesting( |
| + const media::AudioParameters& sink_params) { |
| + DCHECK(thread_checker_.CalledOnValidThread()); |
| + sink_params_ = sink_params; |
| + use_sink_params_for_testing_ = true; |
| +} |
| + |
| +} // namespace content |