diff options
author | henrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-20 22:41:31 +0000 |
---|---|---|
committer | henrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-20 22:41:31 +0000 |
commit | 1a5f6eacc2e704970d566b236c196645eab7d2aa (patch) | |
tree | d64368b52ef3e49b75e34b00ef4aad54f3f99e5a /media | |
parent | 0bf6ad7c727a13039c2e26fb7773868f37d55fad (diff) | |
download | chromium_src-1a5f6eacc2e704970d566b236c196645eab7d2aa.zip chromium_src-1a5f6eacc2e704970d566b236c196645eab7d2aa.tar.gz chromium_src-1a5f6eacc2e704970d566b236c196645eab7d2aa.tar.bz2 |
Finalizes support of device selection for live-audio on Windows.
BUG=147327
TEST=media_unittests.exe --gtest_filter=WASAPIUni* gtest_also_run_disabled_tests where I've also hard coded uniqe device IDs for non-default capture devices.
Also tested misc. live-audio clients where a non-default mic was selected under content/settings
Review URL: https://chromiumcodereview.appspot.com/17410006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207615 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/audio/win/audio_unified_win.cc | 25 | ||||
-rw-r--r-- | media/audio/win/audio_unified_win_unittest.cc | 68 | ||||
-rw-r--r-- | media/audio/win/core_audio_util_win.cc | 21 | ||||
-rw-r--r-- | media/audio/win/core_audio_util_win.h | 7 |
4 files changed, 100 insertions, 21 deletions
diff --git a/media/audio/win/audio_unified_win.cc b/media/audio/win/audio_unified_win.cc index a2f2c36..baf025a9 100644 --- a/media/audio/win/audio_unified_win.cc +++ b/media/audio/win/audio_unified_win.cc @@ -221,8 +221,16 @@ bool WASAPIUnifiedStream::Open() { } AudioParameters hw_input_params; - hr = CoreAudioUtil::GetPreferredAudioParameters( - eCapture, eConsole, &hw_input_params); + if (input_device_id_ == AudioManagerBase::kDefaultDeviceId) { + // Query native parameters for the default capture device. + hr = CoreAudioUtil::GetPreferredAudioParameters( + eCapture, eConsole, &hw_input_params); + } else { + // Query native parameters for the capture device given by + // |input_device_id_|. + hr = CoreAudioUtil::GetPreferredAudioParameters( + input_device_id_, &hw_input_params); + } if (FAILED(hr)) { LOG(ERROR) << "Failed to get preferred input audio parameters."; return false; @@ -333,10 +341,15 @@ bool WASAPIUnifiedStream::Open() { return false; // Capture side (always event driven but format depends on varispeed or not): - // TODO(henrika): Open the correct input device with |input_device_id_|, - // http://crbug.com/147327. - ScopedComPtr<IAudioClient> audio_input_client = - CoreAudioUtil::CreateDefaultClient(eCapture, eConsole); + + ScopedComPtr<IAudioClient> audio_input_client; + if (input_device_id_ == AudioManagerBase::kDefaultDeviceId) { + audio_input_client = CoreAudioUtil::CreateDefaultClient(eCapture, eConsole); + } else { + ScopedComPtr<IMMDevice> audio_input_device( + CoreAudioUtil::CreateDevice(input_device_id_)); + audio_input_client = CoreAudioUtil::CreateClient(audio_input_device); + } if (!audio_input_client) return false; diff --git a/media/audio/win/audio_unified_win_unittest.cc b/media/audio/win/audio_unified_win_unittest.cc index 807ca7f..772fd50 100644 --- a/media/audio/win/audio_unified_win_unittest.cc +++ b/media/audio/win/audio_unified_win_unittest.cc @@ -108,9 +108,9 @@ class UnifiedSourceCallback : public AudioOutputStream::AudioSourceCallback { // Play out the recorded audio samples in loop back. Perform channel mixing // if required using a channel mixer which is created only if needed. - if (source->channels() == dest->channels()) + if (source->channels() == dest->channels()) { source->CopyTo(dest); - else { + } else { // A channel mixer is required for converting audio between two different // channel layouts. if (!channel_mixer_) { @@ -145,7 +145,7 @@ class UnifiedSourceCallback : public AudioOutputStream::AudioSourceCallback { // Convenience method which ensures that we fulfill all required conditions // to run unified audio tests on Windows. static bool CanRunUnifiedAudioTests(AudioManager* audio_man) { - if (!CoreAudioUtil::IsSupported()) { + if (!CoreAudioUtil::IsSupported()) { LOG(WARNING) << "This tests requires Windows Vista or higher."; return false; } @@ -178,13 +178,6 @@ class AudioUnifiedStreamWrapper { EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters( eRender, eConsole, &out_params))); - // We use the number of channels for the input side to signal that - // unified audio is requested. The audio manager will create a unified - // audio backend only if in_params.channels() is larger than zero.M - AudioParameters in_params; - EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters( - eCapture, eConsole, &in_params))); - // WebAudio is the only real user of unified audio and it always asks // for stereo. // TODO(henrika): extend support to other input channel layouts as well. @@ -201,11 +194,17 @@ class AudioUnifiedStreamWrapper { ~AudioUnifiedStreamWrapper() {} - // Creates AudioOutputStream object using default parameters. + // Creates an AudioOutputStream object using default parameters. WASAPIUnifiedStream* Create() { return static_cast<WASAPIUnifiedStream*> (CreateOutputStream()); } + // Creates an AudioOutputStream object using default parameters but a + // specified input device. + WASAPIUnifiedStream* Create(const std::string device_id) { + return static_cast<WASAPIUnifiedStream*> (CreateOutputStream(device_id)); + } + AudioParameters::Format format() const { return params_.format(); } int channels() const { return params_.channels(); } int bits_per_sample() const { return params_.bits_per_sample(); } @@ -216,8 +215,28 @@ class AudioUnifiedStreamWrapper { private: AudioOutputStream* CreateOutputStream() { + // Get the unique device ID of the default capture device instead of using + // AudioManagerBase::kDefaultDeviceId since it provides slightly better + // test coverage and will utilize the same code path as if a non default + // input device was used. + ScopedComPtr<IMMDevice> audio_device = + CoreAudioUtil::CreateDefaultDevice(eCapture, eConsole); + AudioDeviceName name; + EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(audio_device, &name))); + const std::string& device_id = name.unique_id; + EXPECT_TRUE(CoreAudioUtil::DeviceIsDefault(eCapture, eConsole, device_id)); + + // Create the unified audio I/O stream using the default input device. + AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params_, + device_id); + EXPECT_TRUE(aos); + return aos; + } + + AudioOutputStream* CreateOutputStream(const std::string& device_id) { + // Create the unified audio I/O stream using the specified input device. AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params_, - std::string()); + device_id); EXPECT_TRUE(aos); return aos; } @@ -234,6 +253,14 @@ static WASAPIUnifiedStream* CreateDefaultUnifiedStream( return aosw.Create(); } +// Convenience method which creates a default WASAPIUnifiedStream object but +// with a specified audio input device. +static WASAPIUnifiedStream* CreateDefaultUnifiedStream( + AudioManager* audio_manager, const std::string& device_id) { + AudioUnifiedStreamWrapper aosw(audio_manager); + return aosw.Create(device_id); +} + // Test Open(), Close() calling sequence. TEST(WASAPIUnifiedStreamTest, OpenAndClose) { scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); @@ -245,6 +272,23 @@ TEST(WASAPIUnifiedStreamTest, OpenAndClose) { wus->Close(); } +// Test Open(), Close() calling sequence for all available capture devices. +TEST(WASAPIUnifiedStreamTest, OpenAndCloseForAllInputDevices) { + scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); + if (!CanRunUnifiedAudioTests(audio_manager.get())) + return; + + AudioDeviceNames device_names; + audio_manager->GetAudioInputDeviceNames(&device_names); + for (AudioDeviceNames::iterator i = device_names.begin(); + i != device_names.end(); ++i) { + WASAPIUnifiedStream* wus = CreateDefaultUnifiedStream( + audio_manager.get(), i->unique_id); + EXPECT_TRUE(wus->Open()); + wus->Close(); + } +} + // Test Open(), Start(), Close() calling sequence. TEST(WASAPIUnifiedStreamTest, OpenStartAndClose) { scoped_ptr<AudioManager> audio_manager(AudioManager::Create()); diff --git a/media/audio/win/core_audio_util_win.cc b/media/audio/win/core_audio_util_win.cc index 38a3d2e..392184b 100644 --- a/media/audio/win/core_audio_util_win.cc +++ b/media/audio/win/core_audio_util_win.cc @@ -333,7 +333,7 @@ std::string CoreAudioUtil::GetFriendlyName(const std::string& device_id) { bool CoreAudioUtil::DeviceIsDefault(EDataFlow flow, ERole role, - std::string device_id) { + const std::string& device_id) { DCHECK(IsSupported()); ScopedComPtr<IMMDevice> device = CreateDefaultDevice(flow, role); if (!device) @@ -579,6 +579,25 @@ HRESULT CoreAudioUtil::GetPreferredAudioParameters( return GetPreferredAudioParameters(client, params); } +HRESULT CoreAudioUtil::GetPreferredAudioParameters( + const std::string& device_id, AudioParameters* params) { + DCHECK(IsSupported()); + ScopedComPtr<IMMDevice> device(CreateDevice(device_id)); + if (!device) { + // Map NULL-pointer to new error code which can be different from the + // actual error code. The exact value is not important here. + return AUDCLNT_E_DEVICE_INVALIDATED; + } + + ScopedComPtr<IAudioClient> client(CreateClient(device)); + if (!client) { + // Map NULL-pointer to new error code which can be different from the + // actual error code. The exact value is not important here. + return AUDCLNT_E_ENDPOINT_CREATE_FAILED; + } + return GetPreferredAudioParameters(client, params); +} + HRESULT CoreAudioUtil::SharedModeInitialize(IAudioClient* client, const WAVEFORMATPCMEX* format, HANDLE event_handle, diff --git a/media/audio/win/core_audio_util_win.h b/media/audio/win/core_audio_util_win.h index 2dac60a..5e2e99f 100644 --- a/media/audio/win/core_audio_util_win.h +++ b/media/audio/win/core_audio_util_win.h @@ -75,7 +75,7 @@ class MEDIA_EXPORT CoreAudioUtil { // Returns true if the provided unique |device_id| corresponds to the current // default device for the specified by a data-flow direction and role. static bool DeviceIsDefault( - EDataFlow flow, ERole role, std::string device_id); + EDataFlow flow, ERole role, const std::string& device_id); // Query if the audio device is a rendering device or a capture device. static EDataFlow GetDataFlow(IMMDevice* device); @@ -137,13 +137,16 @@ class MEDIA_EXPORT CoreAudioUtil { REFERENCE_TIME* device_period); // Get the preferred audio parameters for the specified |client| or the - // given direction and role is define by |data_flow| and |role|. + // given direction and role is define by |data_flow| and |role|, or the + // unique device id given by |device_id|. // The acquired values should only be utilized for shared mode streamed since // there are no preferred settings for an exclusive mode stream. static HRESULT GetPreferredAudioParameters(IAudioClient* client, AudioParameters* params); static HRESULT GetPreferredAudioParameters(EDataFlow data_flow, ERole role, AudioParameters* params); + static HRESULT GetPreferredAudioParameters(const std::string& device_id, + AudioParameters* params); // After activating an IAudioClient interface on an audio endpoint device, // the client must initialize it once, and only once, to initialize the audio |