diff options
author | dalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-01 04:42:39 +0000 |
---|---|---|
committer | dalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-01 04:42:39 +0000 |
commit | 563d665f0a231e3a0237445b577b68bb9b3f212e (patch) | |
tree | 5f4b4dd7497f7fe94653850f3f4f3812fcecf4d8 | |
parent | ccfa43f042db868f6584f9cceef94ca7c4ddf239 (diff) | |
download | chromium_src-563d665f0a231e3a0237445b577b68bb9b3f212e.zip chromium_src-563d665f0a231e3a0237445b577b68bb9b3f212e.tar.gz chromium_src-563d665f0a231e3a0237445b577b68bb9b3f212e.tar.bz2 |
Introduce AudioHardwareConfig for renderer side audio device info.
As discussed, this creates a media::AudioHardwareConfig class lazily created,
owned, and filled by RenderThreadImpl via a single synchronous IPC and updated
via AudioMessageFilter.
This change does not plumb part 2 where AudioRendererMixer recreates itself based
on these device change updates.
BUG=157216
TEST=New unittest. Device changes on Windows/Mac continue to work.
Review URL: https://chromiumcodereview.appspot.com/11880009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@180068 0039d316-1c4b-4281-b951-d872f2087c98
32 files changed, 400 insertions, 319 deletions
diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc index 3c87947..1901e2f 100644 --- a/content/browser/renderer_host/media/audio_renderer_host.cc +++ b/content/browser/renderer_host/media/audio_renderer_host.cc @@ -123,6 +123,17 @@ void AudioRendererHost::OnError(media::AudioOutputController* controller, this, make_scoped_refptr(controller), error_code)); } +void AudioRendererHost::OnDeviceChange(media::AudioOutputController* controller, + int new_buffer_size, + int new_sample_rate) { + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&AudioRendererHost::DoSendDeviceChangeMessage, + this, make_scoped_refptr(controller), new_buffer_size, + new_sample_rate)); +} + void AudioRendererHost::DoCompleteCreation( media::AudioOutputController* controller) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); @@ -196,6 +207,19 @@ void AudioRendererHost::DoSendPausedMessage( entry->stream_id, media::AudioOutputIPCDelegate::kPaused)); } +void AudioRendererHost::DoSendDeviceChangeMessage( + media::AudioOutputController* controller, int new_buffer_size, + int new_sample_rate) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + AudioEntry* entry = LookupByController(controller); + if (!entry) + return; + + Send(new AudioMsg_NotifyDeviceChanged( + entry->stream_id, new_buffer_size, new_sample_rate)); +} + void AudioRendererHost::DoHandleError(media::AudioOutputController* controller, int error_code) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); diff --git a/content/browser/renderer_host/media/audio_renderer_host.h b/content/browser/renderer_host/media/audio_renderer_host.h index 15ebf89..c90d717 100644 --- a/content/browser/renderer_host/media/audio_renderer_host.h +++ b/content/browser/renderer_host/media/audio_renderer_host.h @@ -85,6 +85,9 @@ class CONTENT_EXPORT AudioRendererHost virtual void OnPaused(media::AudioOutputController* controller) OVERRIDE; virtual void OnError(media::AudioOutputController* controller, int error_code) OVERRIDE; + virtual void OnDeviceChange(media::AudioOutputController* controller, + int new_buffer_size, + int new_sample_rate) OVERRIDE; private: friend class AudioRendererHostTest; @@ -135,6 +138,8 @@ class CONTENT_EXPORT AudioRendererHost // Send a state change message to the renderer. void DoSendPlayingMessage(media::AudioOutputController* controller); void DoSendPausedMessage(media::AudioOutputController* controller); + void DoSendDeviceChangeMessage(media::AudioOutputController* controller, + int new_buffer_size, int new_sample_rate); // Handle error coming from audio stream. void DoHandleError(media::AudioOutputController* controller, int error_code); diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc index 5393f5a..aacc6e9 100644 --- a/content/browser/renderer_host/render_message_filter.cc +++ b/content/browser/renderer_host/render_message_filter.cc @@ -417,14 +417,8 @@ bool RenderMessageFilter::OnMessageReceived(const IPC::Message& message, IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_Keygen, OnKeygen) IPC_MESSAGE_HANDLER(ViewHostMsg_AsyncOpenFile, OnAsyncOpenFile) IPC_MESSAGE_HANDLER(ViewHostMsg_GetCPUUsage, OnGetCPUUsage) - IPC_MESSAGE_HANDLER(ViewHostMsg_GetHardwareBufferSize, - OnGetHardwareBufferSize) - IPC_MESSAGE_HANDLER(ViewHostMsg_GetHardwareInputSampleRate, - OnGetHardwareInputSampleRate) - IPC_MESSAGE_HANDLER(ViewHostMsg_GetHardwareSampleRate, - OnGetHardwareSampleRate) - IPC_MESSAGE_HANDLER(ViewHostMsg_GetHardwareInputChannelLayout, - OnGetHardwareInputChannelLayout) + IPC_MESSAGE_HANDLER(ViewHostMsg_GetAudioHardwareConfig, + OnGetAudioHardwareConfig) IPC_MESSAGE_HANDLER(ViewHostMsg_GetMonitorColorProfile, OnGetMonitorColorProfile) IPC_MESSAGE_HANDLER(ViewHostMsg_MediaLogEvent, OnMediaLogEvent) @@ -778,24 +772,16 @@ void RenderMessageFilter::OnGetCPUUsage(int* cpu_usage) { *cpu_usage = cpu_usage_; } -void RenderMessageFilter::OnGetHardwareBufferSize(uint32* buffer_size) { - *buffer_size = static_cast<uint32>(media::GetAudioHardwareBufferSize()); -} +void RenderMessageFilter::OnGetAudioHardwareConfig( + int* output_buffer_size, int* output_sample_rate, int* input_sample_rate, + media::ChannelLayout* input_channel_layout) { + *output_buffer_size = media::GetAudioHardwareBufferSize(); + *output_sample_rate = media::GetAudioHardwareSampleRate(); -void RenderMessageFilter::OnGetHardwareInputSampleRate(int* sample_rate) { // TODO(henrika): add support for all available input devices. - *sample_rate = media::GetAudioInputHardwareSampleRate( + *input_sample_rate = media::GetAudioInputHardwareSampleRate( media::AudioManagerBase::kDefaultDeviceId); -} - -void RenderMessageFilter::OnGetHardwareSampleRate(int* sample_rate) { - *sample_rate = media::GetAudioHardwareSampleRate(); -} - -void RenderMessageFilter::OnGetHardwareInputChannelLayout( - media::ChannelLayout* layout) { - // TODO(henrika): add support for all available input devices. - *layout = media::GetAudioInputHardwareChannelLayout( + *input_channel_layout = media::GetAudioInputHardwareChannelLayout( media::AudioManagerBase::kDefaultDeviceId); } diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h index 1d77fb3..af6036e 100644 --- a/content/browser/renderer_host/render_message_filter.h +++ b/content/browser/renderer_host/render_message_filter.h @@ -189,10 +189,9 @@ class RenderMessageFilter : public BrowserMessageFilter { void OnGetCPUUsage(int* cpu_usage); - void OnGetHardwareBufferSize(uint32* buffer_size); - void OnGetHardwareInputSampleRate(int* sample_rate); - void OnGetHardwareSampleRate(int* sample_rate); - void OnGetHardwareInputChannelLayout(media::ChannelLayout* layout); + void OnGetAudioHardwareConfig(int* output_buffer_size, + int* output_sample_rate, int* input_sample_rate, + media::ChannelLayout* input_channel_layout); // Used to look up the monitor color profile. void OnGetMonitorColorProfile(std::vector<char>* profile); diff --git a/content/common/media/audio_messages.h b/content/common/media/audio_messages.h index cac43d1..8977417 100644 --- a/content/common/media/audio_messages.h +++ b/content/common/media/audio_messages.h @@ -63,6 +63,13 @@ IPC_MESSAGE_CONTROL4(AudioInputMsg_NotifyStreamCreated, uint32 /* length */) #endif +// Notification message sent from AudioRendererHost to renderer after an output +// device change has occurred. +IPC_MESSAGE_CONTROL3(AudioMsg_NotifyDeviceChanged, + int /* stream_id */, + int /* new_buffer_size */, + int /* new_sample_rate */) + // Notification message sent from AudioRendererHost to renderer for state // update after the renderer has requested a Create/Start/Close. IPC_MESSAGE_CONTROL2(AudioMsg_NotifyStreamStateChanged, diff --git a/content/common/view_messages.h b/content/common/view_messages.h index 0b36fdc..4e064fa 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h @@ -720,20 +720,11 @@ IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GenerateRoutingID, int /* routing_id */) // Asks the browser for the default audio hardware buffer-size. -IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GetHardwareBufferSize, - uint32 /* buffer_size */) - -// Asks the browser for the default audio input hardware sample-rate. -IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GetHardwareInputSampleRate, - int /* sample_rate */) - -// Asks the browser for the default audio hardware sample-rate. -IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GetHardwareSampleRate, - int /* sample_rate */) - -// Asks the browser for the default channel layout. -IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GetHardwareInputChannelLayout, - media::ChannelLayout /* channel layout */) +IPC_SYNC_MESSAGE_CONTROL0_4(ViewHostMsg_GetAudioHardwareConfig, + int /* output_buffer_size */, + int /* output_sample_rate */, + int /* input_sample_rate */, + media::ChannelLayout /* input_channel_layout */) // Asks the browser for CPU usage of the renderer process in percents. IPC_SYNC_MESSAGE_CONTROL0_1(ViewHostMsg_GetCPUUsage, diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 633717c..46b29b1 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -114,8 +114,6 @@ 'renderer/load_progress_tracker.h', 'renderer/media/audio_device_factory.cc', 'renderer/media/audio_device_factory.h', - 'renderer/media/audio_hardware.cc', - 'renderer/media/audio_hardware.h', 'renderer/media/audio_input_message_filter.cc', 'renderer/media/audio_input_message_filter.h', 'renderer/media/audio_message_filter.cc', diff --git a/content/renderer/media/audio_hardware.cc b/content/renderer/media/audio_hardware.cc deleted file mode 100644 index 9f22a2d..0000000 --- a/content/renderer/media/audio_hardware.cc +++ /dev/null @@ -1,76 +0,0 @@ -// 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 "content/renderer/media/audio_hardware.h" - -#include "base/logging.h" -#include "content/common/view_messages.h" -#include "content/renderer/render_thread_impl.h" - -using media::ChannelLayout; -using media::CHANNEL_LAYOUT_NONE; - -static int output_sample_rate = 0; -static int input_sample_rate = 0; -static size_t output_buffer_size = 0; -static ChannelLayout input_channel_layout = CHANNEL_LAYOUT_NONE; - -namespace content { - -int GetAudioOutputSampleRate() { - DCHECK(RenderThreadImpl::current() != NULL); - - if (!output_sample_rate) { - RenderThreadImpl::current()->Send( - new ViewHostMsg_GetHardwareSampleRate(&output_sample_rate)); - } - return output_sample_rate; -} - -int GetAudioInputSampleRate() { - DCHECK(RenderThreadImpl::current() != NULL); - - if (!input_sample_rate) { - RenderThreadImpl::current()->Send( - new ViewHostMsg_GetHardwareInputSampleRate(&input_sample_rate)); - } - return input_sample_rate; -} - -size_t GetAudioOutputBufferSize() { - DCHECK(RenderThreadImpl::current() != NULL); - - if (!output_buffer_size) { - uint32 buffer_size = 0; - RenderThreadImpl::current()->Send( - new ViewHostMsg_GetHardwareBufferSize(&buffer_size)); - output_buffer_size = buffer_size; - } - - return output_buffer_size; -} - -ChannelLayout GetAudioInputChannelLayout() { - DCHECK(RenderThreadImpl::current() != NULL); - - if (input_channel_layout == CHANNEL_LAYOUT_NONE) { - ChannelLayout layout = CHANNEL_LAYOUT_NONE; - RenderThreadImpl::current()->Send( - new ViewHostMsg_GetHardwareInputChannelLayout(&layout)); - input_channel_layout = layout; - } - - return input_channel_layout; -} - -void ResetAudioCache() { - DCHECK(RenderThreadImpl::current() != NULL); - - output_sample_rate = 0.0; - input_sample_rate = 0.0; - output_buffer_size = 0; - input_channel_layout = CHANNEL_LAYOUT_NONE; -} - -} // namespace content diff --git a/content/renderer/media/audio_hardware.h b/content/renderer/media/audio_hardware.h deleted file mode 100644 index 3171387..0000000 --- a/content/renderer/media/audio_hardware.h +++ /dev/null @@ -1,40 +0,0 @@ -// 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. -// -#ifndef CONTENT_RENDERER_MEDIA_AUDIO_HARDWARE_H_ -#define CONTENT_RENDERER_MEDIA_AUDIO_HARDWARE_H_ - -#include "base/basictypes.h" -#include "content/common/content_export.h" -#include "media/base/channel_layout.h" - -// This file contains static methods to query audio hardware properties from -// the browser process. Values are cached to avoid unnecessary round trips, -// but the cache can be cleared if needed (currently only used by tests). - -namespace content { - -// Fetch the sample rate of the default audio output end point device. -// Must be called from RenderThreadImpl::current(). -CONTENT_EXPORT int GetAudioOutputSampleRate(); - -// Fetch the sample rate of the default audio input end point device. -// Must be called from RenderThreadImpl::current(). -CONTENT_EXPORT int GetAudioInputSampleRate(); - -// Fetch the buffer size we use for the default output device. -// Must be called from RenderThreadImpl::current(). -// Must be used in conjunction with AUDIO_PCM_LOW_LATENCY. -CONTENT_EXPORT size_t GetAudioOutputBufferSize(); - -// Fetch the audio channel layout for the default input device. -// Must be called from RenderThreadImpl::current(). -CONTENT_EXPORT media::ChannelLayout GetAudioInputChannelLayout(); - -// Forces the next call to any of the Get functions to query the hardware -// and repopulate the cache. -CONTENT_EXPORT void ResetAudioCache(); -} // namespace content - -#endif // CONTENT_RENDERER_MEDIA_AUDIO_HARDWARE_H_ diff --git a/content/renderer/media/audio_message_filter.cc b/content/renderer/media/audio_message_filter.cc index 22915c5..4eef36c 100644 --- a/content/renderer/media/audio_message_filter.cc +++ b/content/renderer/media/audio_message_filter.cc @@ -23,21 +23,22 @@ AudioMessageFilter* AudioMessageFilter::Get() { AudioMessageFilter::AudioMessageFilter() : next_stream_id_(1), - channel_(NULL) { + channel_(NULL), + audio_hardware_config_(NULL) { DVLOG(1) << "AudioMessageFilter::AudioMessageFilter()"; DCHECK(!filter_); filter_ = this; } int AudioMessageFilter::AddDelegate(media::AudioOutputIPCDelegate* delegate) { - base::AutoLock guard(delegates_lock_); + base::AutoLock auto_lock(lock_); const int id = next_stream_id_++; delegates_.insert(std::make_pair(id, delegate)); return id; } void AudioMessageFilter::RemoveDelegate(int id) { - base::AutoLock guard(delegates_lock_); + base::AutoLock auto_lock(lock_); delegates_.erase(id); } @@ -96,6 +97,7 @@ bool AudioMessageFilter::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(AudioMessageFilter, message) IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamCreated, OnStreamCreated) IPC_MESSAGE_HANDLER(AudioMsg_NotifyStreamStateChanged, OnStreamStateChanged) + IPC_MESSAGE_HANDLER(AudioMsg_NotifyDeviceChanged, OnOutputDeviceChanged) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -115,7 +117,7 @@ void AudioMessageFilter::OnChannelClosing() { DelegateMap zombies; { - base::AutoLock guard(delegates_lock_); + base::AutoLock auto_lock(lock_); delegates_.swap(zombies); } @@ -153,7 +155,7 @@ void AudioMessageFilter::OnStreamCreated( #endif { - base::AutoLock guard(delegates_lock_); + base::AutoLock auto_lock(lock_); DelegateMap::const_iterator it = delegates_.find(stream_id); if (it != delegates_.end()) { it->second->OnStreamCreated(handle, socket_handle, length); @@ -169,7 +171,7 @@ void AudioMessageFilter::OnStreamCreated( void AudioMessageFilter::OnStreamStateChanged( int stream_id, media::AudioOutputIPCDelegate::State state) { - base::AutoLock guard(delegates_lock_); + base::AutoLock auto_lock(lock_); DelegateMap::const_iterator it = delegates_.find(stream_id); DLOG_IF(WARNING, it == delegates_.end()) << "No delegate found for state change. " << state; @@ -177,4 +179,24 @@ void AudioMessageFilter::OnStreamStateChanged( it->second->OnStateChanged(state); } +void AudioMessageFilter::OnOutputDeviceChanged(int stream_id, + int new_buffer_size, + int new_sample_rate) { + base::AutoLock auto_lock(lock_); + + // Ignore the message if an audio hardware config hasn't been created; this + // can occur if the renderer is using the high latency audio path. + // TODO(dalecurtis): After http://crbug.com/173435 is fixed, convert to CHECK. + if (!audio_hardware_config_) + return; + + audio_hardware_config_->UpdateOutputConfig(new_buffer_size, new_sample_rate); +} + +void AudioMessageFilter::SetAudioHardwareConfig( + media::AudioHardwareConfig* config) { + base::AutoLock auto_lock(lock_); + audio_hardware_config_ = config; +} + } // namespace content diff --git a/content/renderer/media/audio_message_filter.h b/content/renderer/media/audio_message_filter.h index de746d5..1172607 100644 --- a/content/renderer/media/audio_message_filter.h +++ b/content/renderer/media/audio_message_filter.h @@ -19,6 +19,7 @@ #include "ipc/ipc_channel_proxy.h" #include "media/audio/audio_buffers_state.h" #include "media/audio/audio_output_ipc.h" +#include "media/base/audio_hardware_config.h" namespace content { @@ -37,8 +38,8 @@ class CONTENT_EXPORT AudioMessageFilter // media::AudioOutputIPC implementation. virtual int AddDelegate(media::AudioOutputIPCDelegate* delegate) OVERRIDE; virtual void RemoveDelegate(int id) OVERRIDE; - virtual void CreateStream(int stream_id, - const media::AudioParameters& params, int input_channels) OVERRIDE; + virtual void CreateStream(int stream_id, const media::AudioParameters& params, + int input_channels) OVERRIDE; virtual void PlayStream(int stream_id) OVERRIDE; virtual void PauseStream(int stream_id) OVERRIDE; virtual void FlushStream(int stream_id) OVERRIDE; @@ -51,6 +52,11 @@ class CONTENT_EXPORT AudioMessageFilter virtual void OnFilterRemoved() OVERRIDE; virtual void OnChannelClosing() OVERRIDE; + // When set, AudioMessageFilter will update the AudioHardwareConfig with new + // configuration values as recieved by OnOutputDeviceChanged(). The provided + // |config| must outlive AudioMessageFilter. + void SetAudioHardwareConfig(media::AudioHardwareConfig* config); + protected: virtual ~AudioMessageFilter(); @@ -75,21 +81,26 @@ class CONTENT_EXPORT AudioMessageFilter void OnStreamStateChanged(int stream_id, media::AudioOutputIPCDelegate::State state); + // Received when the browser process detects an output device change. + void OnOutputDeviceChanged(int stream_id, int new_buffer_size, + int new_sample_rate); + // The singleton instance for this filter. static AudioMessageFilter* filter_; - // Guards delegates_ since AddDelegate() and RemoveDelegate() are called from - // threads other than the IO thread. - base::Lock delegates_lock_; + // Unique ID to use for next added delegate. + int next_stream_id_; + IPC::Channel* channel_; + + // Guards all variables below which are accessed from multiple threads. + base::Lock lock_; // A map of stream ids to delegates. typedef base::hash_map<int, media::AudioOutputIPCDelegate*> DelegateMap; DelegateMap delegates_; - // Unique ID to use for next added delegate. - int next_stream_id_; - - IPC::Channel* channel_; + // Audio hardware configuration to update when OnOutputDeviceChanged() fires. + media::AudioHardwareConfig* audio_hardware_config_; DISALLOW_COPY_AND_ASSIGN(AudioMessageFilter); }; diff --git a/content/renderer/media/audio_renderer_mixer_manager.cc b/content/renderer/media/audio_renderer_mixer_manager.cc index 71fafcb..d6e88c8 100644 --- a/content/renderer/media/audio_renderer_mixer_manager.cc +++ b/content/renderer/media/audio_renderer_mixer_manager.cc @@ -8,15 +8,15 @@ #include "base/bind_helpers.h" #include "content/renderer/media/audio_device_factory.h" #include "content/renderer/media/renderer_audio_output_device.h" +#include "media/base/audio_hardware_config.h" #include "media/base/audio_renderer_mixer.h" #include "media/base/audio_renderer_mixer_input.h" namespace content { -AudioRendererMixerManager::AudioRendererMixerManager(int hardware_sample_rate, - int hardware_buffer_size) - : hardware_sample_rate_(hardware_sample_rate), - hardware_buffer_size_(hardware_buffer_size), +AudioRendererMixerManager::AudioRendererMixerManager( + media::AudioHardwareConfig* hardware_config) + : hardware_config_(hardware_config), sink_for_testing_(NULL) { } @@ -57,7 +57,7 @@ media::AudioRendererMixer* AudioRendererMixerManager::GetMixer( #if defined(OS_LINUX) int sample_rate = params.sample_rate(); #else - int sample_rate = hardware_sample_rate_; + int sample_rate = hardware_config_->GetOutputSampleRate(); #endif // Create output parameters based on the audio hardware configuration for @@ -65,7 +65,7 @@ media::AudioRendererMixer* AudioRendererMixerManager::GetMixer( // know that works well for WebAudio and WebRTC. media::AudioParameters output_params( media::AudioParameters::AUDIO_PCM_LOW_LATENCY, params.channel_layout(), - sample_rate, 16, hardware_buffer_size_); + sample_rate, 16, hardware_config_->GetOutputBufferSize()); // If we've created invalid output parameters, simply pass on the input params // and let the browser side handle automatic fallback. diff --git a/content/renderer/media/audio_renderer_mixer_manager.h b/content/renderer/media/audio_renderer_mixer_manager.h index 20afcb8..dd2575b 100644 --- a/content/renderer/media/audio_renderer_mixer_manager.h +++ b/content/renderer/media/audio_renderer_mixer_manager.h @@ -13,6 +13,7 @@ #include "media/audio/audio_parameters.h" namespace media { +class AudioHardwareConfig; class AudioRendererMixer; class AudioRendererMixerInput; class AudioRendererSink; @@ -35,8 +36,11 @@ namespace content { // via the shared memory. See http://crbug.com/114700. class CONTENT_EXPORT AudioRendererMixerManager { public: - // Construct an instance using the given audio hardware configuration. - AudioRendererMixerManager(int hardware_sample_rate, int hardware_buffer_size); + // Construct an instance using the given audio hardware configuration. The + // provided |hardware_config| is not owned by AudioRendererMixerManager and + // must outlive it. + explicit AudioRendererMixerManager( + media::AudioHardwareConfig* hardware_config); ~AudioRendererMixerManager(); // Creates an AudioRendererMixerInput with the proper callbacks necessary to @@ -82,8 +86,7 @@ class CONTENT_EXPORT AudioRendererMixerManager { // Audio hardware configuration. Used to construct output AudioParameters for // each AudioRendererMixer instance. - int hardware_sample_rate_; - int hardware_buffer_size_; + media::AudioHardwareConfig* const hardware_config_; media::AudioRendererSink* sink_for_testing_; diff --git a/content/renderer/media/audio_renderer_mixer_manager_unittest.cc b/content/renderer/media/audio_renderer_mixer_manager_unittest.cc index 46e78f3..0d00942 100644 --- a/content/renderer/media/audio_renderer_mixer_manager_unittest.cc +++ b/content/renderer/media/audio_renderer_mixer_manager_unittest.cc @@ -2,9 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "content/renderer/media/audio_renderer_mixer_manager.h" +#include "media/base/audio_hardware_config.h" #include "media/base/audio_renderer_mixer.h" #include "media/base/audio_renderer_mixer_input.h" #include "media/base/fake_audio_render_callback.h" @@ -24,8 +26,9 @@ static const int kAnotherRenderViewId = 456; class AudioRendererMixerManagerTest : public testing::Test { public: - AudioRendererMixerManagerTest() { - manager_.reset(new AudioRendererMixerManager(kSampleRate, kBufferSize)); + AudioRendererMixerManagerTest() + : fake_config_(kBufferSize, kSampleRate, 0, media::CHANNEL_LAYOUT_NONE) { + manager_.reset(new AudioRendererMixerManager(&fake_config_)); // We don't want to deal with instantiating a real AudioOutputDevice since // it's not important to our testing, so we inject a mock. @@ -49,6 +52,7 @@ class AudioRendererMixerManagerTest : public testing::Test { } protected: + media::AudioHardwareConfig fake_config_; scoped_ptr<AudioRendererMixerManager> manager_; scoped_refptr<media::MockAudioRendererSink> mock_sink_; diff --git a/content/renderer/media/webrtc_audio_capturer.cc b/content/renderer/media/webrtc_audio_capturer.cc index 16836f2a..a3c6ebf 100644 --- a/content/renderer/media/webrtc_audio_capturer.cc +++ b/content/renderer/media/webrtc_audio_capturer.cc @@ -10,7 +10,6 @@ #include "base/string_util.h" #include "content/common/child_process.h" #include "content/renderer/media/audio_device_factory.h" -#include "content/renderer/media/audio_hardware.h" #include "content/renderer/media/webrtc_audio_device_impl.h" #include "content/renderer/media/webrtc_local_audio_renderer.h" #include "media/audio/audio_util.h" diff --git a/content/renderer/media/webrtc_audio_device_impl.cc b/content/renderer/media/webrtc_audio_device_impl.cc index 21fc788..32a5e49 100644 --- a/content/renderer/media/webrtc_audio_device_impl.cc +++ b/content/renderer/media/webrtc_audio_device_impl.cc @@ -8,7 +8,6 @@ #include "base/metrics/histogram.h" #include "base/string_util.h" #include "base/win/windows_version.h" -#include "content/renderer/media/audio_hardware.h" #include "content/renderer/media/webrtc_audio_capturer.h" #include "content/renderer/media/webrtc_audio_renderer.h" #include "content/renderer/render_thread_impl.h" diff --git a/content/renderer/media/webrtc_audio_device_unittest.cc b/content/renderer/media/webrtc_audio_device_unittest.cc index 30157b0..e988aa2 100644 --- a/content/renderer/media/webrtc_audio_device_unittest.cc +++ b/content/renderer/media/webrtc_audio_device_unittest.cc @@ -4,13 +4,14 @@ #include "base/environment.h" #include "base/test/test_timeouts.h" -#include "content/renderer/media/audio_hardware.h" #include "content/renderer/media/webrtc_audio_capturer.h" #include "content/renderer/media/webrtc_audio_device_impl.h" #include "content/renderer/media/webrtc_audio_renderer.h" +#include "content/renderer/render_thread_impl.h" #include "content/test/webrtc_audio_device_test.h" -#include "media/audio/audio_manager.h" +#include "media/audio/audio_manager_base.h" #include "media/audio/audio_util.h" +#include "media/base/audio_hardware_config.h" #include "testing/gmock/include/gmock/gmock.h" #include "third_party/webrtc/voice_engine/include/voe_audio_processing.h" #include "third_party/webrtc/voice_engine/include/voe_base.h" @@ -30,52 +31,14 @@ namespace { const int kRenderViewId = 1; -class AudioUtil : public AudioUtilInterface { - public: - AudioUtil() {} - - virtual int GetAudioHardwareSampleRate() OVERRIDE { - return media::GetAudioHardwareSampleRate(); - } - virtual int GetAudioInputHardwareSampleRate( - const std::string& device_id) OVERRIDE { - return media::GetAudioInputHardwareSampleRate(device_id); - } - virtual media::ChannelLayout GetAudioInputHardwareChannelLayout( - const std::string& device_id) OVERRIDE { - return media::GetAudioInputHardwareChannelLayout(device_id); - } - private: - DISALLOW_COPY_AND_ASSIGN(AudioUtil); -}; - -class AudioUtilNoHardware : public AudioUtilInterface { - public: - AudioUtilNoHardware(int output_rate, int input_rate, - media::ChannelLayout input_channel_layout) - : output_rate_(output_rate), - input_rate_(input_rate), - input_channel_layout_(input_channel_layout) { - } - - virtual int GetAudioHardwareSampleRate() OVERRIDE { - return output_rate_; - } - virtual int GetAudioInputHardwareSampleRate( - const std::string& device_id) OVERRIDE { - return input_rate_; - } - virtual media::ChannelLayout GetAudioInputHardwareChannelLayout( - const std::string& device_id) OVERRIDE { - return input_channel_layout_; - } - - private: - int output_rate_; - int input_rate_; - media::ChannelLayout input_channel_layout_; - DISALLOW_COPY_AND_ASSIGN(AudioUtilNoHardware); -}; +scoped_ptr<media::AudioHardwareConfig> CreateRealHardwareConfig() { + return make_scoped_ptr(new media::AudioHardwareConfig( + media::GetAudioHardwareBufferSize(), media::GetAudioHardwareSampleRate(), + media::GetAudioInputHardwareSampleRate( + media::AudioManagerBase::kDefaultDeviceId), + media::GetAudioInputHardwareChannelLayout( + media::AudioManagerBase::kDefaultDeviceId))); +} // Return true if at least one element in the array matches |value|. bool FindElementInArray(int* array, int size, int value) { @@ -95,8 +58,11 @@ bool HardwareSampleRatesAreValid() { int valid_input_rates[] = {16000, 32000, 44100, 48000, 96000}; int valid_output_rates[] = {44100, 48000, 96000}; + media::AudioHardwareConfig* hardware_config = + RenderThreadImpl::current()->GetAudioHardwareConfig(); + // Verify the input sample rate. - int input_sample_rate = GetAudioInputSampleRate(); + int input_sample_rate = hardware_config->GetInputSampleRate(); if (!FindElementInArray(valid_input_rates, arraysize(valid_input_rates), input_sample_rate)) { @@ -105,7 +71,7 @@ bool HardwareSampleRatesAreValid() { } // Given that the input rate was OK, verify the output rate as well. - int output_sample_rate = GetAudioOutputSampleRate(); + int output_sample_rate = hardware_config->GetOutputSampleRate(); if (!FindElementInArray(valid_output_rates, arraysize(valid_output_rates), output_sample_rate)) { LOG(WARNING) << "Non-supported output sample rate detected."; @@ -124,10 +90,14 @@ bool InitializeCapturer(WebRtcAudioDeviceImpl* webrtc_audio_device) { if (!capturer) return false; + media::AudioHardwareConfig* hardware_config = + RenderThreadImpl::current()->GetAudioHardwareConfig(); + // Use native capture sample rate and channel configuration to get some // action in this test. - int sample_rate = GetAudioInputSampleRate(); - media::ChannelLayout channel_layout = GetAudioInputChannelLayout(); + int sample_rate = hardware_config->GetInputSampleRate(); + media::ChannelLayout channel_layout = + hardware_config->GetInputChannelLayout(); if (!capturer->Initialize(channel_layout, sample_rate)) return false; @@ -246,8 +216,9 @@ TEST_F(WebRTCAudioDeviceTest, TestValidOutputRates) { // Basic test that instantiates and initializes an instance of // WebRtcAudioDeviceImpl. TEST_F(WebRTCAudioDeviceTest, Construct) { - AudioUtilNoHardware audio_util(48000, 48000, media::CHANNEL_LAYOUT_MONO); - SetAudioUtilCallback(&audio_util); + media::AudioHardwareConfig audio_config( + 480, 48000, 48000, media::CHANNEL_LAYOUT_MONO); + SetAudioHardwareConfig(&audio_config); scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device( new WebRtcAudioDeviceImpl()); @@ -279,8 +250,8 @@ TEST_F(WebRTCAudioDeviceTest, DISABLED_StartPlayout) { return; } - AudioUtil audio_util; - SetAudioUtilCallback(&audio_util); + scoped_ptr<media::AudioHardwareConfig> config = CreateRealHardwareConfig(); + SetAudioHardwareConfig(config.get()); if (!HardwareSampleRatesAreValid()) return; @@ -357,8 +328,8 @@ TEST_F(WebRTCAudioDeviceTest, StartRecording) { return; } - AudioUtil audio_util; - SetAudioUtilCallback(&audio_util); + scoped_ptr<media::AudioHardwareConfig> config = CreateRealHardwareConfig(); + SetAudioHardwareConfig(config.get()); if (!HardwareSampleRatesAreValid()) return; @@ -430,8 +401,8 @@ TEST_F(WebRTCAudioDeviceTest, DISABLED_PlayLocalFile) { std::string file_path( GetTestDataPath(FILE_PATH_LITERAL("speechmusic_mono_16kHz.pcm"))); - AudioUtil audio_util; - SetAudioUtilCallback(&audio_util); + scoped_ptr<media::AudioHardwareConfig> config = CreateRealHardwareConfig(); + SetAudioHardwareConfig(config.get()); if (!HardwareSampleRatesAreValid()) return; @@ -501,8 +472,8 @@ TEST_F(WebRTCAudioDeviceTest, FullDuplexAudioWithAGC) { return; } - AudioUtil audio_util; - SetAudioUtilCallback(&audio_util); + scoped_ptr<media::AudioHardwareConfig> config = CreateRealHardwareConfig(); + SetAudioHardwareConfig(config.get()); if (!HardwareSampleRatesAreValid()) return; diff --git a/content/renderer/media/webrtc_audio_renderer.cc b/content/renderer/media/webrtc_audio_renderer.cc index c21c662..0d33713 100644 --- a/content/renderer/media/webrtc_audio_renderer.cc +++ b/content/renderer/media/webrtc_audio_renderer.cc @@ -8,11 +8,13 @@ #include "base/metrics/histogram.h" #include "base/string_util.h" #include "content/renderer/media/audio_device_factory.h" -#include "content/renderer/media/audio_hardware.h" #include "content/renderer/media/renderer_audio_output_device.h" #include "content/renderer/media/webrtc_audio_device_impl.h" +#include "content/renderer/render_thread_impl.h" #include "media/audio/audio_util.h" #include "media/audio/sample_rates.h" +#include "media/base/audio_hardware_config.h" + #if defined(OS_WIN) #include "base/win/windows_version.h" #include "media/audio/win/core_audio_util_win.h" @@ -24,10 +26,10 @@ namespace { // Supported hardware sample rates for output sides. #if defined(OS_WIN) || defined(OS_MACOSX) -// media::GetAudioOutputHardwareSampleRate() asks the audio layer -// for its current sample rate (set by the user) on Windows and Mac OS X. -// The listed rates below adds restrictions and Initialize() -// will fail if the user selects any rate outside these ranges. +// AudioHardwareConfig::GetOutputSampleRate() asks the audio layer for its +// current sample rate (set by the user) on Windows and Mac OS X. The listed +// rates below adds restrictions and Initialize() will fail if the user selects +// any rate outside these ranges. int kValidOutputRates[] = {96000, 48000, 44100}; #elif defined(OS_LINUX) || defined(OS_OPENBSD) int kValidOutputRates[] = {48000, 44100}; @@ -104,9 +106,10 @@ bool WebRtcAudioRenderer::Initialize(WebRtcAudioRendererSource* source) { sink_ = AudioDeviceFactory::NewOutputDevice(); DCHECK(sink_); - // Ask the browser for the default audio output hardware sample-rate. - // This request is based on a synchronous IPC message. - int sample_rate = GetAudioOutputSampleRate(); + // Ask the renderer for the default audio output hardware sample-rate. + media::AudioHardwareConfig* hardware_config = + RenderThreadImpl::current()->GetAudioHardwareConfig(); + int sample_rate = hardware_config->GetOutputSampleRate(); DVLOG(1) << "Audio output hardware sample rate: " << sample_rate; UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputSampleRate", sample_rate, media::kUnexpectedAudioSampleRate); diff --git a/content/renderer/pepper/pepper_platform_audio_output_impl.cc b/content/renderer/pepper/pepper_platform_audio_output_impl.cc index 6681d0a..2a6dbf6 100644 --- a/content/renderer/pepper/pepper_platform_audio_output_impl.cc +++ b/content/renderer/pepper/pepper_platform_audio_output_impl.cc @@ -11,9 +11,9 @@ #include "build/build_config.h" #include "content/common/child_process.h" #include "content/common/media/audio_messages.h" -#include "content/renderer/media/audio_hardware.h" #include "content/renderer/media/audio_message_filter.h" #include "content/renderer/render_thread_impl.h" +#include "media/base/audio_hardware_config.h" #include "media/base/media_switches.h" namespace content { @@ -125,14 +125,17 @@ bool PepperPlatformAudioOutputImpl::Initialize( media::AudioParameters::Format format; const int kMaxFramesForLowLatency = 2047; + media::AudioHardwareConfig* hardware_config = + RenderThreadImpl::current()->GetAudioHardwareConfig(); + const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); if (!cmd_line->HasSwitch(switches::kDisableAudioOutputResampler)) { // Rely on AudioOutputResampler to handle any inconsistencies between the // hardware params required for low latency and the requested params. format = media::AudioParameters::AUDIO_PCM_LOW_LATENCY; - } else if (sample_rate == GetAudioOutputSampleRate() && + } else if (sample_rate == hardware_config->GetOutputSampleRate() && frames_per_buffer <= kMaxFramesForLowLatency && - frames_per_buffer % content::GetAudioOutputBufferSize() == 0) { + frames_per_buffer % hardware_config->GetOutputBufferSize() == 0) { // Use the low latency back end if the client request is compatible, and // the sample count is low enough to justify using AUDIO_PCM_LOW_LATENCY. format = media::AudioParameters::AUDIO_PCM_LOW_LATENCY; diff --git a/content/renderer/pepper/pepper_plugin_delegate_impl.cc b/content/renderer/pepper/pepper_plugin_delegate_impl.cc index 8c6eb0d..5fdd139 100644 --- a/content/renderer/pepper/pepper_plugin_delegate_impl.cc +++ b/content/renderer/pepper/pepper_plugin_delegate_impl.cc @@ -35,7 +35,6 @@ #include "content/public/renderer/content_renderer_client.h" #include "content/public/renderer/renderer_restrict_dispatch_group.h" #include "content/renderer/gamepad_shared_memory_reader.h" -#include "content/renderer/media/audio_hardware.h" #include "content/renderer/media/media_stream_dispatcher.h" #include "content/renderer/media/pepper_platform_video_decoder_impl.h" #include "content/renderer/p2p/socket_dispatcher.h" @@ -57,6 +56,7 @@ #include "content/renderer/webplugin_delegate_proxy.h" #include "googleurl/src/gurl.h" #include "ipc/ipc_channel_handle.h" +#include "media/base/audio_hardware_config.h" #include "media/video/capture/video_capture_proxy.h" #include "ppapi/c/dev/pp_video_dev.h" #include "ppapi/c/pp_errors.h" @@ -864,11 +864,13 @@ void PepperPluginDelegateImpl::SelectedFindResultChanged(int identifier, } uint32_t PepperPluginDelegateImpl::GetAudioHardwareOutputSampleRate() { - return static_cast<uint32_t>(GetAudioOutputSampleRate()); + RenderThreadImpl* thread = RenderThreadImpl::current(); + return thread->GetAudioHardwareConfig()->GetOutputSampleRate(); } uint32_t PepperPluginDelegateImpl::GetAudioHardwareOutputBufferSize() { - return static_cast<uint32_t>(GetAudioOutputBufferSize()); + RenderThreadImpl* thread = RenderThreadImpl::current(); + return thread->GetAudioHardwareConfig()->GetOutputBufferSize(); } webkit::ppapi::PluginDelegate::PlatformAudioOutput* diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 5cc42cd..7dd13c2 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc @@ -55,7 +55,6 @@ #include "content/renderer/gpu/compositor_thread.h" #include "content/renderer/gpu/compositor_output_surface.h" #include "content/renderer/gpu/gpu_benchmarking_extension.h" -#include "content/renderer/media/audio_hardware.h" #include "content/renderer/media/audio_input_message_filter.h" #include "content/renderer/media/audio_message_filter.h" #include "content/renderer/media/audio_renderer_mixer_manager.h" @@ -73,6 +72,7 @@ #include "ipc/ipc_channel_handle.h" #include "ipc/ipc_forwarding_message_filter.h" #include "ipc/ipc_platform_file.h" +#include "media/base/audio_hardware_config.h" #include "media/base/media.h" #include "media/base/media_switches.h" #include "net/base/net_errors.h" @@ -904,13 +904,32 @@ RenderThreadImpl::GetGpuVDAContext3D() { AudioRendererMixerManager* RenderThreadImpl::GetAudioRendererMixerManager() { if (!audio_renderer_mixer_manager_.get()) { audio_renderer_mixer_manager_.reset(new AudioRendererMixerManager( - GetAudioOutputSampleRate(), - GetAudioOutputBufferSize())); + GetAudioHardwareConfig())); } return audio_renderer_mixer_manager_.get(); } +media::AudioHardwareConfig* RenderThreadImpl::GetAudioHardwareConfig() { + if (!audio_hardware_config_) { + int output_buffer_size; + int output_sample_rate; + int input_sample_rate; + media::ChannelLayout input_channel_layout; + + Send(new ViewHostMsg_GetAudioHardwareConfig( + &output_buffer_size, &output_sample_rate, + &input_sample_rate, &input_channel_layout)); + + audio_hardware_config_.reset(new media::AudioHardwareConfig( + output_buffer_size, output_sample_rate, input_sample_rate, + input_channel_layout)); + audio_message_filter_->SetAudioHardwareConfig(audio_hardware_config_.get()); + } + + return audio_hardware_config_.get(); +} + #if defined(OS_WIN) void RenderThreadImpl::PreCacheFontCharacters(const LOGFONT& log_font, const string16& str) { diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h index a70be92..0ca7420 100644 --- a/content/renderer/render_thread_impl.h +++ b/content/renderer/render_thread_impl.h @@ -45,6 +45,10 @@ namespace IPC { class ForwardingMessageFilter; } +namespace media { +class AudioHardwareConfig; +} + namespace v8 { class Extension; } @@ -246,6 +250,11 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread, // first call. AudioRendererMixerManager* GetAudioRendererMixerManager(); + // AudioHardwareConfig contains audio hardware configuration for + // renderer side clients. Creation requires a synchronous IPC call so it is + // lazily created on the first call. + media::AudioHardwareConfig* GetAudioHardwareConfig(); + #if defined(OS_WIN) void PreCacheFontCharacters(const LOGFONT& log_font, const string16& str); #endif @@ -381,6 +390,7 @@ class CONTENT_EXPORT RenderThreadImpl : public RenderThread, scoped_ptr<WebGraphicsContext3DCommandBufferImpl> gpu_vda_context3d_; scoped_ptr<AudioRendererMixerManager> audio_renderer_mixer_manager_; + scoped_ptr<media::AudioHardwareConfig> audio_hardware_config_; HistogramCustomizer histogram_customizer_; diff --git a/content/renderer/renderer_webkitplatformsupport_impl.cc b/content/renderer/renderer_webkitplatformsupport_impl.cc index 4b05c99..685d642 100644 --- a/content/renderer/renderer_webkitplatformsupport_impl.cc +++ b/content/renderer/renderer_webkitplatformsupport_impl.cc @@ -27,7 +27,6 @@ #include "content/renderer/dom_storage/webstoragenamespace_impl.h" #include "content/renderer/gamepad_shared_memory_reader.h" #include "content/renderer/hyphenator/hyphenator.h" -#include "content/renderer/media/audio_hardware.h" #include "content/renderer/media/media_stream_dependency_factory.h" #include "content/renderer/media/renderer_webaudiodevice_impl.h" #include "content/renderer/render_thread_impl.h" @@ -36,6 +35,7 @@ #include "googleurl/src/gurl.h" #include "ipc/ipc_sync_message_filter.h" #include "media/audio/audio_output_device.h" +#include "media/base/audio_hardware_config.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebBlobRegistry.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebGamepads.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebMediaStreamCenter.h" @@ -555,11 +555,13 @@ bool RendererWebKitPlatformSupportImpl::canAccelerate2dCanvas() { } double RendererWebKitPlatformSupportImpl::audioHardwareSampleRate() { - return GetAudioOutputSampleRate(); + RenderThreadImpl* thread = RenderThreadImpl::current(); + return thread->GetAudioHardwareConfig()->GetOutputSampleRate(); } size_t RendererWebKitPlatformSupportImpl::audioHardwareBufferSize() { - return GetAudioOutputBufferSize(); + RenderThreadImpl* thread = RenderThreadImpl::current(); + return thread->GetAudioHardwareConfig()->GetOutputBufferSize(); } // TODO(crogers): remove deprecated API as soon as WebKit calls new API. diff --git a/content/test/webrtc_audio_device_test.cc b/content/test/webrtc_audio_device_test.cc index 5191f9d..571c4a6 100644 --- a/content/test/webrtc_audio_device_test.cc +++ b/content/test/webrtc_audio_device_test.cc @@ -21,13 +21,13 @@ #include "content/public/common/content_paths.h" #include "content/public/test/mock_resource_context.h" #include "content/public/test/test_browser_thread.h" -#include "content/renderer/media/audio_hardware.h" #include "content/renderer/media/audio_input_message_filter.h" #include "content/renderer/media/audio_message_filter.h" #include "content/renderer/media/webrtc_audio_device_impl.h" #include "content/renderer/render_process.h" #include "content/renderer/render_thread_impl.h" #include "content/renderer/renderer_webkitplatformsupport_impl.h" +#include "media/base/audio_hardware_config.h" #include "net/url_request/url_request_test_util.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -115,7 +115,7 @@ ACTION_P(QuitMessageLoop, loop_or_proxy) { } WebRTCAudioDeviceTest::WebRTCAudioDeviceTest() - : render_thread_(NULL), audio_util_callback_(NULL), + : render_thread_(NULL), audio_hardware_config_(NULL), has_input_devices_(false), has_output_devices_(false) { } @@ -147,7 +147,7 @@ void WebRTCAudioDeviceTest::SetUp() { } void WebRTCAudioDeviceTest::TearDown() { - SetAudioUtilCallback(NULL); + SetAudioHardwareConfig(NULL); // Run any pending cleanup tasks that may have been posted to the main thread. ChildProcess::current()->main_thread()->message_loop()->RunUntilIdle(); @@ -183,11 +183,9 @@ bool WebRTCAudioDeviceTest::Send(IPC::Message* message) { return channel_->Send(message); } -void WebRTCAudioDeviceTest::SetAudioUtilCallback(AudioUtilInterface* callback) { - // Invalidate any potentially cached values since the new callback should - // be used for those queries. - ResetAudioCache(); - audio_util_callback_ = callback; +void WebRTCAudioDeviceTest::SetAudioHardwareConfig( + media::AudioHardwareConfig* hardware_config) { + audio_hardware_config_ = hardware_config; } void WebRTCAudioDeviceTest::InitializeIOThread(const char* thread_name) { @@ -261,25 +259,17 @@ void WebRTCAudioDeviceTest::DestroyChannel() { audio_input_renderer_host_ = NULL; } -void WebRTCAudioDeviceTest::OnGetHardwareSampleRate(int* sample_rate) { - EXPECT_TRUE(audio_util_callback_); - *sample_rate = audio_util_callback_ ? - audio_util_callback_->GetAudioHardwareSampleRate() : 0; -} +void WebRTCAudioDeviceTest::OnGetAudioHardwareConfig( + int* output_buffer_size, int* output_sample_rate, int* input_sample_rate, + media::ChannelLayout* input_channel_layout) { + ASSERT_TRUE(audio_hardware_config_); -void WebRTCAudioDeviceTest::OnGetHardwareInputSampleRate(int* sample_rate) { - EXPECT_TRUE(audio_util_callback_); - *sample_rate = audio_util_callback_ ? - audio_util_callback_->GetAudioInputHardwareSampleRate( - media::AudioManagerBase::kDefaultDeviceId) : 0; -} + *output_buffer_size = audio_hardware_config_->GetOutputBufferSize(); + *output_sample_rate = audio_hardware_config_->GetOutputSampleRate(); -void WebRTCAudioDeviceTest::OnGetHardwareInputChannelLayout( - media::ChannelLayout* layout) { - EXPECT_TRUE(audio_util_callback_); - *layout = !audio_util_callback_ ? media::CHANNEL_LAYOUT_NONE : - audio_util_callback_->GetAudioInputHardwareChannelLayout( - media::AudioManagerBase::kDefaultDeviceId); + // TODO(henrika): add support for all available input devices. + *input_sample_rate = audio_hardware_config_->GetInputSampleRate(); + *input_channel_layout = audio_hardware_config_->GetInputChannelLayout(); } // IPC::Listener implementation. @@ -310,12 +300,8 @@ bool WebRTCAudioDeviceTest::OnMessageReceived(const IPC::Message& message) { bool handled ALLOW_UNUSED = true; bool message_is_ok = true; IPC_BEGIN_MESSAGE_MAP_EX(WebRTCAudioDeviceTest, message, message_is_ok) - IPC_MESSAGE_HANDLER(ViewHostMsg_GetHardwareSampleRate, - OnGetHardwareSampleRate) - IPC_MESSAGE_HANDLER(ViewHostMsg_GetHardwareInputSampleRate, - OnGetHardwareInputSampleRate) - IPC_MESSAGE_HANDLER(ViewHostMsg_GetHardwareInputChannelLayout, - OnGetHardwareInputChannelLayout) + IPC_MESSAGE_HANDLER(ViewHostMsg_GetAudioHardwareConfig, + OnGetAudioHardwareConfig) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP_EX() diff --git a/content/test/webrtc_audio_device_test.h b/content/test/webrtc_audio_device_test.h index b2974c4..2e52e94b 100644 --- a/content/test/webrtc_audio_device_test.h +++ b/content/test/webrtc_audio_device_test.h @@ -14,6 +14,7 @@ #include "content/browser/renderer_host/media/mock_media_observer.h" #include "content/public/renderer/content_renderer_client.h" #include "ipc/ipc_listener.h" +#include "media/base/audio_hardware_config.h" #include "media/base/channel_layout.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/webrtc/common_types.h" @@ -109,18 +110,6 @@ class WebRTCAutoDelete { T* ptr_; }; -// Individual tests can provide an implementation (or mock) of this interface -// when the audio code queries for hardware capabilities on the IO thread. -class AudioUtilInterface { - public: - virtual ~AudioUtilInterface() {} - virtual int GetAudioHardwareSampleRate() = 0; - virtual int GetAudioInputHardwareSampleRate( - const std::string& device_id) = 0; - virtual media::ChannelLayout GetAudioInputHardwareChannelLayout( - const std::string& device_id) = 0; -}; - // Implemented and defined in the cc file. class ReplaceContentClientRenderer; @@ -135,7 +124,7 @@ class WebRTCAudioDeviceTest : public ::testing::Test, public IPC::Listener { // Sends an IPC message to the IO thread channel. bool Send(IPC::Message* message); - void SetAudioUtilCallback(AudioUtilInterface* callback); + void SetAudioHardwareConfig(media::AudioHardwareConfig* hardware_config); protected: void InitializeIOThread(const char* thread_name); @@ -143,9 +132,9 @@ class WebRTCAudioDeviceTest : public ::testing::Test, public IPC::Listener { void CreateChannel(const char* name); void DestroyChannel(); - void OnGetHardwareSampleRate(int* sample_rate); - void OnGetHardwareInputSampleRate(int* sample_rate); - void OnGetHardwareInputChannelLayout(media::ChannelLayout* channels); + void OnGetAudioHardwareConfig(int* output_buffer_size, + int* output_sample_rate, int* input_sample_rate, + media::ChannelLayout* input_channel_layout); // IPC::Listener implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; @@ -177,7 +166,7 @@ class WebRTCAudioDeviceTest : public ::testing::Test, public IPC::Listener { scoped_refptr<AudioRendererHost> audio_render_host_; scoped_refptr<AudioInputRendererHost> audio_input_renderer_host_; - AudioUtilInterface* audio_util_callback_; // Weak reference. + media::AudioHardwareConfig* audio_hardware_config_; // Weak reference. // Initialized on the main test thread that we mark as the UI thread. scoped_ptr<TestBrowserThread> ui_thread_; diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc index f48cf7f..9990389 100644 --- a/media/audio/audio_output_controller.cc +++ b/media/audio/audio_output_controller.cc @@ -10,6 +10,7 @@ #include "base/threading/platform_thread.h" #include "base/time.h" #include "build/build_config.h" +#include "media/audio/audio_util.h" #include "media/audio/shared_memory_util.h" using base::Time; @@ -323,6 +324,10 @@ void AudioOutputController::DoStopCloseAndClearStream() { void AudioOutputController::OnDeviceChange() { DCHECK(message_loop_->BelongsToCurrentThread()); + // TODO(dalecurtis): Notify the renderer side that a device change has + // occurred. Currently querying the hardware information here will lead to + // crashes on OSX. See http://crbug.com/158170. + // Recreate the stream (DoCreate() will first shut down an existing stream). // Exit if we ran into an error. const State original_state = state_; diff --git a/media/audio/audio_output_controller.h b/media/audio/audio_output_controller.h index be6d68c..e8fae22 100644 --- a/media/audio/audio_output_controller.h +++ b/media/audio/audio_output_controller.h @@ -71,6 +71,8 @@ class MEDIA_EXPORT AudioOutputController virtual void OnPlaying(AudioOutputController* controller) = 0; virtual void OnPaused(AudioOutputController* controller) = 0; virtual void OnError(AudioOutputController* controller, int error_code) = 0; + virtual void OnDeviceChange(AudioOutputController* controller, + int new_buffer_size, int new_sample_rate) = 0; protected: virtual ~EventHandler() {} diff --git a/media/audio/audio_output_controller_unittest.cc b/media/audio/audio_output_controller_unittest.cc index 746bc45..944d661 100644 --- a/media/audio/audio_output_controller_unittest.cc +++ b/media/audio/audio_output_controller_unittest.cc @@ -43,7 +43,8 @@ class MockAudioOutputControllerEventHandler MOCK_METHOD1(OnPaused, void(AudioOutputController* controller)); MOCK_METHOD2(OnError, void(AudioOutputController* controller, int error_code)); - + MOCK_METHOD3(OnDeviceChange, void(AudioOutputController* controller, + int new_buffer_size, int new_sample_rate)); private: DISALLOW_COPY_AND_ASSIGN(MockAudioOutputControllerEventHandler); }; diff --git a/media/base/audio_hardware_config.cc b/media/base/audio_hardware_config.cc new file mode 100644 index 0000000..eaacc69 --- /dev/null +++ b/media/base/audio_hardware_config.cc @@ -0,0 +1,53 @@ +// Copyright (c) 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 "media/base/audio_hardware_config.h" + +namespace media { + +AudioHardwareConfig::AudioHardwareConfig( + int output_buffer_size, int output_sample_rate, + int input_sample_rate, ChannelLayout input_channel_layout) + : output_buffer_size_(output_buffer_size), + output_sample_rate_(output_sample_rate), + input_sample_rate_(input_sample_rate), + input_channel_layout_(input_channel_layout) { +} + +AudioHardwareConfig::~AudioHardwareConfig() {} + +int AudioHardwareConfig::GetOutputBufferSize() { + base::AutoLock auto_lock(config_lock_); + return output_buffer_size_; +} + +int AudioHardwareConfig::GetOutputSampleRate() { + base::AutoLock auto_lock(config_lock_); + return output_sample_rate_; +} + +int AudioHardwareConfig::GetInputSampleRate() { + base::AutoLock auto_lock(config_lock_); + return input_sample_rate_; +} + +ChannelLayout AudioHardwareConfig::GetInputChannelLayout() { + base::AutoLock auto_lock(config_lock_); + return input_channel_layout_; +} + +void AudioHardwareConfig::UpdateInputConfig( + int sample_rate, media::ChannelLayout channel_layout) { + base::AutoLock auto_lock(config_lock_); + input_sample_rate_ = sample_rate; + input_channel_layout_ = channel_layout; +} + +void AudioHardwareConfig::UpdateOutputConfig(int buffer_size, int sample_rate) { + base::AutoLock auto_lock(config_lock_); + output_buffer_size_ = buffer_size; + output_sample_rate_ = sample_rate; +} + +} // namespace media diff --git a/media/base/audio_hardware_config.h b/media/base/audio_hardware_config.h new file mode 100644 index 0000000..e61d9ba --- /dev/null +++ b/media/base/audio_hardware_config.h @@ -0,0 +1,50 @@ +// Copyright (c) 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. + +#ifndef MEDIA_BASE_AUDIO_HARDWARE_CONFIG_H_ +#define MEDIA_BASE_AUDIO_HARDWARE_CONFIG_H_ + +#include "base/compiler_specific.h" +#include "base/synchronization/lock.h" +#include "media/base/channel_layout.h" +#include "media/base/media_export.h" + +namespace media { + +// Provides thread safe access to the audio hardware configuration. +class MEDIA_EXPORT AudioHardwareConfig { + public: + AudioHardwareConfig(int output_buffer_size, int output_sample_rate, + int input_sample_rate, + ChannelLayout input_channel_layout); + virtual ~AudioHardwareConfig(); + + // Accessors for the currently cached hardware configuration. Safe to call + // from any thread. + int GetOutputBufferSize(); + int GetOutputSampleRate(); + int GetInputSampleRate(); + ChannelLayout GetInputChannelLayout(); + + // Allows callers to update the cached values for either input or output. The + // values are paired under the assumption that these values will only be set + // after an input or output device change respectively. Safe to call from + // any thread. + void UpdateInputConfig(int sample_rate, media::ChannelLayout channel_layout); + void UpdateOutputConfig(int buffer_size, int sample_rate); + + private: + // Cached values; access is protected by |config_lock_|. + base::Lock config_lock_; + int output_buffer_size_; + int output_sample_rate_; + int input_sample_rate_; + ChannelLayout input_channel_layout_; + + DISALLOW_COPY_AND_ASSIGN(AudioHardwareConfig); +}; + +} // namespace media + +#endif // MEDIA_BASE_AUDIO_HARDWARE_CONFIG_H_ diff --git a/media/base/audio_hardware_config_unittest.cc b/media/base/audio_hardware_config_unittest.cc new file mode 100644 index 0000000..afa2e0d --- /dev/null +++ b/media/base/audio_hardware_config_unittest.cc @@ -0,0 +1,50 @@ +// Copyright (c) 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 "media/base/audio_hardware_config.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +static const int kOutputBufferSize = 2048; +static const int kOutputSampleRate = 48000; +static const int kInputSampleRate = 44100; +static const ChannelLayout kInputChannelLayout = CHANNEL_LAYOUT_STEREO; + +TEST(AudioHardwareConfig, Getters) { + AudioHardwareConfig fake_config( + kOutputBufferSize, kOutputSampleRate, kInputSampleRate, + kInputChannelLayout); + + EXPECT_EQ(kOutputBufferSize, fake_config.GetOutputBufferSize()); + EXPECT_EQ(kOutputSampleRate, fake_config.GetOutputSampleRate()); + EXPECT_EQ(kInputSampleRate, fake_config.GetInputSampleRate()); + EXPECT_EQ(kInputChannelLayout, fake_config.GetInputChannelLayout()); +} + +TEST(AudioHardwareConfig, Setters) { + AudioHardwareConfig fake_config( + kOutputBufferSize, kOutputSampleRate, kInputSampleRate, + kInputChannelLayout); + + // Verify output parameters. + const int kNewOutputBufferSize = kOutputBufferSize * 2; + const int kNewOutputSampleRate = kOutputSampleRate * 2; + EXPECT_NE(kNewOutputBufferSize, fake_config.GetOutputBufferSize()); + EXPECT_NE(kNewOutputSampleRate, fake_config.GetOutputSampleRate()); + fake_config.UpdateOutputConfig(kNewOutputBufferSize, kNewOutputSampleRate); + EXPECT_EQ(kNewOutputBufferSize, fake_config.GetOutputBufferSize()); + EXPECT_EQ(kNewOutputSampleRate, fake_config.GetOutputSampleRate()); + + // Verify input parameters. + const int kNewInputSampleRate = kInputSampleRate * 2; + const ChannelLayout kNewInputChannelLayout = CHANNEL_LAYOUT_MONO; + EXPECT_NE(kNewInputSampleRate, fake_config.GetInputSampleRate()); + EXPECT_NE(kNewInputChannelLayout, fake_config.GetInputChannelLayout()); + fake_config.UpdateInputConfig(kNewInputSampleRate, kNewInputChannelLayout); + EXPECT_EQ(kNewInputSampleRate, fake_config.GetInputSampleRate()); + EXPECT_EQ(kNewInputChannelLayout, fake_config.GetInputChannelLayout()); +} + +} // namespace content diff --git a/media/media.gyp b/media/media.gyp index 82a297a..cc8be41 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -186,6 +186,8 @@ 'base/audio_decoder_config.h', 'base/audio_fifo.cc', 'base/audio_fifo.h', + 'base/audio_hardware_config.cc', + 'base/audio_hardware_config.h', 'base/audio_pull_fifo.cc', 'base/audio_pull_fifo.h', 'base/audio_renderer.cc', @@ -771,6 +773,7 @@ 'base/audio_bus_unittest.cc', 'base/audio_converter_unittest.cc', 'base/audio_fifo_unittest.cc', + 'base/audio_hardware_config_unittest.cc', 'base/audio_pull_fifo_unittest.cc', 'base/audio_renderer_mixer_input_unittest.cc', 'base/audio_renderer_mixer_unittest.cc', |