Index: content/renderer/audio_input_device.cc |
=================================================================== |
--- content/renderer/audio_input_device.cc (revision 88131) |
+++ content/renderer/audio_input_device.cc (working copy) |
@@ -1,241 +0,0 @@ |
-// Copyright (c) 2011 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/audio_input_device.h" |
- |
-#include "base/memory/singleton.h" |
-#include "base/message_loop.h" |
-#include "content/common/audio_messages.h" |
-#include "content/common/child_process.h" |
-#include "content/common/view_messages.h" |
-#include "content/renderer/render_thread.h" |
-#include "media/audio/audio_util.h" |
- |
-scoped_refptr<AudioInputMessageFilter> AudioInputDevice::filter_; |
- |
-namespace { |
- |
-// AudioMessageFilterCreator is intended to be used as a singleton so we can |
-// get access to a shared AudioInputMessageFilter. |
-// Example usage: |
-// AudioInputMessageFilter* filter = |
-// AudioInputMessageFilterCreator::SharedFilter(); |
- |
-class AudioInputMessageFilterCreator { |
- public: |
- AudioInputMessageFilterCreator() { |
- int routing_id; |
- RenderThread::current()->Send( |
- new ViewHostMsg_GenerateRoutingID(&routing_id)); |
- filter_ = new AudioInputMessageFilter(routing_id); |
- RenderThread::current()->AddFilter(filter_); |
- } |
- |
- static AudioInputMessageFilter* SharedFilter() { |
- return GetInstance()->filter_.get(); |
- } |
- |
- static AudioInputMessageFilterCreator* GetInstance() { |
- return Singleton<AudioInputMessageFilterCreator>::get(); |
- } |
- |
- private: |
- scoped_refptr<AudioInputMessageFilter> filter_; |
-}; |
- |
-} // namespace |
- |
-AudioInputDevice::AudioInputDevice(size_t buffer_size, |
- int channels, |
- double sample_rate, |
- CaptureCallback* callback) |
- : buffer_size_(buffer_size), |
- channels_(channels), |
- bits_per_sample_(16), |
- sample_rate_(sample_rate), |
- callback_(callback), |
- audio_delay_milliseconds_(0), |
- volume_(1.0), |
- stream_id_(0) { |
- audio_data_.reserve(channels); |
- for (int i = 0; i < channels; ++i) { |
- float* channel_data = new float[buffer_size]; |
- audio_data_.push_back(channel_data); |
- } |
- // Lazily create the message filter and share across AudioInputDevice |
- // instances. |
- filter_ = AudioInputMessageFilterCreator::SharedFilter(); |
-} |
- |
-AudioInputDevice::~AudioInputDevice() { |
- // Make sure we have been shut down. |
- DCHECK_EQ(0, stream_id_); |
- Stop(); |
- for (int i = 0; i < channels_; ++i) |
- delete [] audio_data_[i]; |
-} |
- |
-bool AudioInputDevice::Start() { |
- // Make sure we don't call Start() more than once. |
- DCHECK_EQ(0, stream_id_); |
- if (stream_id_) |
- return false; |
- |
- AudioParameters params; |
- // TODO(henrika): add support for low-latency mode? |
- params.format = AudioParameters::AUDIO_PCM_LINEAR; |
- params.channels = channels_; |
- params.sample_rate = static_cast<int>(sample_rate_); |
- params.bits_per_sample = bits_per_sample_; |
- params.samples_per_packet = buffer_size_; |
- |
- // Ensure that the initialization task is posted on the I/O thread by |
- // accessing the I/O message loop directly. This approach avoids a race |
- // condition which could exist if the message loop of the filter was |
- // used instead. |
- DCHECK(ChildProcess::current()) << "Must be in the renderer"; |
- MessageLoop* message_loop = ChildProcess::current()->io_message_loop(); |
- if (!message_loop) |
- return false; |
- |
- message_loop->PostTask(FROM_HERE, |
- NewRunnableMethod(this, &AudioInputDevice::InitializeOnIOThread, params)); |
- |
- return true; |
-} |
- |
-bool AudioInputDevice::Stop() { |
- if (!stream_id_) |
- return false; |
- |
- filter_->message_loop()->PostTask(FROM_HERE, |
- NewRunnableMethod(this, &AudioInputDevice::ShutDownOnIOThread)); |
- |
- if (audio_thread_.get()) { |
- socket_->Close(); |
- audio_thread_->Join(); |
- } |
- |
- return true; |
-} |
- |
-bool AudioInputDevice::SetVolume(double volume) { |
- NOTIMPLEMENTED(); |
- return false; |
-} |
- |
-bool AudioInputDevice::GetVolume(double* volume) { |
- NOTIMPLEMENTED(); |
- return false; |
-} |
- |
-void AudioInputDevice::InitializeOnIOThread(const AudioParameters& params) { |
- stream_id_ = filter_->AddDelegate(this); |
- filter_->Send( |
- new AudioInputHostMsg_CreateStream(0, stream_id_, params, true)); |
-} |
- |
-void AudioInputDevice::StartOnIOThread() { |
- if (stream_id_) |
- filter_->Send(new AudioInputHostMsg_RecordStream(0, stream_id_)); |
-} |
- |
-void AudioInputDevice::ShutDownOnIOThread() { |
- // Make sure we don't call shutdown more than once. |
- if (!stream_id_) |
- return; |
- |
- filter_->Send(new AudioInputHostMsg_CloseStream(0, stream_id_)); |
- filter_->RemoveDelegate(stream_id_); |
- stream_id_ = 0; |
-} |
- |
-void AudioInputDevice::SetVolumeOnIOThread(double volume) { |
- if (stream_id_) |
- filter_->Send(new AudioInputHostMsg_SetVolume(0, stream_id_, volume)); |
-} |
- |
-void AudioInputDevice::OnLowLatencyCreated( |
- base::SharedMemoryHandle handle, |
- base::SyncSocket::Handle socket_handle, |
- uint32 length) { |
-#if defined(OS_WIN) |
- DCHECK(handle); |
- DCHECK(socket_handle); |
-#else |
- DCHECK_GE(handle.fd, 0); |
- DCHECK_GE(socket_handle, 0); |
-#endif |
- DCHECK(length); |
- |
- // TODO(henrika) : check that length is big enough for buffer_size_ |
- |
- shared_memory_.reset(new base::SharedMemory(handle, false)); |
- shared_memory_->Map(length); |
- |
- socket_.reset(new base::SyncSocket(socket_handle)); |
- |
- // TODO(henrika): we could optionally set the thread to high-priority |
- audio_thread_.reset( |
- new base::DelegateSimpleThread(this, "renderer_audio_input_thread")); |
- audio_thread_->Start(); |
- |
- if (filter_) { |
- filter_->message_loop()->PostTask(FROM_HERE, |
- NewRunnableMethod(this, &AudioInputDevice::StartOnIOThread)); |
- } |
-} |
- |
-void AudioInputDevice::OnVolume(double volume) { |
- NOTIMPLEMENTED(); |
-} |
- |
-// Our audio thread runs here. We receive captured audio samples on |
-// this thread. |
-void AudioInputDevice::Run() { |
- int pending_data; |
- const int samples_per_ms = static_cast<int>(sample_rate_) / 1000; |
- const int bytes_per_ms = channels_ * (bits_per_sample_ / 8) * samples_per_ms; |
- |
- while (sizeof(pending_data) == socket_->Receive(&pending_data, |
- sizeof(pending_data)) && |
- pending_data >= 0) { |
- // TODO(henrika): investigate the provided |pending_data| value |
- // and ensure that it is actually an accurate delay estimation. |
- |
- // Convert the number of pending bytes in the capture buffer |
- // into milliseconds. |
- audio_delay_milliseconds_ = pending_data / bytes_per_ms; |
- |
- FireCaptureCallback(); |
- } |
-} |
- |
-void AudioInputDevice::FireCaptureCallback() { |
- if (!callback_) |
- return; |
- |
- const size_t number_of_frames = buffer_size_; |
- |
- // Read 16-bit samples from shared memory (browser writes to it). |
- int16* input_audio = static_cast<int16*>(shared_memory_data()); |
- const int bytes_per_sample = sizeof(input_audio[0]); |
- |
- // Deinterleave each channel and convert to 32-bit floating-point |
- // with nominal range -1.0 -> +1.0. |
- for (int channel_index = 0; channel_index < channels_; ++channel_index) { |
- media::DeinterleaveAudioChannel(input_audio, |
- audio_data_[channel_index], |
- channels_, |
- channel_index, |
- bytes_per_sample, |
- number_of_frames); |
- } |
- |
- // Deliver captured data to the client in floating point format |
- // and update the audio-delay measurement. |
- callback_->Capture(audio_data_, |
- number_of_frames, |
- audio_delay_milliseconds_); |
-} |