diff options
author | henrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-24 09:41:12 +0000 |
---|---|---|
committer | henrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-24 09:41:12 +0000 |
commit | f5968e6ada72f515d7d183e67e35f90d7704daee (patch) | |
tree | 28f4fcbe9850f52dc7196c5a1db394b0aa2d577a /content | |
parent | a80a258880e3ababe9f806dd9bb4d60ad90473ae (diff) | |
download | chromium_src-f5968e6ada72f515d7d183e67e35f90d7704daee.zip chromium_src-f5968e6ada72f515d7d183e67e35f90d7704daee.tar.gz chromium_src-f5968e6ada72f515d7d183e67e35f90d7704daee.tar.bz2 |
Low-latency AudioInputStream implementation based on WASAPI for Windows.
Requires Windows Vista or higher.
BUG=none
TEST=Attached unit test (requires undefined CHROME_HEADLESS)
Review URL: http://codereview.chromium.org/8283032
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@106899 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r-- | content/browser/renderer_host/render_message_filter.cc | 6 | ||||
-rw-r--r-- | content/browser/renderer_host/render_message_filter.h | 1 | ||||
-rw-r--r-- | content/common/view_messages.h | 4 | ||||
-rw-r--r-- | content/renderer/media/audio_input_device.cc | 4 | ||||
-rw-r--r-- | content/renderer/media/webrtc_audio_device_impl.cc | 69 |
5 files changed, 60 insertions, 24 deletions
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc index 5f3e5cd..0ee35cd 100644 --- a/content/browser/renderer_host/render_message_filter.cc +++ b/content/browser/renderer_host/render_message_filter.cc @@ -355,6 +355,8 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message, OnCacheableMetadataAvailable) IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_Keygen, OnKeygen) IPC_MESSAGE_HANDLER(ViewHostMsg_AsyncOpenFile, OnAsyncOpenFile) + IPC_MESSAGE_HANDLER(ViewHostMsg_GetHardwareInputSampleRate, + OnGetHardwareInputSampleRate) IPC_MESSAGE_HANDLER(ViewHostMsg_GetHardwareSampleRate, OnGetHardwareSampleRate) IPC_MESSAGE_HANDLER(ViewHostMsg_MediaLogEvent, OnMediaLogEvent) @@ -602,6 +604,10 @@ void RenderMessageFilter::OnGenerateRoutingID(int* route_id) { *route_id = render_widget_helper_->GetNextRoutingID(); } +void RenderMessageFilter::OnGetHardwareInputSampleRate(double* sample_rate) { + *sample_rate = media::GetAudioInputHardwareSampleRate(); +} + void RenderMessageFilter::OnGetHardwareSampleRate(double* sample_rate) { *sample_rate = media::GetAudioHardwareSampleRate(); } diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h index 1fbf322..22b9616 100644 --- a/content/browser/renderer_host/render_message_filter.h +++ b/content/browser/renderer_host/render_message_filter.h @@ -182,6 +182,7 @@ class RenderMessageFilter : public BrowserMessageFilter { void OnCheckNotificationPermission(const GURL& source_url, int* permission_level); + void OnGetHardwareInputSampleRate(double* sample_rate); void OnGetHardwareSampleRate(double* sample_rate); // Used to ask the browser to allocate a block of shared memory for the diff --git a/content/common/view_messages.h b/content/common/view_messages.h index 2e06adc..03fa43c 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h @@ -686,6 +686,10 @@ IPC_MESSAGE_ROUTED1(ViewMsg_SetCSSColors, IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GenerateRoutingID, int /* routing_id */) +// Asks the browser for the default audio input hardware sample-rate. +IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GetHardwareInputSampleRate, + double /* sample_rate */) + // Asks the browser for the default audio hardware sample-rate. IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GetHardwareSampleRate, double /* sample_rate */) diff --git a/content/renderer/media/audio_input_device.cc b/content/renderer/media/audio_input_device.cc index 0dd06b8..ce0da67 100644 --- a/content/renderer/media/audio_input_device.cc +++ b/content/renderer/media/audio_input_device.cc @@ -30,7 +30,11 @@ AudioInputDevice::AudioInputDevice(size_t buffer_size, #if defined(OS_MACOSX) VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X."; audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; +#elif defined(OS_WIN) + VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows."; + audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; #else + // TODO(henrika): add support for AUDIO_PCM_LOW_LATENCY on Linux as well. audio_parameters_.format = AudioParameters::AUDIO_PCM_LINEAR; #endif audio_parameters_.channels = channels; diff --git a/content/renderer/media/webrtc_audio_device_impl.cc b/content/renderer/media/webrtc_audio_device_impl.cc index eb2cef33..cb5728ec 100644 --- a/content/renderer/media/webrtc_audio_device_impl.cc +++ b/content/renderer/media/webrtc_audio_device_impl.cc @@ -6,12 +6,22 @@ #include "base/bind.h" #include "base/string_util.h" +#include "content/common/view_messages.h" #include "content/renderer/render_thread_impl.h" #include "media/audio/audio_util.h" static const int64 kMillisecondsBetweenProcessCalls = 5000; static const char kVersion[] = "WebRTC AudioDevice 1.0.0.Chrome"; +static int GetAudioInputHardwareSampleRate() { + static double input_sample_rate = 0; + if (!input_sample_rate) { + RenderThreadImpl::current()->Send( + new ViewHostMsg_GetHardwareInputSampleRate(&input_sample_rate)); + } + return static_cast<int>(input_sample_rate); +} + WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl() : ref_count_(0), render_loop_(base::MessageLoopProxy::current()), @@ -72,8 +82,6 @@ void WebRtcAudioDeviceImpl::Render( int samples_per_sec = static_cast<int>(output_sample_rate_); if (samples_per_sec == 44100) { // Even if the hardware runs at 44.1kHz, we use 44.0 internally. - // Can only happen on Mac OS X currently since Windows and Mac - // both uses 48kHz. samples_per_sec = 44000; } uint32_t samples_per_10_msec = (samples_per_sec / 100); @@ -132,7 +140,11 @@ void WebRtcAudioDeviceImpl::Capture( input_buffer_.get(), number_of_frames); - const int samples_per_sec = static_cast<int>(input_sample_rate_); + int samples_per_sec = static_cast<int>(input_sample_rate_); + if (samples_per_sec == 44100) { + // Even if the hardware runs at 44.1kHz, we use 44.0 internally. + samples_per_sec = 44000; + } const int samples_per_10_msec = (samples_per_sec / 100); const int bytes_per_10_msec = channels * samples_per_10_msec * bytes_per_sample_; @@ -274,14 +286,16 @@ int32_t WebRtcAudioDeviceImpl::Init() { DCHECK(!input_buffer_.get()); DCHECK(!output_buffer_.get()); - // TODO(henrika): add AudioInputDevice::GetAudioHardwareSampleRate(). - // Assume that input and output sample rates are identical for now. - // Ask the browser for the default audio output hardware sample-rate. // This request is based on a synchronous IPC message. int output_sample_rate = static_cast<int>(AudioDevice::GetAudioHardwareSampleRate()); - VLOG(1) << "Audio hardware sample rate: " << output_sample_rate; + VLOG(1) << "Audio output hardware sample rate: " << output_sample_rate; + + // Ask the browser for the default audio input hardware sample-rate. + // This request is based on a synchronous IPC message. + int input_sample_rate = GetAudioInputHardwareSampleRate(); + VLOG(1) << "Audio input hardware sample rate: " << input_sample_rate; int input_channels = 0; int output_channels = 0; @@ -291,21 +305,32 @@ int32_t WebRtcAudioDeviceImpl::Init() { // For real-time audio (in combination with the webrtc::VoiceEngine) it // is convenient to use audio buffers of size N*10ms. + #if defined(OS_WIN) if (output_sample_rate != 48000) { DLOG(ERROR) << "Only 48kHz sample rate is supported on Windows."; return -1; } - input_channels = 1; + + // Use stereo recording on Windows since low-latency Core Audio (WASAPI) + // does not support mono. + input_channels = 2; output_channels = 1; - // Capture side: AUDIO_PCM_LINEAR on Windows is based on a callback- - // driven Wave implementation where 3 buffers are used for recording audio. - // Each buffer is of the size that we specify here and using more than one - // does not increase the delay but only adds robustness against dropping - // audio. It might also affect the initial start-up time before callbacks - // start to pump. Real-time tests have shown that a buffer size of 10ms - // works fine on the capture side. - input_buffer_size = 480; + + // Capture side: AUDIO_PCM_LOW_LATENCY is based on the Core Audio (WASAPI) + // API which was introduced in Windows Vista. For lower Windows versions, + // a callback-driven Wave implementation is used instead. An input buffer + // size of 10ms works well for both these implementations. + + // Use different buffer sizes depending on the current hardware sample rate. + if (input_sample_rate == 48000) { + input_buffer_size = 480; + } else { + // We do run at 44.1kHz at the actual audio layer, but ask for frames + // at 44.0kHz to ensure that we can feed them to the webrtc::VoiceEngine. + input_buffer_size = 440; + } + // Rendering side: AUDIO_PCM_LOW_LATENCY on Windows is based on a callback- // driven Wave implementation where 2 buffers are fed to the audio driver // before actual rendering starts. Initial real-time tests have shown that @@ -320,6 +345,7 @@ int32_t WebRtcAudioDeviceImpl::Init() { } input_channels = 1; output_channels = 1; + // Rendering side: AUDIO_PCM_LOW_LATENCY on Mac OS X is based on a callback- // driven Core Audio implementation. Tests have shown that 10ms is a suitable // frame size to use, both for 48kHz and 44.1kHz. @@ -347,6 +373,7 @@ int32_t WebRtcAudioDeviceImpl::Init() { } input_channels = 1; output_channels = 1; + // Based on tests using the current ALSA implementation in Chrome, we have // found that the best combination is 20ms on the input side and 10ms on the // output side. @@ -367,17 +394,11 @@ int32_t WebRtcAudioDeviceImpl::Init() { input_buffer_size_ = input_buffer_size; input_channels_ = input_channels; - // TODO(henrika): we use same rate as on output for now. - input_sample_rate_ = output_sample_rate_; + input_sample_rate_ = input_sample_rate; // Create and configure the audio capturing client. audio_input_device_ = new AudioInputDevice( - input_buffer_size, input_channels, output_sample_rate, this, this); -#if defined(OS_MACOSX) - // We create the input device for Mac as well but the performance - // will be very bad. - DLOG(WARNING) << "Real-time recording is not yet supported on Mac OS X"; -#endif + input_buffer_size, input_channels, input_sample_rate, this, this); // Create and configure the audio rendering client. audio_output_device_ = new AudioDevice( |