diff options
34 files changed, 493 insertions, 340 deletions
diff --git a/content/browser/renderer_host/media/audio_input_device_manager.cc b/content/browser/renderer_host/media/audio_input_device_manager.cc index 14bd470..60e9be5 100644 --- a/content/browser/renderer_host/media/audio_input_device_manager.cc +++ b/content/browser/renderer_host/media/audio_input_device_manager.cc @@ -12,7 +12,7 @@ #include "media/audio/audio_device_name.h" #include "media/audio/audio_input_ipc.h" #include "media/audio/audio_manager_base.h" -#include "media/audio/audio_util.h" +#include "media/audio/audio_parameters.h" #include "media/base/channel_layout.h" namespace content { @@ -158,15 +158,13 @@ void AudioInputDeviceManager::EnumerateOnDeviceThread( it != device_names.end(); ++it) { // Get the preferred sample rate and channel configuration for the // current audio device. - int sample_rate = - media::GetAudioInputHardwareSampleRate(it->unique_id); - media::ChannelLayout channel_layout = - media::GetAudioInputHardwareChannelLayout(it->unique_id); + media::AudioParameters default_params = + audio_manager_->GetInputStreamParameters(it->unique_id); // Add device information to device vector. devices->push_back(StreamDeviceInfo( - stream_type, it->device_name, it->unique_id, sample_rate, - channel_layout, false)); + stream_type, it->device_name, it->unique_id, + default_params.sample_rate(), default_params.channel_layout(), false)); } // Return the device list through the listener by posting a task on diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc index 4a0e1ca..3adfaf4 100644 --- a/content/browser/renderer_host/media/media_stream_manager.cc +++ b/content/browser/renderer_host/media/media_stream_manager.cc @@ -25,7 +25,7 @@ #include "content/public/common/media_stream_request.h" #include "googleurl/src/gurl.h" #include "media/audio/audio_manager_base.h" -#include "media/audio/audio_util.h" +#include "media/audio/audio_parameters.h" #include "media/base/channel_layout.h" #if defined(OS_WIN) @@ -852,7 +852,9 @@ void MediaStreamManager::DevicesAccepted(const std::string& label, // mirroring, we don't go through EnumerateDevices where these are usually // initialized. if (device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) { - int sample_rate = media::GetAudioHardwareSampleRate(); + const media::AudioParameters parameters = + audio_manager_->GetDefaultOutputStreamParameters(); + int sample_rate = parameters.sample_rate(); // If we weren't able to get the native sampling rate, it most likely // means the system did not have an output device, but for mirroring we // still want to startup the audio engine, so set reasonable defaults. diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc index e94286a..608c7ed 100644 --- a/content/browser/renderer_host/render_message_filter.cc +++ b/content/browser/renderer_host/render_message_filter.cc @@ -16,6 +16,7 @@ #include "base/threading/thread.h" #include "base/threading/worker_pool.h" #include "base/utf_string_conversions.h" +#include "content/browser/browser_main_loop.h" #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/dom_storage/dom_storage_context_impl.h" #include "content/browser/dom_storage/session_storage_namespace_impl.h" @@ -45,8 +46,9 @@ #include "content/public/common/url_constants.h" #include "ipc/ipc_channel_handle.h" #include "ipc/ipc_platform_file.h" +#include "media/audio/audio_manager.h" #include "media/audio/audio_manager_base.h" -#include "media/audio/audio_util.h" +#include "media/audio/audio_parameters.h" #include "media/base/media_log_event.h" #include "net/base/io_buffer.h" #include "net/base/keygen_handler.h" @@ -776,17 +778,22 @@ void RenderMessageFilter::OnGetCPUUsage(int* cpu_usage) { *cpu_usage = cpu_usage_; } +// TODO(xians): refactor the API to return input and output AudioParameters. 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(); + media::AudioManager* audio_manager = BrowserMainLoop::GetAudioManager(); + const media::AudioParameters output_parameters = + audio_manager->GetDefaultOutputStreamParameters(); + *output_buffer_size = output_parameters.frames_per_buffer(); + *output_sample_rate = output_parameters.sample_rate(); // TODO(henrika): add support for all available input devices. - *input_sample_rate = media::GetAudioInputHardwareSampleRate( - media::AudioManagerBase::kDefaultDeviceId); - *input_channel_layout = media::GetAudioInputHardwareChannelLayout( - media::AudioManagerBase::kDefaultDeviceId); + const media::AudioParameters input_parameters = + audio_manager->GetInputStreamParameters( + media::AudioManagerBase::kDefaultDeviceId); + *input_sample_rate = input_parameters.sample_rate(); + *input_channel_layout = input_parameters.channel_layout(); } void RenderMessageFilter::OnGetMonitorColorProfile(std::vector<char>* profile) { diff --git a/content/renderer/media/webrtc_audio_device_unittest.cc b/content/renderer/media/webrtc_audio_device_unittest.cc index 42e9c6d..e04eafc 100644 --- a/content/renderer/media/webrtc_audio_device_unittest.cc +++ b/content/renderer/media/webrtc_audio_device_unittest.cc @@ -10,7 +10,6 @@ #include "content/renderer/render_thread_impl.h" #include "content/test/webrtc_audio_device_test.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" @@ -31,13 +30,16 @@ namespace { const int kRenderViewId = 1; -scoped_ptr<media::AudioHardwareConfig> CreateRealHardwareConfig() { +scoped_ptr<media::AudioHardwareConfig> CreateRealHardwareConfig( + media::AudioManager* manager) { + const media::AudioParameters output_parameters = + manager->GetDefaultOutputStreamParameters(); + const media::AudioParameters input_parameters = + manager->GetInputStreamParameters( + media::AudioManagerBase::kDefaultDeviceId); return make_scoped_ptr(new media::AudioHardwareConfig( - media::GetAudioHardwareBufferSize(), media::GetAudioHardwareSampleRate(), - media::GetAudioInputHardwareSampleRate( - media::AudioManagerBase::kDefaultDeviceId), - media::GetAudioInputHardwareChannelLayout( - media::AudioManagerBase::kDefaultDeviceId))); + output_parameters.frames_per_buffer(), output_parameters.sample_rate(), + input_parameters.sample_rate(), input_parameters.channel_layout())); } // Return true if at least one element in the array matches |value|. @@ -250,7 +252,8 @@ TEST_F(WebRTCAudioDeviceTest, DISABLED_StartPlayout) { return; } - scoped_ptr<media::AudioHardwareConfig> config = CreateRealHardwareConfig(); + scoped_ptr<media::AudioHardwareConfig> config = + CreateRealHardwareConfig(audio_manager_.get()); SetAudioHardwareConfig(config.get()); if (!HardwareSampleRatesAreValid()) @@ -336,7 +339,8 @@ TEST_F(WebRTCAudioDeviceTest, MAYBE_StartRecording) { return; } - scoped_ptr<media::AudioHardwareConfig> config = CreateRealHardwareConfig(); + scoped_ptr<media::AudioHardwareConfig> config = + CreateRealHardwareConfig(audio_manager_.get()); SetAudioHardwareConfig(config.get()); if (!HardwareSampleRatesAreValid()) @@ -409,7 +413,8 @@ TEST_F(WebRTCAudioDeviceTest, DISABLED_PlayLocalFile) { std::string file_path( GetTestDataPath(FILE_PATH_LITERAL("speechmusic_mono_16kHz.pcm"))); - scoped_ptr<media::AudioHardwareConfig> config = CreateRealHardwareConfig(); + scoped_ptr<media::AudioHardwareConfig> config = + CreateRealHardwareConfig(audio_manager_.get()); SetAudioHardwareConfig(config.get()); if (!HardwareSampleRatesAreValid()) @@ -486,7 +491,8 @@ TEST_F(WebRTCAudioDeviceTest, MAYBE_FullDuplexAudioWithAGC) { return; } - scoped_ptr<media::AudioHardwareConfig> config = CreateRealHardwareConfig(); + scoped_ptr<media::AudioHardwareConfig> config = + CreateRealHardwareConfig(audio_manager_.get()); SetAudioHardwareConfig(config.get()); if (!HardwareSampleRatesAreValid()) diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc index 93296d7..80e1a27 100644 --- a/media/audio/android/audio_manager_android.cc +++ b/media/audio/android/audio_manager_android.cc @@ -8,8 +8,9 @@ #include "media/audio/android/opensles_input.h" #include "media/audio/android/opensles_output.h" #include "media/audio/audio_manager.h" -#include "media/audio/audio_util.h" +#include "media/audio/audio_parameters.h" #include "media/audio/fake_audio_input_stream.h" +#include "media/base/channel_layout.h" namespace media { @@ -43,20 +44,16 @@ void AudioManagerAndroid::GetAudioInputDeviceNames( media::AudioDeviceName(kDefaultDeviceName, kDefaultDeviceId)); } -AudioParameters -AudioManagerAndroid::GetPreferredLowLatencyOutputStreamParameters( - const AudioParameters& input_params) { - // TODO(leozwang): Android defines the minimal buffer size requirment - // we should follow it. From Android 4.1, a new audio low latency api - // set was introduced and is under development, we want to take advantage - // of it. - int buffer_size = GetAudioHardwareBufferSize(); - if (input_params.frames_per_buffer() < buffer_size) - buffer_size = input_params.frames_per_buffer(); - +AudioParameters AudioManagerAndroid::GetInputStreamParameters( + const std::string& device_id) { + // TODO(xians): figure out the right input sample rate and buffer size to + // achieve the best audio performance for Android devices. + // TODO(xians): query the native channel layout for the specific device. + static const int kDefaultSampleRate = 16000; + static const int kDefaultBufferSize = 1024; return AudioParameters( - AudioParameters::AUDIO_PCM_LOW_LATENCY, input_params.channel_layout(), - input_params.sample_rate(), 16, buffer_size); + AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, + kDefaultSampleRate, 16, kDefaultBufferSize); } AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream( @@ -83,4 +80,35 @@ AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream( return new OpenSLESInputStream(this, params); } +AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters( + const AudioParameters& input_params) { + // TODO(xians): figure out the right output sample rate and sample rate to + // achieve the best audio performance for Android devices. + static const int kDefaultSampleRate = 16000; + static const int kDefaultBufferSize = 1024; + + ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; + int sample_rate = kDefaultSampleRate; + int buffer_size = kDefaultBufferSize; + int bits_per_sample = 16; + int input_channels = 0; + if (input_params.IsValid()) { + // Use the client's input parameters if they are valid. + sample_rate = input_params.sample_rate(); + bits_per_sample = input_params.bits_per_sample(); + channel_layout = input_params.channel_layout(); + input_channels = input_params.input_channels(); + + // TODO(leozwang): Android defines the minimal buffer size requirment + // we should follow it. From Android 4.1, a new audio low latency api + // set was introduced and is under development, we want to take advantage + // of it. + buffer_size = std::min(buffer_size, input_params.frames_per_buffer()); + } + + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, + sample_rate, bits_per_sample, buffer_size); +} + } // namespace media diff --git a/media/audio/android/audio_manager_android.h b/media/audio/android/audio_manager_android.h index 2c8f7ac..fbc05d2 100644 --- a/media/audio/android/audio_manager_android.h +++ b/media/audio/android/audio_manager_android.h @@ -19,6 +19,8 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase { virtual bool HasAudioInputDevices() OVERRIDE; virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names) OVERRIDE; + virtual AudioParameters GetInputStreamParameters( + const std::string& device_id) OVERRIDE; // Implementation of AudioManagerBase. virtual AudioOutputStream* MakeLinearOutputStream( @@ -29,12 +31,13 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase { const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeLowLatencyInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; - virtual AudioParameters GetPreferredLowLatencyOutputStreamParameters( - const AudioParameters& input_params) OVERRIDE; protected: virtual ~AudioManagerAndroid(); + virtual AudioParameters GetPreferredOutputStreamParameters( + const AudioParameters& input_params) OVERRIDE; + private: DISALLOW_COPY_AND_ASSIGN(AudioManagerAndroid); }; diff --git a/media/audio/audio_input_volume_unittest.cc b/media/audio/audio_input_volume_unittest.cc index 8f754cc..2f3bda9 100644 --- a/media/audio/audio_input_volume_unittest.cc +++ b/media/audio/audio_input_volume_unittest.cc @@ -51,29 +51,10 @@ class AudioInputVolumeTest : public ::testing::Test { } AudioInputStream* CreateAndOpenStream(const std::string& device_id) { - AudioParameters::Format format = AudioParameters::AUDIO_PCM_LOW_LATENCY; - ChannelLayout channel_layout = - media::GetAudioInputHardwareChannelLayout(device_id); - int bits_per_sample = 16; - int sample_rate = - static_cast<int>(media::GetAudioInputHardwareSampleRate(device_id)); - int samples_per_packet = 0; -#if defined(OS_MACOSX) - samples_per_packet = (sample_rate / 100); -#elif defined(OS_LINUX) || defined(OS_OPENBSD) - samples_per_packet = (sample_rate / 100); -#elif defined(OS_WIN) - if (sample_rate == 44100) - samples_per_packet = 448; - else - samples_per_packet = (sample_rate / 100); -#else -#error Unsupported platform -#endif + const AudioParameters& params = + audio_manager_->GetInputStreamParameters(device_id); AudioInputStream* ais = audio_manager_->MakeAudioInputStream( - AudioParameters(format, channel_layout, sample_rate, bits_per_sample, - samples_per_packet), - device_id); + params, device_id); EXPECT_TRUE(NULL != ais); #if defined(OS_LINUX) || defined(OS_OPENBSD) diff --git a/media/audio/audio_low_latency_input_output_unittest.cc b/media/audio/audio_low_latency_input_output_unittest.cc index 8c05b12..a13d3ba 100644 --- a/media/audio/audio_low_latency_input_output_unittest.cc +++ b/media/audio/audio_low_latency_input_output_unittest.cc @@ -14,7 +14,6 @@ #include "build/build_config.h" #include "media/audio/audio_io.h" #include "media/audio/audio_manager_base.h" -#include "media/audio/audio_util.h" #include "media/base/seekable_buffer.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -286,14 +285,10 @@ class AudioInputStreamTraits { public: typedef AudioInputStream StreamType; - static int HardwareSampleRate() { - return static_cast<int>(media::GetAudioInputHardwareSampleRate( - AudioManagerBase::kDefaultDeviceId)); - } - - // TODO(henrika): add support for GetAudioInputHardwareBufferSize in media. - static int HardwareBufferSize() { - return static_cast<int>(media::GetAudioHardwareBufferSize()); + static AudioParameters GetDefaultAudioStreamParameters( + AudioManager* audio_manager) { + return audio_manager->GetInputStreamParameters( + AudioManagerBase::kDefaultDeviceId); } static StreamType* CreateStream(AudioManager* audio_manager, @@ -307,12 +302,9 @@ class AudioOutputStreamTraits { public: typedef AudioOutputStream StreamType; - static int HardwareSampleRate() { - return static_cast<int>(media::GetAudioHardwareSampleRate()); - } - - static int HardwareBufferSize() { - return static_cast<int>(media::GetAudioHardwareBufferSize()); + static AudioParameters GetDefaultAudioStreamParameters( + AudioManager* audio_manager) { + return audio_manager->GetDefaultOutputStreamParameters(); } static StreamType* CreateStream(AudioManager* audio_manager, @@ -339,11 +331,13 @@ class StreamWrapper { #endif bits_per_sample_(16) { // Use the preferred sample rate. - sample_rate_ = StreamTraits::HardwareSampleRate(); + const AudioParameters& params = + StreamTraits::GetDefaultAudioStreamParameters(audio_manager_); + sample_rate_ = params.sample_rate(); // Use the preferred buffer size. Note that the input side uses the same // size as the output side in this implementation. - samples_per_packet_ = StreamTraits::HardwareBufferSize(); + samples_per_packet_ = params.frames_per_buffer(); } virtual ~StreamWrapper() {} diff --git a/media/audio/audio_manager.h b/media/audio/audio_manager.h index f169b41..fbc3c7c 100644 --- a/media/audio/audio_manager.h +++ b/media/audio/audio_manager.h @@ -120,6 +120,18 @@ class MEDIA_EXPORT AudioManager { virtual void RemoveOutputDeviceChangeListener( AudioDeviceListener* listener) = 0; + // Returns the default output hardware audio parameters for opening output + // streams. It is a convenience interface to + // AudioManagerBase::GetPreferredOutputStreamParameters and each AudioManager + // does not need their own implementation to this interface. + virtual AudioParameters GetDefaultOutputStreamParameters() = 0; + + // Returns the input hardware audio parameters of the specific device + // for opening input streams. Each AudioManager needs to implement their own + // version of this interface. + virtual AudioParameters GetInputStreamParameters( + const std::string& device_id) = 0; + protected: AudioManager(); diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc index 662d39a..2a65f82 100644 --- a/media/audio/audio_manager_base.cc +++ b/media/audio/audio_manager_base.cc @@ -182,7 +182,7 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( // as our input parameters. AudioParameters output_params = params; if (use_audio_output_resampler) { - output_params = GetPreferredLowLatencyOutputStreamParameters(params); + output_params = GetPreferredOutputStreamParameters(params); // Ensure we only pass on valid output parameters. if (!output_params.IsValid()) { @@ -317,22 +317,6 @@ void AudioManagerBase::ShutdownOnAudioThread() { #endif // defined(OS_IOS) } -AudioParameters AudioManagerBase::GetPreferredLowLatencyOutputStreamParameters( - const AudioParameters& input_params) { -#if defined(OS_IOS) - // IOS implements audio input only. - NOTIMPLEMENTED(); - return AudioParameters(); -#else - // TODO(dalecurtis): This should include bits per channel and channel layout - // eventually. - return AudioParameters( - AudioParameters::AUDIO_PCM_LOW_LATENCY, - input_params.channel_layout(), input_params.input_channels(), - GetAudioHardwareSampleRate(), 16, GetAudioHardwareBufferSize()); -#endif // defined(OS_IOS) -} - void AudioManagerBase::AddOutputDeviceChangeListener( AudioDeviceListener* listener) { DCHECK(message_loop_->BelongsToCurrentThread()); @@ -351,4 +335,14 @@ void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() { FOR_EACH_OBSERVER(AudioDeviceListener, output_listeners_, OnDeviceChange()); } +AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() { + return GetPreferredOutputStreamParameters(AudioParameters()); +} + +AudioParameters AudioManagerBase::GetInputStreamParameters( + const std::string& device_id) { + NOTREACHED(); + return AudioParameters(); +} + } // namespace media diff --git a/media/audio/audio_manager_base.h b/media/audio/audio_manager_base.h index 22140cb..2275f9b 100644 --- a/media/audio/audio_manager_base.h +++ b/media/audio/audio_manager_base.h @@ -83,21 +83,16 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager { virtual AudioInputStream* MakeLowLatencyInputStream( const AudioParameters& params, const std::string& device_id) = 0; - // Returns the preferred hardware audio output parameters for opening output - // streams in the |AUDIO_PCM_LOW_LATENCY| format. - // TODO(dalecurtis): Retrieve the |channel_layout| value from hardware instead - // of accepting the value. - // TODO(dalecurtis): Each AudioManager should implement their own version, see - // http://crbug.com/137326 - virtual AudioParameters GetPreferredLowLatencyOutputStreamParameters( - const AudioParameters& input_params); - // Listeners will be notified on the AudioManager::GetMessageLoop() loop. virtual void AddOutputDeviceChangeListener( AudioDeviceListener* listener) OVERRIDE; virtual void RemoveOutputDeviceChangeListener( AudioDeviceListener* listener) OVERRIDE; + virtual AudioParameters GetDefaultOutputStreamParameters() OVERRIDE; + virtual AudioParameters GetInputStreamParameters( + const std::string& device_id) OVERRIDE; + protected: AudioManagerBase(); @@ -121,6 +116,14 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager { // thread. void NotifyAllOutputDeviceChangeListeners(); + // Returns the preferred hardware audio output parameters for opening output + // streams. If the users inject a valid |input_params|, each AudioManager + // will decide if they should return the values from |input_params| or the + // default hardware values. If the |input_params| is invalid, it will return + // the default hardware audio parameters. + virtual AudioParameters GetPreferredOutputStreamParameters( + const AudioParameters& input_params) = 0; + // Map of cached AudioOutputDispatcher instances. Must only be touched // from the audio thread (no locking). AudioOutputDispatchersMap output_dispatchers_; diff --git a/media/audio/audio_output_proxy_unittest.cc b/media/audio/audio_output_proxy_unittest.cc index 880e996..6c4870a 100644 --- a/media/audio/audio_output_proxy_unittest.cc +++ b/media/audio/audio_output_proxy_unittest.cc @@ -117,6 +117,8 @@ class MockAudioManager : public AudioManagerBase { const AudioParameters& params, const std::string& device_id)); MOCK_METHOD2(MakeLowLatencyInputStream, AudioInputStream*( const AudioParameters& params, const std::string& device_id)); + MOCK_METHOD1(GetPreferredOutputStreamParameters, AudioParameters( + const AudioParameters& params)); }; class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback { diff --git a/media/audio/audio_util.cc b/media/audio/audio_util.cc index 0c8b96c..f88478f 100644 --- a/media/audio/audio_util.cc +++ b/media/audio/audio_util.cc @@ -108,124 +108,6 @@ bool AdjustVolume(void* buf, return false; } -int GetAudioHardwareSampleRate() { -#if defined(OS_MACOSX) - // Hardware sample-rate on the Mac can be configured, so we must query. - return AUAudioOutputStream::HardwareSampleRate(); -#elif defined(OS_WIN) - if (!CoreAudioUtil::IsSupported()) { - // Fall back to Windows Wave implementation on Windows XP or lower - // and use 48kHz as default input sample rate. - return 48000; - } - - // TODO(crogers): tune this rate for best possible WebAudio performance. - // WebRTC works well at 48kHz and a buffer size of 480 samples will be used - // for this case. Note that exclusive mode is experimental. - const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); - if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { - // This sample rate will be combined with a buffer size of 256 samples - // (see GetAudioHardwareBufferSize()), which corresponds to an output - // delay of ~5.33ms. - return 48000; - } - - // Hardware sample-rate on Windows can be configured, so we must query. - // TODO(henrika): improve possibility to specify an audio endpoint. - // Use the default device (same as for Wave) for now to be compatible. - return WASAPIAudioOutputStream::HardwareSampleRate(); -#elif defined(OS_ANDROID) - // TODO(leozwang): return native sampling rate on Android. - return 16000; -#else - return 48000; -#endif -} - -int GetAudioInputHardwareSampleRate(const std::string& device_id) { - // TODO(henrika): add support for device selection on all platforms. - // Only exists on Windows today. -#if defined(OS_MACOSX) - return AUAudioInputStream::HardwareSampleRate(); -#elif defined(OS_WIN) - if (!CoreAudioUtil::IsSupported()) { - return 48000; - } - return WASAPIAudioInputStream::HardwareSampleRate(device_id); -#elif defined(OS_ANDROID) - return 16000; -#else - // Hardware for Linux is nearly always 48KHz. - // TODO(crogers) : return correct value in rare non-48KHz cases. - return 48000; -#endif -} - -size_t GetAudioHardwareBufferSize() { - int user_buffer_size = GetUserBufferSize(); - if (user_buffer_size) - return user_buffer_size; - - // The sizes here were determined by experimentation and are roughly - // the lowest value (for low latency) that still allowed glitch-free - // audio under high loads. - // - // For Mac OS X and Windows the chromium audio backend uses a low-latency - // Core Audio API, so a low buffer size is possible. For Linux, further - // tuning may be needed. -#if defined(OS_MACOSX) - return 128; -#elif defined(OS_WIN) - // TODO(henrika): resolve conflict with GetUserBufferSize(). - // If the user tries to set a buffer size using GetUserBufferSize() it will - // most likely fail since only the native/perfect buffer size is allowed. - - // Buffer size to use when a proper size can't be determined from the system. - static const int kFallbackBufferSize = 2048; - - if (!CoreAudioUtil::IsSupported()) { - // Fall back to Windows Wave implementation on Windows XP or lower - // and assume 48kHz as default sample rate. - return kFallbackBufferSize; - } - - // TODO(crogers): tune this size to best possible WebAudio performance. - // WebRTC always uses 10ms for Windows and does not call this method. - // Note that exclusive mode is experimental. - const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); - if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { - return 256; - } - - AudioParameters params; - HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(eRender, eConsole, - ¶ms); - return FAILED(hr) ? kFallbackBufferSize : params.frames_per_buffer(); -#elif defined(OS_LINUX) - return 512; -#else - return 2048; -#endif -} - -ChannelLayout GetAudioInputHardwareChannelLayout(const std::string& device_id) { - // TODO(henrika): add support for device selection on all platforms. - // Only exists on Windows today. -#if defined(OS_MACOSX) - return CHANNEL_LAYOUT_MONO; -#elif defined(OS_WIN) - if (!CoreAudioUtil::IsSupported()) { - // Fall back to Windows Wave implementation on Windows XP or lower and - // use stereo by default. - return CHANNEL_LAYOUT_STEREO; - } - return WASAPIAudioInputStream::HardwareChannelCount(device_id) == 1 ? - CHANNEL_LAYOUT_MONO : CHANNEL_LAYOUT_STEREO; -#else - return CHANNEL_LAYOUT_STEREO; -#endif -} - // Computes a buffer size based on the given |sample_rate|. Must be used in // conjunction with AUDIO_PCM_LINEAR. size_t GetHighLatencyOutputBufferSize(int sample_rate) { diff --git a/media/audio/audio_util.h b/media/audio/audio_util.h index 6067b21..0076b34 100644 --- a/media/audio/audio_util.h +++ b/media/audio/audio_util.h @@ -39,22 +39,6 @@ MEDIA_EXPORT bool AdjustVolume(void* buf, int bytes_per_sample, float volume); -// Returns the default audio output hardware sample-rate. -MEDIA_EXPORT int GetAudioHardwareSampleRate(); - -// Returns the audio input hardware sample-rate for the specified device. -MEDIA_EXPORT int GetAudioInputHardwareSampleRate( - const std::string& device_id); - -// Returns the optimal low-latency buffer size for the audio hardware. -// This is the smallest buffer size the system can comfortably render -// at without glitches. The buffer size is in sample-frames. -MEDIA_EXPORT size_t GetAudioHardwareBufferSize(); - -// Returns the channel layout for the specified audio input device. -MEDIA_EXPORT ChannelLayout GetAudioInputHardwareChannelLayout( - const std::string& device_id); - // Computes a buffer size based on the given |sample_rate|. Must be used in // conjunction with AUDIO_PCM_LINEAR. MEDIA_EXPORT size_t GetHighLatencyOutputBufferSize(int sample_rate); diff --git a/media/audio/cras/audio_manager_cras.cc b/media/audio/cras/audio_manager_cras.cc index 3401cc5..977fba9 100644 --- a/media/audio/cras/audio_manager_cras.cc +++ b/media/audio/cras/audio_manager_cras.cc @@ -10,15 +10,18 @@ #include "base/nix/xdg_util.h" #include "base/process_util.h" #include "base/stl_util.h" -#include "media/audio/audio_util.h" #include "media/audio/cras/cras_input.h" #include "media/audio/cras/cras_output.h" +#include "media/base/channel_layout.h" namespace media { // Maximum number of output streams that can be open simultaneously. static const int kMaxOutputStreams = 50; +// Default sample rate for input and output streams. +static const int kDefaultSampleRate = 48000; + static const char kCrasAutomaticDeviceName[] = "Automatic"; static const char kCrasAutomaticDeviceId[] = "automatic"; @@ -49,6 +52,15 @@ void AudioManagerCras::GetAudioInputDeviceNames( return; } +AudioParameters AudioManagerCras::GetInputStreamParameters( + const std::string& device_id) { + static const int kDefaultInputBufferSize = 1024; + + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, + kDefaultSampleRate, 16, kDefaultInputBufferSize); +} + void AudioManagerCras::GetCrasAudioInputDevices( media::AudioDeviceNames* device_names) { // Cras will route audio from a proper physical device automatically. @@ -80,6 +92,28 @@ AudioInputStream* AudioManagerCras::MakeLowLatencyInputStream( return MakeInputStream(params, device_id); } +AudioParameters AudioManagerCras::GetPreferredOutputStreamParameters( + const AudioParameters& input_params) { + static const int kDefaultOutputBufferSize = 512; + + ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; + int sample_rate = kDefaultSampleRate; + int buffer_size = kDefaultOutputBufferSize; + int bits_per_sample = 16; + int input_channels = 0; + if (input_params.IsValid()) { + sample_rate = input_params.sample_rate(); + bits_per_sample = input_params.bits_per_sample(); + channel_layout = input_params.channel_layout(); + input_channels = input_params.input_channels(); + buffer_size = input_params.frames_per_buffer(); + } + + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, + sample_rate, bits_per_sample, buffer_size, input_channels); +} + AudioOutputStream* AudioManagerCras::MakeOutputStream( const AudioParameters& params) { return new CrasOutputStream(params, this); @@ -90,13 +124,4 @@ AudioInputStream* AudioManagerCras::MakeInputStream( return new CrasInputStream(params, this); } -AudioParameters AudioManagerCras::GetPreferredLowLatencyOutputStreamParameters( - const AudioParameters& input_params) { - // TODO(dalecurtis): This should include bits per channel and channel layout - // eventually. - return AudioParameters( - AudioParameters::AUDIO_PCM_LOW_LATENCY, input_params.channel_layout(), - input_params.sample_rate(), 16, input_params.frames_per_buffer()); -} - } // namespace media diff --git a/media/audio/cras/audio_manager_cras.h b/media/audio/cras/audio_manager_cras.h index e84f47f..2c38c8e 100644 --- a/media/audio/cras/audio_manager_cras.h +++ b/media/audio/cras/audio_manager_cras.h @@ -23,6 +23,8 @@ class MEDIA_EXPORT AudioManagerCras : public AudioManagerBase { virtual void ShowAudioInputSettings() OVERRIDE; virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names) OVERRIDE; + virtual AudioParameters GetInputStreamParameters( + const std::string& device_id) OVERRIDE; // AudioManagerBase implementation. virtual AudioOutputStream* MakeLinearOutputStream( @@ -33,12 +35,13 @@ class MEDIA_EXPORT AudioManagerCras : public AudioManagerBase { const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeLowLatencyInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; - virtual AudioParameters GetPreferredLowLatencyOutputStreamParameters( - const AudioParameters& input_params) OVERRIDE; protected: virtual ~AudioManagerCras(); + virtual AudioParameters GetPreferredOutputStreamParameters( + const AudioParameters& input_params) OVERRIDE; + private: // Gets a list of available cras input devices. void GetCrasAudioInputDevices(media::AudioDeviceNames* device_names); diff --git a/media/audio/ios/audio_manager_ios.h b/media/audio/ios/audio_manager_ios.h index 34a85fc..e1fd5de 100644 --- a/media/audio/ios/audio_manager_ios.h +++ b/media/audio/ios/audio_manager_ios.h @@ -25,6 +25,8 @@ class MEDIA_EXPORT AudioManagerIOS : public AudioManagerBase { const AudioParameters& params) OVERRIDE; virtual AudioInputStream* MakeAudioInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; + virtual AudioParameters GetInputStreamParameters( + const std::string& device_id) OVERRIDE; // Implementation of AudioManagerBase. virtual AudioOutputStream* MakeLinearOutputStream( @@ -41,6 +43,9 @@ class MEDIA_EXPORT AudioManagerIOS : public AudioManagerBase { protected: virtual ~AudioManagerIOS(); + virtual AudioParameters GetPreferredOutputStreamParameters( + const AudioParameters& input_params) OVERRIDE; + private: DISALLOW_COPY_AND_ASSIGN(AudioManagerIOS); }; diff --git a/media/audio/ios/audio_manager_ios.mm b/media/audio/ios/audio_manager_ios.mm index 8949b1c..00b8d79 100644 --- a/media/audio/ios/audio_manager_ios.mm +++ b/media/audio/ios/audio_manager_ios.mm @@ -8,9 +8,11 @@ #import <AVFoundation/AVFoundation.h> #include "base/sys_info.h" +#include "media/audio/audio_parameters.h" #include "media/audio/fake_audio_input_stream.h" #include "media/audio/ios/audio_session_util_ios.h" #include "media/audio/mac/audio_input_mac.h" +#include "media/base/channel_layout.h" #include "media/base/limits.h" namespace media { @@ -47,6 +49,18 @@ bool AudioManagerIOS::HasAudioInputDevices() { return error == kAudioSessionNoError ? audio_input_is_available : false; } +AudioParameters AudioManagerIOS::GetInputStreamParameters( + const std::string& device_id) { + // TODO(xians): figure out the right input sample rate and buffer size to + // achieve the best audio performance for iOS devices. + // TODO(xians): query the native channel layout for the specific device. + static const int kDefaultSampleRate = 48000; + static const int kDefaultBufferSize = 2048; + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, + kDefaultSampleRate, 16, kDefaultBufferSize); +} + AudioOutputStream* AudioManagerIOS::MakeAudioOutputStream( const AudioParameters& params) { NOTIMPLEMENTED(); // Only input is supported on iOS. @@ -90,6 +104,22 @@ AudioInputStream* AudioManagerIOS::MakeLowLatencyInputStream( return MakeAudioInputStream(params, device_id); } + +AudioParameters AudioManagerIOS::GetPreferredOutputStreamParameters( + const AudioParameters& input_params) { + // TODO(xians): handle the case when input_params is valid. + // TODO(xians): figure out the right output sample rate and sample rate to + // achieve the best audio performance for iOS devices. + static const int kDefaultSampleRate = 48000; + static const int kDefaultBufferSize = 2048; + if (input_params.IsValid()) { + NOTREACHED(); + } + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, + kDefaultSampleRate, 16, kDefaultBufferSize); +} + // Called by the stream when it has been released by calling Close(). void AudioManagerIOS::ReleaseOutputStream(AudioOutputStream* stream) { NOTIMPLEMENTED(); // Only input is supported on iOS. diff --git a/media/audio/linux/audio_manager_linux.cc b/media/audio/linux/audio_manager_linux.cc index fa86125..d591cb2 100644 --- a/media/audio/linux/audio_manager_linux.cc +++ b/media/audio/linux/audio_manager_linux.cc @@ -11,7 +11,7 @@ #include "base/process_util.h" #include "base/stl_util.h" #include "media/audio/audio_output_dispatcher.h" -#include "media/audio/audio_util.h" +#include "media/audio/audio_parameters.h" #if defined(USE_CRAS) #include "media/audio/cras/audio_manager_cras.h" #endif @@ -21,6 +21,7 @@ #if defined(USE_PULSEAUDIO) #include "media/audio/pulse/audio_manager_pulse.h" #endif +#include "media/base/channel_layout.h" #include "media/base/limits.h" #include "media/base/media_switches.h" @@ -29,6 +30,9 @@ namespace media { // Maximum number of output streams that can be open simultaneously. static const int kMaxOutputStreams = 50; +// Default sample rate for input and output streams. +static const int kDefaultSampleRate = 48000; + // Since "default", "pulse" and "dmix" devices are virtual devices mapped to // real devices, we remove them from the list to avoiding duplicate counting. // In addition, note that we support no more than 2 channels for recording, @@ -94,6 +98,15 @@ void AudioManagerLinux::GetAudioInputDeviceNames( GetAlsaAudioInputDevices(device_names); } +AudioParameters AudioManagerLinux::GetInputStreamParameters( + const std::string& device_id) { + static const int kDefaultInputBufferSize = 1024; + + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, + kDefaultSampleRate, 16, kDefaultInputBufferSize); +} + void AudioManagerLinux::GetAlsaAudioInputDevices( media::AudioDeviceNames* device_names) { // Constants specified by the ALSA API for device hints. @@ -251,6 +264,32 @@ AudioInputStream* AudioManagerLinux::MakeLowLatencyInputStream( return MakeInputStream(params, device_id); } +AudioParameters AudioManagerLinux::GetPreferredOutputStreamParameters( + const AudioParameters& input_params) { + static const int kDefaultOutputBufferSize = 512; + ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; + int sample_rate = kDefaultSampleRate; + int buffer_size = kDefaultOutputBufferSize; + int bits_per_sample = 16; + int input_channels = 0; + if (input_params.IsValid()) { + // Some clients, such as WebRTC, have a more limited use case and work + // acceptably with a smaller buffer size. The check below allows clients + // which want to try a smaller buffer size on Linux to do so. + // TODO(dalecurtis): This should include bits per channel and channel layout + // eventually. + sample_rate = input_params.sample_rate(); + bits_per_sample = input_params.bits_per_sample(); + channel_layout = input_params.channel_layout(); + input_channels = input_params.input_channels(); + buffer_size = std::min(input_params.frames_per_buffer(), buffer_size); + } + + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, + sample_rate, bits_per_sample, buffer_size); +} + AudioOutputStream* AudioManagerLinux::MakeOutputStream( const AudioParameters& params) { std::string device_name = AlsaPcmOutputStream::kAutoSelectDevice; @@ -292,22 +331,4 @@ AudioManager* CreateAudioManager() { return new AudioManagerLinux(); } -AudioParameters AudioManagerLinux::GetPreferredLowLatencyOutputStreamParameters( - const AudioParameters& input_params) { - // Since Linux doesn't actually have a low latency path the hardware buffer - // size is quite large in order to prevent glitches with general usage. Some - // clients, such as WebRTC, have a more limited use case and work acceptably - // with a smaller buffer size. The check below allows clients which want to - // try a smaller buffer size on Linux to do so. - int buffer_size = GetAudioHardwareBufferSize(); - if (input_params.frames_per_buffer() < buffer_size) - buffer_size = input_params.frames_per_buffer(); - - // TODO(dalecurtis): This should include bits per channel and channel layout - // eventually. - return AudioParameters( - AudioParameters::AUDIO_PCM_LOW_LATENCY, input_params.channel_layout(), - input_params.sample_rate(), 16, buffer_size); -} - } // namespace media diff --git a/media/audio/linux/audio_manager_linux.h b/media/audio/linux/audio_manager_linux.h index 02da961..4c89773 100644 --- a/media/audio/linux/audio_manager_linux.h +++ b/media/audio/linux/audio_manager_linux.h @@ -27,6 +27,8 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase { virtual void ShowAudioInputSettings() OVERRIDE; virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names) OVERRIDE; + virtual AudioParameters GetInputStreamParameters( + const std::string& device_id) OVERRIDE; // Implementation of AudioManagerBase. virtual AudioOutputStream* MakeLinearOutputStream( @@ -37,12 +39,13 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase { const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeLowLatencyInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; - virtual AudioParameters GetPreferredLowLatencyOutputStreamParameters( - const AudioParameters& input_params) OVERRIDE; protected: virtual ~AudioManagerLinux(); + virtual AudioParameters GetPreferredOutputStreamParameters( + const AudioParameters& input_params) OVERRIDE; + private: enum StreamType { kStreamPlayback = 0, diff --git a/media/audio/mac/audio_device_listener_mac.cc b/media/audio/mac/audio_device_listener_mac.cc index 65a4854..24da08a 100644 --- a/media/audio/mac/audio_device_listener_mac.cc +++ b/media/audio/mac/audio_device_listener_mac.cc @@ -125,8 +125,8 @@ AudioDeviceListenerMac::AudioDeviceListenerMac(const base::Closure& listener_cb) // by pausing and resuming the dispatch queue before and after each pumped // task. This is not ideal and long term we should replace the audio thread // on OSX with a dispatch queue. See http://crbug.com/158170 for discussion. - // TODO(dalecurtis): Does not fix the cases where GetAudioHardwareSampleRate() - // and GetAudioInputHardwareSampleRate() are called by the browser process. + // TODO(dalecurtis): Does not fix the cases where + // GetDefaultOutputStreamParameters() are called by the browser process. // These are one time events due to renderer side cache and thus unlikely to // occur at the same time as a device callback. Should be fixed along with // http://crbug.com/137326 using a forced PostTask. diff --git a/media/audio/mac/audio_low_latency_input_mac.cc b/media/audio/mac/audio_low_latency_input_mac.cc index 85eef1f..972ae39 100644 --- a/media/audio/mac/audio_low_latency_input_mac.cc +++ b/media/audio/mac/audio_low_latency_input_mac.cc @@ -67,7 +67,10 @@ AUAudioInputStream::AUAudioInputStream( // Note that we use the same native buffer size as for the output side here // since the AUHAL implementation requires that both capture and render side // use the same buffer size. See http://crbug.com/154352 for more details. - number_of_frames_ = GetAudioHardwareBufferSize(); + // TODO(xians): Get the audio parameters from the right device. + const AudioParameters parameters = + manager_->GetInputStreamParameters(AudioManagerBase::kDefaultDeviceId); + number_of_frames_ = parameters.frames_per_buffer(); DVLOG(1) << "Size of data buffer in frames : " << number_of_frames_; // Derive size (in bytes) of the buffers that we will render to. @@ -225,7 +228,8 @@ bool AUAudioInputStream::Open() { // Set the desired number of frames in the IO buffer (output scope). // WARNING: Setting this value changes the frame size for all audio units in // the current process. It's imperative that the input and output frame sizes - // be the same as audio_util::GetAudioHardwareBufferSize(). + // be the same as the frames_per_buffer() returned by + // GetInputStreamParameters(). // TODO(henrika): Due to http://crrev.com/159666 this is currently not true // and should be fixed, a CHECK() should be added at that time. result = AudioUnitSetProperty(audio_unit_, diff --git a/media/audio/mac/audio_low_latency_output_mac.cc b/media/audio/mac/audio_low_latency_output_mac.cc index 6ab0ead..4b82bef 100644 --- a/media/audio/mac/audio_low_latency_output_mac.cc +++ b/media/audio/mac/audio_low_latency_output_mac.cc @@ -81,7 +81,10 @@ AUAudioOutputStream::AUAudioOutputStream( // Calculate the number of sample frames per callback. number_of_frames_ = params.GetBytesPerBuffer() / format_.mBytesPerPacket; DVLOG(1) << "Number of frames per callback: " << number_of_frames_; - CHECK_EQ(number_of_frames_, GetAudioHardwareBufferSize()); + const AudioParameters parameters = + manager_->GetDefaultOutputStreamParameters(); + CHECK_EQ(number_of_frames_, + static_cast<size_t>(parameters.frames_per_buffer())); } AUAudioOutputStream::~AUAudioOutputStream() { @@ -167,7 +170,8 @@ bool AUAudioOutputStream::Configure() { // Set the buffer frame size. // WARNING: Setting this value changes the frame size for all audio units in // the current process. It's imperative that the input and output frame sizes - // be the same as audio_util::GetAudioHardwareBufferSize(). + // be the same as the frames_per_buffer() returned by + // GetDefaultOutputStreamParameters. // See http://crbug.com/154352 for details. UInt32 buffer_size = number_of_frames_; result = AudioUnitSetProperty( diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc index 4030a23..5a82ce0 100644 --- a/media/audio/mac/audio_manager_mac.cc +++ b/media/audio/mac/audio_manager_mac.cc @@ -12,7 +12,7 @@ #include "base/mac/mac_logging.h" #include "base/mac/scoped_cftyperef.h" #include "base/sys_string_conversions.h" -#include "media/audio/audio_util.h" +#include "media/audio/audio_parameters.h" #include "media/audio/mac/audio_input_mac.h" #include "media/audio/mac/audio_low_latency_input_mac.h" #include "media/audio/mac/audio_low_latency_output_mac.h" @@ -20,6 +20,7 @@ #include "media/audio/mac/audio_synchronized_mac.h" #include "media/audio/mac/audio_unified_mac.h" #include "media/base/bind_to_loop.h" +#include "media/base/channel_layout.h" #include "media/base/limits.h" #include "media/base/media_switches.h" @@ -28,6 +29,9 @@ namespace media { // Maximum number of output streams that can be open simultaneously. static const int kMaxOutputStreams = 50; +// Default buffer size in samples for low-latency input and output streams. +static const int kDefaultLowLatencyBufferSize = 128; + static bool HasAudioHardware(AudioObjectPropertySelector selector) { AudioDeviceID output_device_id = kAudioObjectUnknown; const AudioObjectPropertyAddress property_address = { @@ -273,6 +277,15 @@ void AudioManagerMac::GetAudioInputDeviceNames( } } +AudioParameters AudioManagerMac::GetInputStreamParameters( + const std::string& device_id) { + // TODO(xians): query the native channel layout for the specific device. + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, + AUAudioInputStream::HardwareSampleRate(), 16, + kDefaultLowLatencyBufferSize); +} + AudioOutputStream* AudioManagerMac::MakeLinearOutputStream( const AudioParameters& params) { DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); @@ -321,22 +334,28 @@ AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream( return stream; } -AudioParameters AudioManagerMac::GetPreferredLowLatencyOutputStreamParameters( +AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters( const AudioParameters& input_params) { - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableWebAudioInput)) { - // TODO(crogers): given the limitations of the AudioOutputStream - // back-ends used with kEnableWebAudioInput, we hard-code to stereo. - // Specifically, this is a limitation of AudioSynchronizedStream which - // can be removed as part of the work to consolidate these back-ends. - return AudioParameters( - AudioParameters::AUDIO_PCM_LOW_LATENCY, - CHANNEL_LAYOUT_STEREO, input_params.input_channels(), - GetAudioHardwareSampleRate(), 16, GetAudioHardwareBufferSize()); + ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; + int input_channels = 0; + if (input_params.IsValid()) { + channel_layout = input_params.channel_layout(); + input_channels = input_params.input_channels(); + + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableWebAudioInput)) { + // TODO(crogers): given the limitations of the AudioOutputStream + // back-ends used with kEnableWebAudioInput, we hard-code to stereo. + // Specifically, this is a limitation of AudioSynchronizedStream which + // can be removed as part of the work to consolidate these back-ends. + channel_layout = CHANNEL_LAYOUT_STEREO; + } } - return AudioManagerBase::GetPreferredLowLatencyOutputStreamParameters( - input_params); + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, + AUAudioOutputStream::HardwareSampleRate(), 16, + kDefaultLowLatencyBufferSize); } void AudioManagerMac::CreateDeviceListener() { diff --git a/media/audio/mac/audio_manager_mac.h b/media/audio/mac/audio_manager_mac.h index cdfa241..5eba595 100644 --- a/media/audio/mac/audio_manager_mac.h +++ b/media/audio/mac/audio_manager_mac.h @@ -25,6 +25,8 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase { virtual bool HasAudioInputDevices() OVERRIDE; virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names) OVERRIDE; + virtual AudioParameters GetInputStreamParameters( + const std::string& device_id) OVERRIDE; // Implementation of AudioManagerBase. virtual AudioOutputStream* MakeLinearOutputStream( @@ -35,12 +37,13 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase { const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeLowLatencyInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; - virtual AudioParameters GetPreferredLowLatencyOutputStreamParameters( - const AudioParameters& input_params) OVERRIDE; protected: virtual ~AudioManagerMac(); + virtual AudioParameters GetPreferredOutputStreamParameters( + const AudioParameters& input_params) OVERRIDE; + private: // Helper methods for constructing AudioDeviceListenerMac on the audio thread. void CreateDeviceListener(); diff --git a/media/audio/mock_audio_manager.cc b/media/audio/mock_audio_manager.cc index 4cd5f21..1209e19 100644 --- a/media/audio/mock_audio_manager.cc +++ b/media/audio/mock_audio_manager.cc @@ -6,6 +6,7 @@ #include "base/logging.h" #include "base/message_loop_proxy.h" +#include "media/audio/audio_parameters.h" namespace media { @@ -70,4 +71,13 @@ void MockAudioManager::RemoveOutputDeviceChangeListener( AudioDeviceListener* listener) { } +AudioParameters MockAudioManager::GetDefaultOutputStreamParameters() { + return AudioParameters(); +} + +AudioParameters MockAudioManager::GetInputStreamParameters( + const std::string& device_id) { + return AudioParameters(); +} + } // namespace media. diff --git a/media/audio/mock_audio_manager.h b/media/audio/mock_audio_manager.h index 1046c8c..3a0e907 100644 --- a/media/audio/mock_audio_manager.h +++ b/media/audio/mock_audio_manager.h @@ -53,6 +53,10 @@ class MockAudioManager : public media::AudioManager { virtual void RemoveOutputDeviceChangeListener( AudioDeviceListener* listener) OVERRIDE; + virtual AudioParameters GetDefaultOutputStreamParameters() OVERRIDE; + virtual AudioParameters GetInputStreamParameters( + const std::string& device_id) OVERRIDE; + private: virtual ~MockAudioManager(); diff --git a/media/audio/openbsd/audio_manager_openbsd.cc b/media/audio/openbsd/audio_manager_openbsd.cc index 84304a5..67fba91 100644 --- a/media/audio/openbsd/audio_manager_openbsd.cc +++ b/media/audio/openbsd/audio_manager_openbsd.cc @@ -7,9 +7,11 @@ #include "base/command_line.h" #include "base/stl_util.h" #include "media/audio/audio_output_dispatcher.h" +#include "media/audio/audio_parameters.h" #if defined(USE_PULSEAUDIO) #include "media/audio/pulse/pulse_output.h" #endif +#include "media/base/channel_layout.h" #include "media/base/limits.h" #include "media/base/media_switches.h" @@ -20,6 +22,9 @@ namespace media { // Maximum number of output streams that can be open simultaneously. static const int kMaxOutputStreams = 50; +// Default sample rate for input and output streams. +static const int kDefaultSampleRate = 48000; + // Implementation of AudioManager. static bool HasAudioHardware() { int fd; @@ -43,6 +48,15 @@ bool AudioManagerOpenBSD::HasAudioInputDevices() { return HasAudioHardware(); } +AudioParameters AudioManagerOpenBSD::GetInputStreamParameters( + const std::string& device_id) { + static const int kDefaultInputBufferSize = 1024; + + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, + kDefaultSampleRate, 16, kDefaultInputBufferSize); +} + AudioManagerOpenBSD::AudioManagerOpenBSD() { SetMaxOutputStreamsAllowed(kMaxOutputStreams); } @@ -77,6 +91,29 @@ AudioInputStream* AudioManagerOpenBSD::MakeLowLatencyInputStream( return NULL; } +AudioParameters AudioManagerOpenBSD::GetPreferredOutputStreamParameters( + const AudioParameters& input_params) { + static const int kDefaultOutputBufferSize = 512; + + ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; + int sample_rate = kDefaultSampleRate; + int buffer_size = kDefaultOutputBufferSize; + int bits_per_sample = 16; + int input_channels = 0; + if (input_params.IsValid()) { + sample_rate = input_params.sample_rate(); + bits_per_sample = input_params.bits_per_sample(); + channel_layout = input_params.channel_layout(); + input_channels = input_params.input_channels(); + buffer_size = std::min(buffer_size, input_params.frames_per_buffer()); + } + + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, + sample_rate, bits_per_sample, buffer_size); +} + + AudioOutputStream* AudioManagerOpenBSD::MakeOutputStream( const AudioParameters& params) { #if defined(USE_PULSEAUDIO) @@ -89,6 +126,7 @@ AudioOutputStream* AudioManagerOpenBSD::MakeOutputStream( return NULL; } +// TODO(xians): Merge AudioManagerOpenBSD with AudioManagerPulse; // static AudioManager* CreateAudioManager() { return new AudioManagerOpenBSD(); diff --git a/media/audio/openbsd/audio_manager_openbsd.h b/media/audio/openbsd/audio_manager_openbsd.h index aeba43e..14c5636 100644 --- a/media/audio/openbsd/audio_manager_openbsd.h +++ b/media/audio/openbsd/audio_manager_openbsd.h @@ -19,6 +19,8 @@ class MEDIA_EXPORT AudioManagerOpenBSD : public AudioManagerBase { // Implementation of AudioManager. virtual bool HasAudioOutputDevices() OVERRIDE; virtual bool HasAudioInputDevices() OVERRIDE; + virtual AudioParameters GetInputStreamParameters( + const std::string& device_id) OVERRIDE; // Implementation of AudioManagerBase. virtual AudioOutputStream* MakeLinearOutputStream( @@ -33,6 +35,9 @@ class MEDIA_EXPORT AudioManagerOpenBSD : public AudioManagerBase { protected: virtual ~AudioManagerOpenBSD(); + virtual AudioParameters GetPreferredOutputStreamParameters( + const AudioParameters& input_params) OVERRIDE; + private: // Called by MakeLinearOutputStream and MakeLowLatencyOutputStream. AudioOutputStream* MakeOutputStream(const AudioParameters& params); diff --git a/media/audio/pulse/audio_manager_pulse.cc b/media/audio/pulse/audio_manager_pulse.cc index f448fce..1217ecf 100644 --- a/media/audio/pulse/audio_manager_pulse.cc +++ b/media/audio/pulse/audio_manager_pulse.cc @@ -11,12 +11,13 @@ #include "base/nix/xdg_util.h" #include "base/process_util.h" #include "base/stl_util.h" -#include "media/audio/audio_util.h" +#include "media/audio/audio_parameters.h" #include "media/audio/linux/audio_manager_linux.h" #include "media/audio/pulse/pulse_input.h" #include "media/audio/pulse/pulse_output.h" #include "media/audio/pulse/pulse_stubs.h" #include "media/audio/pulse/pulse_util.h" +#include "media/base/channel_layout.h" using media_audio_pulse::kModulePulse; using media_audio_pulse::InitializeStubs; @@ -90,6 +91,16 @@ void AudioManagerPulse::GetAudioInputDeviceNames( } } +AudioParameters AudioManagerPulse::GetInputStreamParameters( + const std::string& device_id) { + static const int kDefaultInputBufferSize = 1024; + + // TODO(xians): add support for querying native channel layout for pulse. + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, + GetNativeSampleRate(), 16, kDefaultInputBufferSize); +} + AudioOutputStream* AudioManagerPulse::MakeLinearOutputStream( const AudioParameters& params) { DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); @@ -114,6 +125,25 @@ AudioInputStream* AudioManagerPulse::MakeLowLatencyInputStream( return MakeInputStream(params, device_id); } +AudioParameters AudioManagerPulse::GetPreferredOutputStreamParameters( + const AudioParameters& input_params) { + static const int kDefaultOutputBufferSize = 512; + + ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; + int buffer_size = kDefaultOutputBufferSize; + int bits_per_sample = 16; + int input_channels = 0; + if (input_params.IsValid()) { + bits_per_sample = input_params.bits_per_sample(); + channel_layout = input_params.channel_layout(); + input_channels = input_params.input_channels(); + buffer_size = std::min(buffer_size, input_params.frames_per_buffer()); + } + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, + GetNativeSampleRate(), bits_per_sample, buffer_size); +} + AudioOutputStream* AudioManagerPulse::MakeOutputStream( const AudioParameters& params) { return new PulseAudioOutputStream(params, this); @@ -125,20 +155,6 @@ AudioInputStream* AudioManagerPulse::MakeInputStream( input_mainloop_, input_context_); } -AudioParameters AudioManagerPulse::GetPreferredLowLatencyOutputStreamParameters( - const AudioParameters& input_params) { - // TODO(xians): figure out the optimized buffer size for the Pulse IO. - int buffer_size = GetAudioHardwareBufferSize(); - if (input_params.frames_per_buffer() < buffer_size) - buffer_size = input_params.frames_per_buffer(); - - // TODO(dalecurtis): This should include bits per channel and channel layout - // eventually. - return AudioParameters( - AudioParameters::AUDIO_PCM_LOW_LATENCY, input_params.channel_layout(), - input_params.sample_rate(), 16, buffer_size); -} - int AudioManagerPulse::GetNativeSampleRate() { DCHECK(input_mainloop_); DCHECK(input_context_); diff --git a/media/audio/pulse/audio_manager_pulse.h b/media/audio/pulse/audio_manager_pulse.h index cff2903..9dacb9c 100644 --- a/media/audio/pulse/audio_manager_pulse.h +++ b/media/audio/pulse/audio_manager_pulse.h @@ -27,6 +27,8 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase { virtual void ShowAudioInputSettings() OVERRIDE; virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names) OVERRIDE; + virtual AudioParameters GetInputStreamParameters( + const std::string& device_id) OVERRIDE; // Implementation of AudioManagerBase. virtual AudioOutputStream* MakeLinearOutputStream( @@ -37,10 +39,10 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase { const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeLowLatencyInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; - virtual AudioParameters GetPreferredLowLatencyOutputStreamParameters( - const AudioParameters& input_params) OVERRIDE; - int GetNativeSampleRate(); + protected: + virtual AudioParameters GetPreferredOutputStreamParameters( + const AudioParameters& input_params) OVERRIDE; private: bool Init(); @@ -64,6 +66,9 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase { AudioInputStream* MakeInputStream(const AudioParameters& params, const std::string& device_id); + // Gets the native sample rate of Pulse. + int GetNativeSampleRate(); + pa_threaded_mainloop* input_mainloop_; pa_context* input_context_; AudioDeviceNames* devices_; diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc index bd809b8..7bfc638 100644 --- a/media/audio/win/audio_manager_win.cc +++ b/media/audio/win/audio_manager_win.cc @@ -20,6 +20,7 @@ #include "base/process_util.h" #include "base/string_number_conversions.h" #include "base/string_util.h" +#include "media/audio/audio_parameters.h" #include "media/audio/audio_util.h" #include "media/audio/win/audio_device_listener_win.h" #include "media/audio/win/audio_low_latency_input_win.h" @@ -31,6 +32,7 @@ #include "media/audio/win/wavein_input_win.h" #include "media/audio/win/waveout_output_win.h" #include "media/base/bind_to_loop.h" +#include "media/base/channel_layout.h" #include "media/base/limits.h" #include "media/base/media_switches.h" @@ -61,6 +63,10 @@ static const int kWinMaxChannels = 8; // play. static const int kNumInputBuffers = 3; +// Buffer size to use for input and output stream when a proper size can't be +// determined from the system +static const int kFallbackBufferSize = 2048; + static int GetVersionPartAsInt(DWORDLONG num) { return static_cast<int>(num & 0xffff); } @@ -255,6 +261,26 @@ void AudioManagerWin::GetAudioInputDeviceNames( } } +AudioParameters AudioManagerWin::GetInputStreamParameters( + const std::string& device_id) { + int sample_rate = 0; + ChannelLayout channel_layout = CHANNEL_LAYOUT_NONE; + if (!CoreAudioUtil::IsSupported()) { + sample_rate = 48000; + channel_layout = CHANNEL_LAYOUT_STEREO; + } else { + sample_rate = WASAPIAudioInputStream::HardwareSampleRate(device_id); + channel_layout = + WASAPIAudioInputStream::HardwareChannelCount(device_id) == 1 ? + CHANNEL_LAYOUT_MONO : CHANNEL_LAYOUT_STEREO; + } + + // TODO(Henrika): improve the default buffer size value for input stream. + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, + sample_rate, 16, kFallbackBufferSize); +} + // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR // mode. // - PCMWaveOutAudioOutputStream: Based on the waveOut API. @@ -329,6 +355,60 @@ AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( return stream; } +AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( + const AudioParameters& input_params) { + const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); + ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; + int sample_rate = 0; + int buffer_size = 0; + int bits_per_sample = 16; + int input_channels = 0; + if (!CoreAudioUtil::IsSupported()) { + // Fall back to Windows Wave implementation on Windows XP or lower. + // Use 48kHz as default input sample rate, kFallbackBufferSize as + // default buffer size. + sample_rate = 48000; + buffer_size = kFallbackBufferSize; + } else if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { + // TODO(crogers): tune these values for best possible WebAudio performance. + // WebRTC works well at 48kHz and a buffer size of 480 samples will be used + // for this case. Note that exclusive mode is experimental. + // This sample rate will be combined with a buffer size of 256 samples, + // which corresponds to an output delay of ~5.33ms. + sample_rate = 48000; + buffer_size = 256; + } else { + // Hardware sample-rate on Windows can be configured, so we must query. + // TODO(henrika): improve possibility to specify an audio endpoint. + // Use the default device (same as for Wave) for now to be compatible. + sample_rate = WASAPIAudioOutputStream::HardwareSampleRate(); + + AudioParameters params; + HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(eRender, eConsole, + ¶ms); + buffer_size = FAILED(hr) ? kFallbackBufferSize : params.frames_per_buffer(); + channel_layout = WASAPIAudioOutputStream::HardwareChannelLayout(); + } + + if (input_params.IsValid()) { + input_channels = input_params.input_channels(); + if (!CoreAudioUtil::IsSupported()) { + // If WASAPI isn't supported we'll fallback to WaveOut, which will take + // care of resampling and bits per sample changes. By setting these + // equal to the input values, AudioOutputResampler will skip resampling + // and bit per sample differences (since the input parameters will match + // the output parameters). + sample_rate = input_params.sample_rate(); + bits_per_sample = input_params.bits_per_sample(); + channel_layout = input_params.channel_layout(); + } + } + + return AudioParameters( + AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, + sample_rate, bits_per_sample, buffer_size); +} + AudioInputStream* AudioManagerWin::CreatePCMWaveInAudioInputStream( const AudioParameters& params, const std::string& device_id) { @@ -352,26 +432,4 @@ AudioManager* CreateAudioManager() { return new AudioManagerWin(); } -AudioParameters AudioManagerWin::GetPreferredLowLatencyOutputStreamParameters( - const AudioParameters& input_params) { - // If WASAPI isn't supported we'll fallback to WaveOut, which will take care - // of resampling and bits per sample changes. By setting these equal to the - // input values, AudioOutputResampler will skip resampling and bit per sample - // differences (since the input parameters will match the output parameters). - int sample_rate = input_params.sample_rate(); - int bits_per_sample = input_params.bits_per_sample(); - ChannelLayout channel_layout = input_params.channel_layout(); - int input_channels = input_params.input_channels(); - if (CoreAudioUtil::IsSupported()) { - sample_rate = GetAudioHardwareSampleRate(); - bits_per_sample = 16; - channel_layout = WASAPIAudioOutputStream::HardwareChannelLayout(); - } - - // TODO(dalecurtis): This should include hardware bits per channel eventually. - return AudioParameters( - AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, input_channels, - sample_rate, bits_per_sample, GetAudioHardwareBufferSize()); -} - } // namespace media diff --git a/media/audio/win/audio_manager_win.h b/media/audio/win/audio_manager_win.h index bb8f395..46d7aa4 100644 --- a/media/audio/win/audio_manager_win.h +++ b/media/audio/win/audio_manager_win.h @@ -27,6 +27,8 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase { virtual void ShowAudioInputSettings() OVERRIDE; virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names) OVERRIDE; + virtual AudioParameters GetInputStreamParameters( + const std::string& device_id) OVERRIDE; // Implementation of AudioManagerBase. virtual AudioOutputStream* MakeLinearOutputStream( @@ -37,12 +39,13 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase { const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeLowLatencyInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; - virtual AudioParameters GetPreferredLowLatencyOutputStreamParameters( - const AudioParameters& input_params) OVERRIDE; protected: virtual ~AudioManagerWin(); + virtual AudioParameters GetPreferredOutputStreamParameters( + const AudioParameters& input_params) OVERRIDE; + private: enum EnumerationType { kUninitializedEnumeration = 0, diff --git a/media/audio/win/audio_output_win_unittest.cc b/media/audio/win/audio_output_win_unittest.cc index 40b4d81..198ee99 100644 --- a/media/audio/win/audio_output_win_unittest.cc +++ b/media/audio/win/audio_output_win_unittest.cc @@ -461,7 +461,8 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) { // Use 10 ms buffer size for WASAPI and 50 ms buffer size for Wave. // Take the existing native sample rate into account. - int sample_rate = static_cast<int>(media::GetAudioHardwareSampleRate()); + const AudioParameters params = audio_man->GetDefaultOutputStreamParameters(); + int sample_rate = params.sample_rate(); uint32 samples_10_ms = sample_rate / 100; int n = 1; (base::win::GetVersion() <= base::win::VERSION_XP) ? n = 5 : n = 1; |