diff options
author | dalecurtis <dalecurtis@chromium.org> | 2015-04-22 12:42:47 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-22 19:42:50 +0000 |
commit | 43f3b0d25752d924390a4d6fc868d6e9469edc4f (patch) | |
tree | c98b782a7a0ee1b939a744759e32a14e87fcfed9 /media/audio | |
parent | 2c7c723477f83a3ae5fae494948c24163fd3aa0e (diff) | |
download | chromium_src-43f3b0d25752d924390a4d6fc868d6e9469edc4f.zip chromium_src-43f3b0d25752d924390a4d6fc868d6e9469edc4f.tar.gz chromium_src-43f3b0d25752d924390a4d6fc868d6e9469edc4f.tar.bz2 |
Switch to STA mode for audio thread and WASAPI I/O streams.
Using COM marshalling to share necessary worker thread pointers
with the render and capture threads.
BUG=422522
TEST=all unit tests pass, audio input and output work.
Review URL: https://codereview.chromium.org/1097553003
Cr-Commit-Position: refs/heads/master@{#326360}
Diffstat (limited to 'media/audio')
-rw-r--r-- | media/audio/audio_input_volume_unittest.cc | 22 | ||||
-rw-r--r-- | media/audio/audio_manager.cc | 15 | ||||
-rw-r--r-- | media/audio/audio_manager_base.cc | 5 | ||||
-rw-r--r-- | media/audio/audio_manager_unittest.cc | 18 | ||||
-rw-r--r-- | media/audio/win/audio_device_listener_win_unittest.cc | 4 | ||||
-rw-r--r-- | media/audio/win/audio_low_latency_input_win.cc | 52 | ||||
-rw-r--r-- | media/audio/win/audio_low_latency_input_win.h | 27 | ||||
-rw-r--r-- | media/audio/win/audio_low_latency_input_win_unittest.cc | 88 | ||||
-rw-r--r-- | media/audio/win/audio_low_latency_output_win.cc | 107 | ||||
-rw-r--r-- | media/audio/win/audio_low_latency_output_win.h | 31 | ||||
-rw-r--r-- | media/audio/win/audio_low_latency_output_win_unittest.cc | 99 | ||||
-rw-r--r-- | media/audio/win/audio_manager_win.h | 4 | ||||
-rw-r--r-- | media/audio/win/audio_output_win_unittest.cc | 2 | ||||
-rw-r--r-- | media/audio/win/core_audio_util_win.cc | 8 | ||||
-rw-r--r-- | media/audio/win/core_audio_util_win_unittest.cc | 7 | ||||
-rw-r--r-- | media/audio/win/device_enumeration_win.h | 2 |
16 files changed, 320 insertions, 171 deletions
diff --git a/media/audio/audio_input_volume_unittest.cc b/media/audio/audio_input_volume_unittest.cc index d6ee313..19c712a 100644 --- a/media/audio/audio_input_volume_unittest.cc +++ b/media/audio/audio_input_volume_unittest.cc @@ -38,13 +38,7 @@ double GetVolumeAfterSetVolumeOnLinux(AudioInputStream* ais, class AudioInputVolumeTest : public ::testing::Test { protected: - AudioInputVolumeTest() - : audio_manager_(AudioManager::CreateForTesting()) -#if defined(OS_WIN) - , com_init_(base::win::ScopedCOMInitializer::kMTA) -#endif - { - } + AudioInputVolumeTest() : audio_manager_(AudioManager::CreateForTesting()) {} bool HasCoreAudioAndInputDevices() { #if defined(OS_WIN) @@ -70,27 +64,27 @@ class AudioInputVolumeTest : public ::testing::Test { params, device_id); EXPECT_TRUE(NULL != ais); -#if defined(OS_LINUX) || defined(OS_OPENBSD) - // Some linux devices do not support our settings, we may fail to open - // those devices. +#if defined(OS_MACOSX) + EXPECT_TRUE(ais->Open()); +#else + // Some linux devices do not support our settings and some Windows devices + // may be "currently unavailable", we may fail to open those devices. if (!ais->Open()) { // Default device should always be able to be opened. EXPECT_TRUE(AudioManagerBase::kDefaultDeviceId != device_id); ais->Close(); ais = NULL; } -#elif defined(OS_WIN) || defined(OS_MACOSX) - EXPECT_TRUE(ais->Open()); #endif return ais; } - scoped_ptr<AudioManager> audio_manager_; - #if defined(OS_WIN) base::win::ScopedCOMInitializer com_init_; #endif + + scoped_ptr<AudioManager> audio_manager_; }; #if defined(OS_LINUX) && !defined(OS_CHROMEOS) diff --git a/media/audio/audio_manager.cc b/media/audio/audio_manager.cc index 6ee61d1..2bbffa7 100644 --- a/media/audio/audio_manager.cc +++ b/media/audio/audio_manager.cc @@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/power_monitor/power_monitor.h" +#include "base/synchronization/waitable_event.h" #include "build/build_config.h" #include "media/audio/fake_audio_log_factory.h" @@ -157,7 +158,19 @@ AudioManager* AudioManager::CreateWithHangTimer( // static AudioManager* AudioManager::CreateForTesting() { - return Create(g_helper.Pointer()->fake_log_factory()); + AudioManager* manager = Create(g_helper.Pointer()->fake_log_factory()); + + // When created for testing, always ensure all methods are ready to run (even + // if they end up called from other threads. + if (!manager->GetTaskRunner()->BelongsToCurrentThread()) { + base::WaitableEvent event(false, false); + manager->GetTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event))); + event.Wait(); + } + + return manager; } // static diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc index edaabf4..24e0883 100644 --- a/media/audio/audio_manager_base.cc +++ b/media/audio/audio_manager_base.cc @@ -83,7 +83,10 @@ AudioManagerBase::AudioManagerBase(AudioLogFactory* audio_log_factory) audio_thread_("AudioThread"), audio_log_factory_(audio_log_factory) { #if defined(OS_WIN) - audio_thread_.init_com_with_mta(true); + // Do not use MTA mode initalization as it causes hangs for a significant + // population of users and is not supported on Windows 8 for audio capture + // and rendering. See http://crbug.com/422522. + audio_thread_.init_com_with_mta(false); #elif defined(OS_MACOSX) // CoreAudio calls must occur on the main thread of the process, which in our // case is sadly the browser UI thread. Failure to execute calls on the right diff --git a/media/audio/audio_manager_unittest.cc b/media/audio/audio_manager_unittest.cc index 26c110e..e876dd1 100644 --- a/media/audio/audio_manager_unittest.cc +++ b/media/audio/audio_manager_unittest.cc @@ -33,19 +33,7 @@ namespace media { // Windows. class AudioManagerTest : public ::testing::Test { protected: - AudioManagerTest() - : audio_manager_(AudioManager::CreateForTesting()) -#if defined(OS_WIN) - , com_init_(base::win::ScopedCOMInitializer::kMTA) -#endif - { - // Wait for audio thread initialization to complete. Otherwise the - // enumeration type may not have been set yet. - base::WaitableEvent event(false, false); - audio_manager_->GetTaskRunner()->PostTask(FROM_HERE, base::Bind( - &base::WaitableEvent::Signal, base::Unretained(&event))); - event.Wait(); - } + AudioManagerTest() : audio_manager_(AudioManager::CreateForTesting()) {} #if defined(OS_WIN) bool SetMMDeviceEnumeration() { @@ -55,13 +43,13 @@ class AudioManagerTest : public ::testing::Test { if (amw->enumeration_type() == AudioManagerWin::kWaveEnumeration) return false; - amw->SetEnumerationType(AudioManagerWin::kMMDeviceEnumeration); + amw->set_enumeration_type(AudioManagerWin::kMMDeviceEnumeration); return true; } void SetWaveEnumeration() { AudioManagerWin* amw = static_cast<AudioManagerWin*>(audio_manager_.get()); - amw->SetEnumerationType(AudioManagerWin::kWaveEnumeration); + amw->set_enumeration_type(AudioManagerWin::kWaveEnumeration); } std::string GetDeviceIdFromPCMWaveInAudioInputStream( diff --git a/media/audio/win/audio_device_listener_win_unittest.cc b/media/audio/win/audio_device_listener_win_unittest.cc index 49a1359..9f9dc2b 100644 --- a/media/audio/win/audio_device_listener_win_unittest.cc +++ b/media/audio/win/audio_device_listener_win_unittest.cc @@ -25,9 +25,7 @@ static const char kSecondTestDevice[] = "test_device_1"; class AudioDeviceListenerWinTest : public testing::Test { public: - AudioDeviceListenerWinTest() - : com_init_(ScopedCOMInitializer::kMTA) { - } + AudioDeviceListenerWinTest() {} virtual void SetUp() { if (!CoreAudioUtil::IsSupported()) diff --git a/media/audio/win/audio_low_latency_input_win.cc b/media/audio/win/audio_low_latency_input_win.cc index 72d1d72..674a097 100644 --- a/media/audio/win/audio_low_latency_input_win.cc +++ b/media/audio/win/audio_low_latency_input_win.cc @@ -158,6 +158,11 @@ void WASAPIAudioInputStream::Start(AudioInputCallback* callback) { // using SetAutomaticGainControl(). StartAgc(); + if (!MarshalComPointers()) { + HandleError(S_FALSE); + return; + } + // Create and start the thread that will drive the capturing by waiting for // capture events. capture_thread_ = @@ -172,6 +177,8 @@ void WASAPIAudioInputStream::Start(AudioInputCallback* callback) { hr = audio_render_client_for_loopback_->Start(); started_ = SUCCEEDED(hr); + if (!started_) + HandleError(hr); } void WASAPIAudioInputStream::Stop() { @@ -350,7 +357,7 @@ HRESULT WASAPIAudioInputStream::GetMixFormat(const std::string& device_id, } void WASAPIAudioInputStream::Run() { - ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA); + ScopedCOMInitializer com_init; // Increase the thread priority. capture_thread_->SetThreadPriority(base::ThreadPriority::REALTIME_AUDIO); @@ -369,6 +376,10 @@ void WASAPIAudioInputStream::Run() { LOG(WARNING) << "Failed to enable MMCSS (error code=" << err << ")."; } + // Retrieve COM pointers from the main thread. + ScopedComPtr<IAudioCaptureClient> audio_capture_client; + UnmarshalComPointers(&audio_capture_client); + // Allocate a buffer with a size that enables us to take care of cases like: // 1) The recorded buffer size is smaller, or does not match exactly with, // the selected packet size used in each callback. @@ -383,7 +394,7 @@ void WASAPIAudioInputStream::Run() { LARGE_INTEGER now_count; bool recording = true; bool error = false; - double volume = GetVolume(); + double volume = 0; HANDLE wait_array[2] = { stop_capture_event_.Get(), audio_samples_ready_event_.Get() }; @@ -412,11 +423,9 @@ void WASAPIAudioInputStream::Run() { // Retrieve the amount of data in the capture endpoint buffer, // replace it with silence if required, create callbacks for each // packet and store non-delivered data for the next event. - hr = audio_capture_client_->GetBuffer(&data_ptr, - &num_frames_to_read, - &flags, - &device_position, - &first_audio_frame_timestamp); + hr = audio_capture_client->GetBuffer( + &data_ptr, &num_frames_to_read, &flags, &device_position, + &first_audio_frame_timestamp); if (FAILED(hr)) { DLOG(ERROR) << "Failed to get data from the capture buffer"; continue; @@ -438,7 +447,7 @@ void WASAPIAudioInputStream::Run() { buffer_frame_index += num_frames_to_read; } - hr = audio_capture_client_->ReleaseBuffer(num_frames_to_read); + hr = audio_capture_client->ReleaseBuffer(num_frames_to_read); DLOG_IF(ERROR, FAILED(hr)) << "Failed to release capture buffer"; // Derive a delay estimate for the captured audio packet. @@ -676,8 +685,11 @@ HRESULT WASAPIAudioInputStream::InitializeAudioEngine() { &format_, (effects_ & AudioParameters::DUCKING) ? &kCommunicationsSessionId : NULL); - if (FAILED(hr)) + if (FAILED(hr)) { + PLOG(ERROR) << "Failed to initalize IAudioClient: " << std::hex << hr + << " : "; return hr; + } // Retrieve the length of the endpoint buffer shared between the client // and the audio engine. The buffer length determines the maximum amount @@ -768,4 +780,26 @@ HRESULT WASAPIAudioInputStream::InitializeAudioEngine() { return hr; } +bool WASAPIAudioInputStream::MarshalComPointers() { + DCHECK(CalledOnValidThread()); + DCHECK(!com_stream_); + HRESULT hr = CoMarshalInterThreadInterfaceInStream( + __uuidof(IAudioCaptureClient), audio_capture_client_.get(), + com_stream_.Receive()); + if (FAILED(hr)) + DLOG(ERROR) << "Marshal failed for IAudioCaptureClient: " << std::hex << hr; + DCHECK_EQ(SUCCEEDED(hr), !!com_stream_); + return SUCCEEDED(hr); +} + +void WASAPIAudioInputStream::UnmarshalComPointers( + ScopedComPtr<IAudioCaptureClient>* audio_capture_client) { + DCHECK_EQ(capture_thread_->tid(), base::PlatformThread::CurrentId()); + DCHECK(com_stream_); + HRESULT hr = CoGetInterfaceAndReleaseStream( + com_stream_.Detach(), __uuidof(IAudioCaptureClient), + audio_capture_client->ReceiveVoid()); + CHECK(SUCCEEDED(hr)); +} + } // namespace media diff --git a/media/audio/win/audio_low_latency_input_win.h b/media/audio/win/audio_low_latency_input_win.h index 7501405..00a7de7 100644 --- a/media/audio/win/audio_low_latency_input_win.h +++ b/media/audio/win/audio_low_latency_input_win.h @@ -131,6 +131,13 @@ class MEDIA_EXPORT WASAPIAudioInputStream WAVEFORMATEX** device_format, int* effects); + // Handles sharing of COM pointers between the audio and capture threads. The + // marshal method must be called on the audio manager thread, while unmarshal + // must be called on |capture_thread_|. + bool MarshalComPointers(); + void UnmarshalComPointers( + base::win::ScopedComPtr<IAudioCaptureClient>* audio_capture_client); + // Our creator, the audio manager needs to be notified when we close. AudioManagerWin* manager_; @@ -179,8 +186,17 @@ class MEDIA_EXPORT WASAPIAudioInputStream // Pointer to the object that will receive the recorded audio samples. AudioInputCallback* sink_; - // Windows Multimedia Device (MMDevice) API interfaces. + // ------------------------------------------------------ + // Warning: COM pointers must be marshaled from the audio thread to be used + // on any other thread. Do not use any of these interfaces on a thread other + // than the audio thread. See MarshalComPointers() and UnmarshalComPointers() + // for marshaling pointers to the capture thread. + + // Stream into which the COM pointers below are marshaled so that they can + // be used on another thread. + base::win::ScopedComPtr<IStream> com_stream_; + // Windows Multimedia Device (MMDevice) API interfaces. // An IMMDevice interface which represents an audio endpoint device. base::win::ScopedComPtr<IMMDevice> endpoint_device_; @@ -198,16 +214,17 @@ class MEDIA_EXPORT WASAPIAudioInputStream // details. base::win::ScopedComPtr<IAudioClient> audio_render_client_for_loopback_; - // The IAudioCaptureClient interface enables a client to read input data - // from a capture endpoint buffer. - base::win::ScopedComPtr<IAudioCaptureClient> audio_capture_client_; - // The ISimpleAudioVolume interface enables a client to control the // master volume level of an audio session. // The volume-level is a value in the range 0.0 to 1.0. // This interface does only work with shared-mode streams. base::win::ScopedComPtr<ISimpleAudioVolume> simple_audio_volume_; + // The IAudioCaptureClient interface enables a client to read input data + // from a capture endpoint buffer. + base::win::ScopedComPtr<IAudioCaptureClient> audio_capture_client_; + // ------------------------------------------------------ + // The audio engine will signal this event each time a buffer has been // recorded. base::win::ScopedHandle audio_samples_ready_event_; diff --git a/media/audio/win/audio_low_latency_input_win_unittest.cc b/media/audio/win/audio_low_latency_input_win_unittest.cc index 69a24f8..60d386d 100644 --- a/media/audio/win/audio_low_latency_input_win_unittest.cc +++ b/media/audio/win/audio_low_latency_input_win_unittest.cc @@ -163,11 +163,9 @@ static bool HasCoreAudioAndInputDevices(AudioManager* audio_man) { class AudioInputStreamWrapper { public: explicit AudioInputStreamWrapper(AudioManager* audio_manager) - : com_init_(ScopedCOMInitializer::kMTA), - audio_man_(audio_manager), - default_params_( - audio_manager->GetInputStreamParameters( - AudioManagerBase::kDefaultDeviceId)) { + : audio_man_(audio_manager), + default_params_(audio_man_->GetInputStreamParameters( + AudioManagerBase::kDefaultDeviceId)) { EXPECT_EQ(format(), AudioParameters::AUDIO_PCM_LOW_LATENCY); frames_per_buffer_ = default_params_.frames_per_buffer(); // We expect the default buffer size to be a 10ms buffer. @@ -207,7 +205,6 @@ class AudioInputStreamWrapper { return ais; } - ScopedCOMInitializer com_init_; AudioManager* audio_man_; const AudioParameters default_params_; int frames_per_buffer_; @@ -254,17 +251,24 @@ class ScopedAudioInputStream { DISALLOW_COPY_AND_ASSIGN(ScopedAudioInputStream); }; +class WinAudioInputTest : public testing::Test { + public: + WinAudioInputTest() : audio_manager_(AudioManager::CreateForTesting()) {} + ~WinAudioInputTest() override {} + + protected: + ScopedCOMInitializer com_init_; + scoped_ptr<AudioManager> audio_manager_; +}; + // Verify that we can retrieve the current hardware/mixing sample rate // for all available input devices. -TEST(WinAudioInputTest, WASAPIAudioInputStreamHardwareSampleRate) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager.get())); - - ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA); +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamHardwareSampleRate) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); // Retrieve a list of all available input devices. media::AudioDeviceNames device_names; - audio_manager->GetAudioInputDeviceNames(&device_names); + audio_manager_->GetAudioInputDeviceNames(&device_names); // Scan all available input devices and repeat the same test for all of them. for (media::AudioDeviceNames::const_iterator it = device_names.begin(); @@ -277,30 +281,27 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamHardwareSampleRate) { } // Test Create(), Close() calling sequence. -TEST(WinAudioInputTest, WASAPIAudioInputStreamCreateAndClose) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager.get())); +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamCreateAndClose) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ScopedAudioInputStream ais( - CreateDefaultAudioInputStream(audio_manager.get())); + CreateDefaultAudioInputStream(audio_manager_.get())); ais.Close(); } // Test Open(), Close() calling sequence. -TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenAndClose) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager.get())); +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenAndClose) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ScopedAudioInputStream ais( - CreateDefaultAudioInputStream(audio_manager.get())); + CreateDefaultAudioInputStream(audio_manager_.get())); EXPECT_TRUE(ais->Open()); ais.Close(); } // Test Open(), Start(), Close() calling sequence. -TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager.get())); +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ScopedAudioInputStream ais( - CreateDefaultAudioInputStream(audio_manager.get())); + CreateDefaultAudioInputStream(audio_manager_.get())); EXPECT_TRUE(ais->Open()); MockAudioInputCallback sink; ais->Start(&sink); @@ -308,11 +309,10 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) { } // Test Open(), Start(), Stop(), Close() calling sequence. -TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager.get())); +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ScopedAudioInputStream ais( - CreateDefaultAudioInputStream(audio_manager.get())); + CreateDefaultAudioInputStream(audio_manager_.get())); EXPECT_TRUE(ais->Open()); MockAudioInputCallback sink; ais->Start(&sink); @@ -321,11 +321,10 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) { } // Test some additional calling sequences. -TEST(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager.get())); +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ScopedAudioInputStream ais( - CreateDefaultAudioInputStream(audio_manager.get())); + CreateDefaultAudioInputStream(audio_manager_.get())); WASAPIAudioInputStream* wais = static_cast<WASAPIAudioInputStream*>(ais.get()); @@ -349,9 +348,8 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) { ais.Close(); } -TEST(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager.get())); +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); int count = 0; base::MessageLoopForUI loop; @@ -360,7 +358,7 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) { // Create default WASAPI input stream which records in stereo using // the shared mixing rate. The default buffer size is 10ms. - AudioInputStreamWrapper aisw(audio_manager.get()); + AudioInputStreamWrapper aisw(audio_manager_.get()); ScopedAudioInputStream ais(aisw.Create()); EXPECT_TRUE(ais->Open()); @@ -419,21 +417,20 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) { } // Test that we can capture a stream in loopback. -TEST(WinAudioInputTest, WASAPIAudioInputStreamLoopback) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(audio_manager->HasAudioOutputDevices() && +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamLoopback) { + ABORT_AUDIO_TEST_IF_NOT(audio_manager_->HasAudioOutputDevices() && CoreAudioUtil::IsSupported()); - AudioParameters params = audio_manager->GetInputStreamParameters( + AudioParameters params = audio_manager_->GetInputStreamParameters( AudioManagerBase::kLoopbackInputDeviceId); EXPECT_EQ(params.effects(), 0); AudioParameters output_params = - audio_manager->GetOutputStreamParameters(std::string()); + audio_manager_->GetOutputStreamParameters(std::string()); EXPECT_EQ(params.sample_rate(), output_params.sample_rate()); EXPECT_EQ(params.channel_layout(), output_params.channel_layout()); - ScopedAudioInputStream stream(audio_manager->MakeAudioInputStream( + ScopedAudioInputStream stream(audio_manager_->MakeAudioInputStream( params, AudioManagerBase::kLoopbackInputDeviceId)); ASSERT_TRUE(stream->Open()); FakeAudioInputCallback sink; @@ -453,16 +450,15 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamLoopback) { // To include disabled tests in test execution, just invoke the test program // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS // environment variable to a value greater than 0. -TEST(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager.get())); +TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); // Name of the output PCM file containing captured data. The output file // will be stored in the directory containing 'media_unittests.exe'. // Example of full name: \src\build\Debug\out_stereo_10sec.pcm. const char* file_name = "out_stereo_10sec.pcm"; - AudioInputStreamWrapper aisw(audio_manager.get()); + AudioInputStreamWrapper aisw(audio_manager_.get()); ScopedAudioInputStream ais(aisw.Create()); EXPECT_TRUE(ais->Open()); diff --git a/media/audio/win/audio_low_latency_output_win.cc b/media/audio/win/audio_low_latency_output_win.cc index f7b31a3..a9d637c 100644 --- a/media/audio/win/audio_low_latency_output_win.cc +++ b/media/audio/win/audio_low_latency_output_win.cc @@ -249,6 +249,11 @@ void WASAPIAudioOutputStream::Start(AudioSourceCallback* callback) { } num_written_frames_ = endpoint_buffer_size_frames_; + if (!MarshalComPointers()) { + callback->OnError(this); + return; + } + // Create and start the thread that will drive the rendering by waiting for // render events. render_thread_.reset( @@ -333,7 +338,7 @@ void WASAPIAudioOutputStream::GetVolume(double* volume) { } void WASAPIAudioOutputStream::Run() { - ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA); + ScopedCOMInitializer com_init; // Increase the thread priority. render_thread_->SetThreadPriority(base::ThreadPriority::REALTIME_AUDIO); @@ -352,6 +357,12 @@ void WASAPIAudioOutputStream::Run() { LOG(WARNING) << "Failed to enable MMCSS (error code=" << err << ")."; } + // Retrieve COM pointers from the main thread. + ScopedComPtr<IAudioClient> audio_client; + ScopedComPtr<IAudioRenderClient> audio_render_client; + ScopedComPtr<IAudioClock> audio_clock; + UnmarshalComPointers(&audio_client, &audio_render_client, &audio_clock); + HRESULT hr = S_FALSE; bool playing = true; @@ -362,7 +373,7 @@ void WASAPIAudioOutputStream::Run() { // The device frequency is the frequency generated by the hardware clock in // the audio device. The GetFrequency() method reports a constant frequency. - hr = audio_clock_->GetFrequency(&device_frequency); + hr = audio_clock->GetFrequency(&device_frequency); error = FAILED(hr); PLOG_IF(ERROR, error) << "Failed to acquire IAudioClock interface: " << std::hex << hr; @@ -383,7 +394,9 @@ void WASAPIAudioOutputStream::Run() { break; case WAIT_OBJECT_0 + 1: // |audio_samples_render_event_| has been set. - error = !RenderAudioFromSource(device_frequency); + error = !RenderAudioFromSource(device_frequency, audio_client.get(), + audio_render_client.get(), + audio_clock.get()); break; default: error = true; @@ -391,11 +404,11 @@ void WASAPIAudioOutputStream::Run() { } } - if (playing && error) { + if (playing && error && audio_client) { // Stop audio rendering since something has gone wrong in our main thread // loop. Note that, we are still in a "started" state, hence a Stop() call // is required to join the thread properly. - audio_client_->Stop(); + audio_client->Stop(); PLOG(ERROR) << "WASAPI rendering failed."; } @@ -405,7 +418,11 @@ void WASAPIAudioOutputStream::Run() { } } -bool WASAPIAudioOutputStream::RenderAudioFromSource(UINT64 device_frequency) { +bool WASAPIAudioOutputStream::RenderAudioFromSource( + UINT64 device_frequency, + IAudioClient* audio_client, + IAudioRenderClient* audio_render_client, + IAudioClock* audio_clock) { TRACE_EVENT0("audio", "RenderAudioFromSource"); HRESULT hr = S_FALSE; @@ -420,7 +437,7 @@ bool WASAPIAudioOutputStream::RenderAudioFromSource(UINT64 device_frequency) { if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { // Get the padding value which represents the amount of rendering // data that is queued up to play in the endpoint buffer. - hr = audio_client_->GetCurrentPadding(&num_queued_frames); + hr = audio_client->GetCurrentPadding(&num_queued_frames); num_available_frames = endpoint_buffer_size_frames_ - num_queued_frames; if (FAILED(hr)) { @@ -462,8 +479,7 @@ bool WASAPIAudioOutputStream::RenderAudioFromSource(UINT64 device_frequency) { for (size_t n = 0; n < num_packets; ++n) { // Grab all available space in the rendering endpoint buffer // into which the client can write a data packet. - hr = audio_render_client_->GetBuffer(packet_size_frames_, - &audio_data); + hr = audio_render_client->GetBuffer(packet_size_frames_, &audio_data); if (FAILED(hr)) { DLOG(ERROR) << "Failed to use rendering audio buffer: " << std::hex << hr; @@ -477,7 +493,7 @@ bool WASAPIAudioOutputStream::RenderAudioFromSource(UINT64 device_frequency) { // unit at the render side. UINT64 position = 0; uint32 audio_delay_bytes = 0; - hr = audio_clock_->GetPosition(&position, NULL); + hr = audio_clock->GetPosition(&position, NULL); if (SUCCEEDED(hr)) { // Stream position of the sample that is currently playing // through the speaker. @@ -517,7 +533,7 @@ bool WASAPIAudioOutputStream::RenderAudioFromSource(UINT64 device_frequency) { // Render silence if we were not able to fill up the buffer totally. DWORD flags = (num_filled_bytes < packet_size_bytes_) ? AUDCLNT_BUFFERFLAGS_SILENT : 0; - audio_render_client_->ReleaseBuffer(packet_size_frames_, flags); + audio_render_client->ReleaseBuffer(packet_size_frames_, flags); num_written_frames_ += packet_size_frames_; } @@ -622,4 +638,73 @@ void WASAPIAudioOutputStream::StopThread() { source_ = NULL; } +bool WASAPIAudioOutputStream::MarshalComPointers() { + DCHECK_EQ(creating_thread_id_, base::PlatformThread::CurrentId()); + DCHECK(!com_stream_); + + ScopedComPtr<IStream> com_stream; + HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, com_stream.Receive()); + if (FAILED(hr)) { + DLOG(ERROR) << "Failed to create stream for marshaling COM pointers."; + return false; + } + + hr = CoMarshalInterface(com_stream.get(), __uuidof(IAudioClient), + audio_client_.get(), MSHCTX_INPROC, NULL, + MSHLFLAGS_NORMAL); + if (FAILED(hr)) { + DLOG(ERROR) << "Marshal failed for IAudioClient: " << std::hex << hr; + return false; + } + + hr = CoMarshalInterface(com_stream.get(), __uuidof(IAudioRenderClient), + audio_render_client_.get(), MSHCTX_INPROC, NULL, + MSHLFLAGS_NORMAL); + if (FAILED(hr)) { + DLOG(ERROR) << "Marshal failed for IAudioRenderClient: " << std::hex << hr; + return false; + } + + hr = CoMarshalInterface(com_stream.get(), __uuidof(IAudioClock), + audio_clock_.get(), MSHCTX_INPROC, NULL, + MSHLFLAGS_NORMAL); + if (FAILED(hr)) { + DLOG(ERROR) << "Marshal failed for IAudioClock: " << std::hex << hr; + return false; + } + + LARGE_INTEGER pos = {0}; + hr = com_stream->Seek(pos, STREAM_SEEK_SET, NULL); + if (FAILED(hr)) { + DLOG(ERROR) << "Failed to seek IStream for marshaling: " << std::hex << hr; + return false; + } + + com_stream_ = com_stream.Pass(); + return true; +} + +void WASAPIAudioOutputStream::UnmarshalComPointers( + ScopedComPtr<IAudioClient>* audio_client, + ScopedComPtr<IAudioRenderClient>* audio_render_client, + ScopedComPtr<IAudioClock>* audio_clock) { + DCHECK_EQ(render_thread_->tid(), base::PlatformThread::CurrentId()); + + DCHECK(com_stream_); + ScopedComPtr<IStream> com_stream; + com_stream = com_stream_.Pass(); + + HRESULT hr = CoUnmarshalInterface(com_stream.get(), __uuidof(IAudioClient), + audio_client->ReceiveVoid()); + CHECK(SUCCEEDED(hr)); + + hr = CoUnmarshalInterface(com_stream.get(), __uuidof(IAudioRenderClient), + audio_render_client->ReceiveVoid()); + CHECK(SUCCEEDED(hr)); + + hr = CoUnmarshalInterface(com_stream.get(), __uuidof(IAudioClock), + audio_clock->ReceiveVoid()); + CHECK(SUCCEEDED(hr)); +} + } // namespace media diff --git a/media/audio/win/audio_low_latency_output_win.h b/media/audio/win/audio_low_latency_output_win.h index 9d612b3..30e791b 100644 --- a/media/audio/win/audio_low_latency_output_win.h +++ b/media/audio/win/audio_low_latency_output_win.h @@ -157,7 +157,10 @@ class MEDIA_EXPORT WASAPIAudioOutputStream : // Checks available amount of space in the endpoint buffer and reads // data from the client to fill up the buffer without causing audio // glitches. - bool RenderAudioFromSource(UINT64 device_frequency); + bool RenderAudioFromSource(UINT64 device_frequency, + IAudioClient* thread_audio_client, + IAudioRenderClient* thread_audio_render_client, + IAudioClock* thread_audio_clock); // Called when the device will be opened in exclusive mode and use the // application specified format. @@ -172,6 +175,15 @@ class MEDIA_EXPORT WASAPIAudioOutputStream : // |source_| is set to NULL. void StopThread(); + // Handles sharing of COM pointers between the audio and render threads. The + // marshal method must be called on the audio manager thread, while unmarshal + // must be called on |render_thread_|. + bool MarshalComPointers(); + void UnmarshalComPointers( + base::win::ScopedComPtr<IAudioClient>* audio_client, + base::win::ScopedComPtr<IAudioRenderClient>* audio_render_client, + base::win::ScopedComPtr<IAudioClock>* audio_clock); + // Contains the thread ID of the creating thread. base::PlatformThreadId creating_thread_id_; @@ -221,6 +233,18 @@ class MEDIA_EXPORT WASAPIAudioOutputStream : // Pointer to the client that will deliver audio samples to be played out. AudioSourceCallback* source_; + // ------------------------------------------------------ + // Warning: COM pointers must be marshaled from the audio thread to be used + // on any other thread. Do not use any of these interfaces on a thread other + // than the audio thread. See MarshalComPointers() and UnmarshalComPointers() + // for marshaling pointers to the render thread. + + // Stream into which the COM pointers below are marshaled so that they can + // be used on another thread. + base::win::ScopedComPtr<IStream> com_stream_; + + // Windows Audio Session API (WASAPI) interfaces. + // An IAudioClient interface which enables a client to create and initialize // an audio stream between an audio application and the audio engine. base::win::ScopedComPtr<IAudioClient> audio_client_; @@ -229,6 +253,9 @@ class MEDIA_EXPORT WASAPIAudioOutputStream : // data to a rendering endpoint buffer. base::win::ScopedComPtr<IAudioRenderClient> audio_render_client_; + base::win::ScopedComPtr<IAudioClock> audio_clock_; + // ------------------------------------------------------ + // The audio engine will signal this event each time a buffer becomes // ready to be filled by the client. base::win::ScopedHandle audio_samples_render_event_; @@ -239,8 +266,6 @@ class MEDIA_EXPORT WASAPIAudioOutputStream : // Container for retrieving data from AudioSourceCallback::OnMoreData(). scoped_ptr<AudioBus> audio_bus_; - base::win::ScopedComPtr<IAudioClock> audio_clock_; - DISALLOW_COPY_AND_ASSIGN(WASAPIAudioOutputStream); }; diff --git a/media/audio/win/audio_low_latency_output_win_unittest.cc b/media/audio/win/audio_low_latency_output_win_unittest.cc index afd565a..193c082 100644 --- a/media/audio/win/audio_low_latency_output_win_unittest.cc +++ b/media/audio/win/audio_low_latency_output_win_unittest.cc @@ -6,6 +6,7 @@ #include <mmsystem.h> #include "base/basictypes.h" +#include "base/bind.h" #include "base/environment.h" #include "base/files/file_util.h" #include "base/memory/scoped_ptr.h" @@ -226,14 +227,24 @@ static AudioOutputStream* CreateDefaultAudioOutputStream( return aos; } +class WASAPIAudioOutputStreamTest : public testing::Test { + public: + WASAPIAudioOutputStreamTest() + : audio_manager_(AudioManager::CreateForTesting()) {} + ~WASAPIAudioOutputStreamTest() override {} + + protected: + ScopedCOMInitializer com_init_; + scoped_ptr<AudioManager> audio_manager_; +}; + // Verify that we can retrieve the current hardware/mixing sample rate // for the default audio device. // TODO(henrika): modify this test when we support full device enumeration. -TEST(WASAPIAudioOutputStreamTest, HardwareSampleRate) { +TEST_F(WASAPIAudioOutputStreamTest, HardwareSampleRate) { // Skip this test in exclusive mode since the resulting rate is only utilized // for shared mode streams. - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager.get()) && + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()) && ExclusiveModeIsEnabled()); // Default device intended for games, system notification sounds, @@ -244,27 +255,24 @@ TEST(WASAPIAudioOutputStreamTest, HardwareSampleRate) { } // Test Create(), Close() calling sequence. -TEST(WASAPIAudioOutputStreamTest, CreateAndClose) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager.get())); - AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager.get()); +TEST_F(WASAPIAudioOutputStreamTest, CreateAndClose) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get())); + AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager_.get()); aos->Close(); } // Test Open(), Close() calling sequence. -TEST(WASAPIAudioOutputStreamTest, OpenAndClose) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager.get())); - AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager.get()); +TEST_F(WASAPIAudioOutputStreamTest, OpenAndClose) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get())); + AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager_.get()); EXPECT_TRUE(aos->Open()); aos->Close(); } // Test Open(), Start(), Close() calling sequence. -TEST(WASAPIAudioOutputStreamTest, OpenStartAndClose) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager.get())); - AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager.get()); +TEST_F(WASAPIAudioOutputStreamTest, OpenStartAndClose) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get())); + AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager_.get()); EXPECT_TRUE(aos->Open()); MockAudioSourceCallback source; EXPECT_CALL(source, OnError(aos)) @@ -274,10 +282,9 @@ TEST(WASAPIAudioOutputStreamTest, OpenStartAndClose) { } // Test Open(), Start(), Stop(), Close() calling sequence. -TEST(WASAPIAudioOutputStreamTest, OpenStartStopAndClose) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager.get())); - AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager.get()); +TEST_F(WASAPIAudioOutputStreamTest, OpenStartStopAndClose) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get())); + AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager_.get()); EXPECT_TRUE(aos->Open()); MockAudioSourceCallback source; EXPECT_CALL(source, OnError(aos)) @@ -288,10 +295,9 @@ TEST(WASAPIAudioOutputStreamTest, OpenStartStopAndClose) { } // Test SetVolume(), GetVolume() -TEST(WASAPIAudioOutputStreamTest, Volume) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager.get())); - AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager.get()); +TEST_F(WASAPIAudioOutputStreamTest, Volume) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get())); + AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager_.get()); // Initial volume should be full volume (1.0). double volume = 0.0; @@ -324,11 +330,10 @@ TEST(WASAPIAudioOutputStreamTest, Volume) { } // Test some additional calling sequences. -TEST(WASAPIAudioOutputStreamTest, MiscCallingSequences) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager.get())); +TEST_F(WASAPIAudioOutputStreamTest, MiscCallingSequences) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get())); - AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager.get()); + AudioOutputStream* aos = CreateDefaultAudioOutputStream(audio_manager_.get()); WASAPIAudioOutputStream* waos = static_cast<WASAPIAudioOutputStream*>(aos); // Open(), Open() is a valid calling sequence (second call does nothing). @@ -363,16 +368,15 @@ TEST(WASAPIAudioOutputStreamTest, MiscCallingSequences) { } // Use preferred packet size and verify that rendering starts. -TEST(WASAPIAudioOutputStreamTest, ValidPacketSize) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager.get())); +TEST_F(WASAPIAudioOutputStreamTest, ValidPacketSize) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get())); base::MessageLoopForUI loop; MockAudioSourceCallback source; // Create default WASAPI output stream which plays out in stereo using // the shared mixing rate. The default buffer size is 10ms. - AudioOutputStreamWrapper aosw(audio_manager.get()); + AudioOutputStreamWrapper aosw(audio_manager_.get()); AudioOutputStream* aos = aosw.Create(); EXPECT_TRUE(aos->Open()); @@ -401,11 +405,10 @@ TEST(WASAPIAudioOutputStreamTest, ValidPacketSize) { // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS // environment variable to a value greater than 0. // The test files are approximately 20 seconds long. -TEST(WASAPIAudioOutputStreamTest, DISABLED_ReadFromStereoFile) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager.get())); +TEST_F(WASAPIAudioOutputStreamTest, DISABLED_ReadFromStereoFile) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get())); - AudioOutputStreamWrapper aosw(audio_manager.get()); + AudioOutputStreamWrapper aosw(audio_manager_.get()); AudioOutputStream* aos = aosw.Create(); EXPECT_TRUE(aos->Open()); @@ -450,12 +453,11 @@ TEST(WASAPIAudioOutputStreamTest, DISABLED_ReadFromStereoFile) { // certain set of audio parameters and a sample rate of 48kHz. // The expected outcomes of each setting in this test has been derived // manually using log outputs (--v=1). -TEST(WASAPIAudioOutputStreamTest, ExclusiveModeBufferSizesAt48kHz) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager.get()) && +TEST_F(WASAPIAudioOutputStreamTest, ExclusiveModeBufferSizesAt48kHz) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()) && ExclusiveModeIsEnabled()); - AudioOutputStreamWrapper aosw(audio_manager.get()); + AudioOutputStreamWrapper aosw(audio_manager_.get()); // 10ms @ 48kHz shall work. // Note that, this is the same size as we can use for shared-mode streaming @@ -498,12 +500,11 @@ TEST(WASAPIAudioOutputStreamTest, ExclusiveModeBufferSizesAt48kHz) { // certain set of audio parameters and a sample rate of 44.1kHz. // The expected outcomes of each setting in this test has been derived // manually using log outputs (--v=1). -TEST(WASAPIAudioOutputStreamTest, ExclusiveModeBufferSizesAt44kHz) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager.get()) && +TEST_F(WASAPIAudioOutputStreamTest, ExclusiveModeBufferSizesAt44kHz) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()) && ExclusiveModeIsEnabled()); - AudioOutputStreamWrapper aosw(audio_manager.get()); + AudioOutputStreamWrapper aosw(audio_manager_.get()); // 10ms @ 44.1kHz does not work due to misalignment. // This test will propose an aligned buffer size of 10.1587ms. @@ -553,9 +554,8 @@ TEST(WASAPIAudioOutputStreamTest, ExclusiveModeBufferSizesAt44kHz) { // Verify that we can open and start the output stream in exclusive mode at // the lowest possible delay at 48kHz. -TEST(WASAPIAudioOutputStreamTest, ExclusiveModeMinBufferSizeAt48kHz) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager.get()) && +TEST_F(WASAPIAudioOutputStreamTest, ExclusiveModeMinBufferSizeAt48kHz) { + ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndOutputDevices(audio_manager_.get()) && ExclusiveModeIsEnabled()); base::MessageLoopForUI loop; @@ -563,7 +563,7 @@ TEST(WASAPIAudioOutputStreamTest, ExclusiveModeMinBufferSizeAt48kHz) { // Create exclusive-mode WASAPI output stream which plays out in stereo // using the minimum buffer size at 48kHz sample rate. - AudioOutputStreamWrapper aosw(audio_manager.get()); + AudioOutputStreamWrapper aosw(audio_manager_.get()); AudioOutputStream* aos = aosw.Create(48000, 160); EXPECT_TRUE(aos->Open()); @@ -588,16 +588,15 @@ TEST(WASAPIAudioOutputStreamTest, ExclusiveModeMinBufferSizeAt48kHz) { // Verify that we can open and start the output stream in exclusive mode at // the lowest possible delay at 44.1kHz. -TEST(WASAPIAudioOutputStreamTest, ExclusiveModeMinBufferSizeAt44kHz) { +TEST_F(WASAPIAudioOutputStreamTest, ExclusiveModeMinBufferSizeAt44kHz) { ABORT_AUDIO_TEST_IF_NOT(ExclusiveModeIsEnabled()); - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); base::MessageLoopForUI loop; MockAudioSourceCallback source; // Create exclusive-mode WASAPI output stream which plays out in stereo // using the minimum buffer size at 44.1kHz sample rate. - AudioOutputStreamWrapper aosw(audio_manager.get()); + AudioOutputStreamWrapper aosw(audio_manager_.get()); AudioOutputStream* aos = aosw.Create(44100, 160); EXPECT_TRUE(aos->Open()); diff --git a/media/audio/win/audio_manager_win.h b/media/audio/win/audio_manager_win.h index 9826566..afd1ef9 100644 --- a/media/audio/win/audio_manager_win.h +++ b/media/audio/win/audio_manager_win.h @@ -64,9 +64,7 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase { EnumerationType enumeration_type_; EnumerationType enumeration_type() { return enumeration_type_; } - void SetEnumerationType(EnumerationType type) { - enumeration_type_ = type; - } + void set_enumeration_type(EnumerationType type) { enumeration_type_ = type; } inline bool core_audio_supported() const { return enumeration_type_ == kMMDeviceEnumeration; diff --git a/media/audio/win/audio_output_win_unittest.cc b/media/audio/win/audio_output_win_unittest.cc index 93454fc..c1dc5b4 100644 --- a/media/audio/win/audio_output_win_unittest.cc +++ b/media/audio/win/audio_output_win_unittest.cc @@ -427,7 +427,7 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) { ABORT_AUDIO_TEST_IF_NOT(audio_man->HasAudioOutputDevices()); // The WASAPI API requires a correct COM environment. - ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA); + ScopedCOMInitializer com_init; // Use 10 ms buffer size for WASAPI and 50 ms buffer size for Wave. // Take the existing native sample rate into account. diff --git a/media/audio/win/core_audio_util_win.cc b/media/audio/win/core_audio_util_win.cc index 53530df..4f72564 100644 --- a/media/audio/win/core_audio_util_win.cc +++ b/media/audio/win/core_audio_util_win.cc @@ -178,10 +178,12 @@ static ScopedComPtr<IMMDeviceEnumerator> CreateDeviceEnumeratorInternal() { // fail with CO_E_NOTINITIALIZED in combination with certain 3rd party // modules. Calling CoInitializeEx is an attempt to resolve the reported // issues. See http://crbug.com/378465 for details. - hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (SUCCEEDED(hr)) { - hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator), - NULL, CLSCTX_INPROC_SERVER); + hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator), NULL, + CLSCTX_INPROC_SERVER); + } else { + LOG(ERROR) << "CoCreateInstance still failed! " << std::hex << hr; } } return device_enumerator; diff --git a/media/audio/win/core_audio_util_win_unittest.cc b/media/audio/win/core_audio_util_win_unittest.cc index 31f91e9..1a24e5d 100644 --- a/media/audio/win/core_audio_util_win_unittest.cc +++ b/media/audio/win/core_audio_util_win_unittest.cc @@ -19,13 +19,10 @@ namespace media { class CoreAudioUtilWinTest : public ::testing::Test { protected: - // The test runs on a COM thread in the multithreaded apartment (MTA). + // The test runs on a COM thread in the singlethreaded apartment (STA). // If we don't initialize the COM library on a thread before using COM, // all function calls will return CO_E_NOTINITIALIZED. - CoreAudioUtilWinTest() - : com_init_(ScopedCOMInitializer::kMTA) { - DCHECK(com_init_.succeeded()); - } + CoreAudioUtilWinTest() { DCHECK(com_init_.succeeded()); } virtual ~CoreAudioUtilWinTest() {} bool DevicesAvailable() { diff --git a/media/audio/win/device_enumeration_win.h b/media/audio/win/device_enumeration_win.h index e61a331..e6485db 100644 --- a/media/audio/win/device_enumeration_win.h +++ b/media/audio/win/device_enumeration_win.h @@ -17,7 +17,7 @@ namespace media { // Example record in the output list: // - device_name: "Microphone (Realtek High Definition Audio)". // - unique_id: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}" -// This method must be called from a COM thread using MTA. +// This method must be called from a COM thread using STA. bool GetInputDeviceNamesWin(media::AudioDeviceNames* device_names); bool GetOutputDeviceNamesWin(media::AudioDeviceNames* device_names); |