1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/memory/scoped_ptr.h"
6 #include "base/strings/utf_string_conversions.h"
7 #include "base/synchronization/waitable_event.h"
8 #include "base/win/scoped_co_mem.h"
9 #include "base/win/scoped_com_initializer.h"
10 #include "base/win/scoped_handle.h"
11 #include "media/audio/audio_manager_base.h"
12 #include "media/audio/audio_unittest_util.h"
13 #include "media/audio/win/core_audio_util_win.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 using base::win::ScopedCOMInitializer
;
21 class CoreAudioUtilWinTest
: public ::testing::Test
{
23 // The tests must run on a COM thread.
24 // If we don't initialize the COM library on a thread before using COM,
25 // all function calls will return CO_E_NOTINITIALIZED.
26 CoreAudioUtilWinTest() {
27 DCHECK(com_init_
.succeeded());
29 ~CoreAudioUtilWinTest() override
{}
31 bool DevicesAvailable() {
32 return CoreAudioUtil::IsSupported() &&
33 CoreAudioUtil::NumberOfActiveDevices(eCapture
) > 0 &&
34 CoreAudioUtil::NumberOfActiveDevices(eRender
) > 0;
37 ScopedCOMInitializer com_init_
;
40 TEST_F(CoreAudioUtilWinTest
, NumberOfActiveDevices
) {
41 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
43 int render_devices
= CoreAudioUtil::NumberOfActiveDevices(eRender
);
44 EXPECT_GT(render_devices
, 0);
45 int capture_devices
= CoreAudioUtil::NumberOfActiveDevices(eCapture
);
46 EXPECT_GT(capture_devices
, 0);
47 int total_devices
= CoreAudioUtil::NumberOfActiveDevices(eAll
);
48 EXPECT_EQ(total_devices
, render_devices
+ capture_devices
);
51 TEST_F(CoreAudioUtilWinTest
, CreateDeviceEnumerator
) {
52 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
54 ScopedComPtr
<IMMDeviceEnumerator
> enumerator
=
55 CoreAudioUtil::CreateDeviceEnumerator();
56 EXPECT_TRUE(enumerator
.get());
59 TEST_F(CoreAudioUtilWinTest
, CreateDefaultDevice
) {
60 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
67 {eRender
, eCommunications
},
68 {eRender
, eMultimedia
},
70 {eCapture
, eCommunications
},
71 {eCapture
, eMultimedia
}
74 // Create default devices for all flow/role combinations above.
75 ScopedComPtr
<IMMDevice
> audio_device
;
76 for (int i
= 0; i
< arraysize(data
); ++i
) {
78 CoreAudioUtil::CreateDefaultDevice(data
[i
].flow
, data
[i
].role
);
79 EXPECT_TRUE(audio_device
.get());
80 EXPECT_EQ(data
[i
].flow
, CoreAudioUtil::GetDataFlow(audio_device
.get()));
83 // Only eRender and eCapture are allowed as flow parameter.
84 audio_device
= CoreAudioUtil::CreateDefaultDevice(eAll
, eConsole
);
85 EXPECT_FALSE(audio_device
.get());
88 TEST_F(CoreAudioUtilWinTest
, CreateDevice
) {
89 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
91 // Get name and ID of default device used for playback.
92 ScopedComPtr
<IMMDevice
> default_render_device
=
93 CoreAudioUtil::CreateDefaultDevice(eRender
, eConsole
);
94 AudioDeviceName default_render_name
;
95 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(
96 default_render_device
.get(), &default_render_name
)));
98 // Use the uniqe ID as input to CreateDevice() and create a corresponding
100 ScopedComPtr
<IMMDevice
> audio_device
=
101 CoreAudioUtil::CreateDevice(default_render_name
.unique_id
);
102 EXPECT_TRUE(audio_device
.get());
104 // Verify that the two IMMDevice interfaces represents the same endpoint
105 // by comparing their unique IDs.
106 AudioDeviceName device_name
;
107 EXPECT_TRUE(SUCCEEDED(
108 CoreAudioUtil::GetDeviceName(audio_device
.get(), &device_name
)));
109 EXPECT_EQ(default_render_name
.unique_id
, device_name
.unique_id
);
112 TEST_F(CoreAudioUtilWinTest
, GetDefaultDeviceName
) {
113 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
120 {eRender
, eCommunications
},
121 {eCapture
, eConsole
},
122 {eCapture
, eCommunications
}
125 // Get name and ID of default devices for all flow/role combinations above.
126 ScopedComPtr
<IMMDevice
> audio_device
;
127 AudioDeviceName device_name
;
128 for (int i
= 0; i
< arraysize(data
); ++i
) {
130 CoreAudioUtil::CreateDefaultDevice(data
[i
].flow
, data
[i
].role
);
131 EXPECT_TRUE(SUCCEEDED(
132 CoreAudioUtil::GetDeviceName(audio_device
.get(), &device_name
)));
133 EXPECT_FALSE(device_name
.device_name
.empty());
134 EXPECT_FALSE(device_name
.unique_id
.empty());
138 TEST_F(CoreAudioUtilWinTest
, GetAudioControllerID
) {
139 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
141 ScopedComPtr
<IMMDeviceEnumerator
> enumerator(
142 CoreAudioUtil::CreateDeviceEnumerator());
143 ASSERT_TRUE(enumerator
.get());
145 // Enumerate all active input and output devices and fetch the ID of
146 // the associated device.
147 EDataFlow flows
[] = { eRender
, eCapture
};
148 for (int i
= 0; i
< arraysize(flows
); ++i
) {
149 ScopedComPtr
<IMMDeviceCollection
> collection
;
150 ASSERT_TRUE(SUCCEEDED(enumerator
->EnumAudioEndpoints(flows
[i
],
151 DEVICE_STATE_ACTIVE
, collection
.Receive())));
153 collection
->GetCount(&count
);
154 for (UINT j
= 0; j
< count
; ++j
) {
155 ScopedComPtr
<IMMDevice
> device
;
156 collection
->Item(j
, device
.Receive());
157 std::string
controller_id(
158 CoreAudioUtil::GetAudioControllerID(device
.get(), enumerator
.get()));
159 EXPECT_FALSE(controller_id
.empty());
164 TEST_F(CoreAudioUtilWinTest
, GetFriendlyName
) {
165 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
167 // Get name and ID of default device used for recording.
168 ScopedComPtr
<IMMDevice
> audio_device
=
169 CoreAudioUtil::CreateDefaultDevice(eCapture
, eConsole
);
170 AudioDeviceName device_name
;
171 HRESULT hr
= CoreAudioUtil::GetDeviceName(audio_device
.get(), &device_name
);
172 EXPECT_TRUE(SUCCEEDED(hr
));
174 // Use unique ID as input to GetFriendlyName() and compare the result
175 // with the already obtained friendly name for the default capture device.
176 std::string friendly_name
= CoreAudioUtil::GetFriendlyName(
177 device_name
.unique_id
);
178 EXPECT_EQ(friendly_name
, device_name
.device_name
);
180 // Same test as above but for playback.
181 audio_device
= CoreAudioUtil::CreateDefaultDevice(eRender
, eConsole
);
182 hr
= CoreAudioUtil::GetDeviceName(audio_device
.get(), &device_name
);
183 EXPECT_TRUE(SUCCEEDED(hr
));
184 friendly_name
= CoreAudioUtil::GetFriendlyName(device_name
.unique_id
);
185 EXPECT_EQ(friendly_name
, device_name
.device_name
);
188 TEST_F(CoreAudioUtilWinTest
, DeviceIsDefault
) {
189 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
191 // Verify that the default render device is correctly identified as a
193 ScopedComPtr
<IMMDevice
> audio_device
=
194 CoreAudioUtil::CreateDefaultDevice(eRender
, eConsole
);
195 AudioDeviceName name
;
197 SUCCEEDED(CoreAudioUtil::GetDeviceName(audio_device
.get(), &name
)));
198 const std::string id
= name
.unique_id
;
199 EXPECT_TRUE(CoreAudioUtil::DeviceIsDefault(eRender
, eConsole
, id
));
200 EXPECT_FALSE(CoreAudioUtil::DeviceIsDefault(eCapture
, eConsole
, id
));
203 TEST_F(CoreAudioUtilWinTest
, CreateDefaultClient
) {
204 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
206 EDataFlow data
[] = {eRender
, eCapture
};
208 for (int i
= 0; i
< arraysize(data
); ++i
) {
209 ScopedComPtr
<IAudioClient
> client
;
210 client
= CoreAudioUtil::CreateDefaultClient(data
[i
], eConsole
);
211 EXPECT_TRUE(client
.get());
215 TEST_F(CoreAudioUtilWinTest
, CreateClient
) {
216 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
218 EDataFlow data
[] = {eRender
, eCapture
};
220 for (int i
= 0; i
< arraysize(data
); ++i
) {
221 ScopedComPtr
<IMMDevice
> device
;
222 ScopedComPtr
<IAudioClient
> client
;
223 device
= CoreAudioUtil::CreateDefaultDevice(data
[i
], eConsole
);
224 EXPECT_TRUE(device
.get());
225 EXPECT_EQ(data
[i
], CoreAudioUtil::GetDataFlow(device
.get()));
226 client
= CoreAudioUtil::CreateClient(device
.get());
227 EXPECT_TRUE(client
.get());
231 TEST_F(CoreAudioUtilWinTest
, GetSharedModeMixFormat
) {
232 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
234 ScopedComPtr
<IMMDevice
> device
;
235 ScopedComPtr
<IAudioClient
> client
;
236 device
= CoreAudioUtil::CreateDefaultDevice(eRender
, eConsole
);
237 EXPECT_TRUE(device
.get());
238 client
= CoreAudioUtil::CreateClient(device
.get());
239 EXPECT_TRUE(client
.get());
241 // Perform a simple sanity test of the aquired format structure.
242 WAVEFORMATPCMEX format
;
244 SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client
.get(), &format
)));
245 EXPECT_GE(format
.Format
.nChannels
, 1);
246 EXPECT_GE(format
.Format
.nSamplesPerSec
, 8000u);
247 EXPECT_GE(format
.Format
.wBitsPerSample
, 16);
248 EXPECT_GE(format
.Samples
.wValidBitsPerSample
, 16);
249 EXPECT_EQ(format
.Format
.wFormatTag
, WAVE_FORMAT_EXTENSIBLE
);
252 TEST_F(CoreAudioUtilWinTest
, IsChannelLayoutSupported
) {
253 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
255 // The preferred channel layout should always be supported. Being supported
256 // means that it is possible to initialize a shared mode stream with the
257 // particular channel layout.
258 AudioParameters mix_params
;
259 HRESULT hr
= CoreAudioUtil::GetPreferredAudioParameters(
260 AudioManagerBase::kDefaultDeviceId
, true, &mix_params
);
261 EXPECT_TRUE(SUCCEEDED(hr
));
262 EXPECT_TRUE(mix_params
.IsValid());
263 EXPECT_TRUE(CoreAudioUtil::IsChannelLayoutSupported(
264 std::string(), eRender
, eConsole
, mix_params
.channel_layout()));
266 // Check if it is possible to modify the channel layout to stereo for a
267 // device which reports that it prefers to be openen up in an other
268 // channel configuration.
269 if (mix_params
.channel_layout() != CHANNEL_LAYOUT_STEREO
) {
270 ChannelLayout channel_layout
= CHANNEL_LAYOUT_STEREO
;
271 // TODO(henrika): it might be too pessimistic to assume false as return
273 EXPECT_FALSE(CoreAudioUtil::IsChannelLayoutSupported(
274 std::string(), eRender
, eConsole
, channel_layout
));
278 TEST_F(CoreAudioUtilWinTest
, GetDevicePeriod
) {
279 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
281 EDataFlow data
[] = {eRender
, eCapture
};
283 // Verify that the device periods are valid for the default render and
285 for (int i
= 0; i
< arraysize(data
); ++i
) {
286 ScopedComPtr
<IAudioClient
> client
;
287 REFERENCE_TIME shared_time_period
= 0;
288 REFERENCE_TIME exclusive_time_period
= 0;
289 client
= CoreAudioUtil::CreateDefaultClient(data
[i
], eConsole
);
290 EXPECT_TRUE(client
.get());
291 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDevicePeriod(
292 client
.get(), AUDCLNT_SHAREMODE_SHARED
, &shared_time_period
)));
293 EXPECT_GT(shared_time_period
, 0);
294 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDevicePeriod(
295 client
.get(), AUDCLNT_SHAREMODE_EXCLUSIVE
, &exclusive_time_period
)));
296 EXPECT_GT(exclusive_time_period
, 0);
297 EXPECT_LE(exclusive_time_period
, shared_time_period
);
301 TEST_F(CoreAudioUtilWinTest
, GetPreferredAudioParameters
) {
302 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
304 EDataFlow data
[] = {eRender
, eCapture
};
306 // Verify that the preferred audio parameters are OK for the default render
307 // and capture devices.
308 for (int i
= 0; i
< arraysize(data
); ++i
) {
309 ScopedComPtr
<IAudioClient
> client
;
310 AudioParameters params
;
311 client
= CoreAudioUtil::CreateDefaultClient(data
[i
], eConsole
);
312 EXPECT_TRUE(client
.get());
313 EXPECT_TRUE(SUCCEEDED(
314 CoreAudioUtil::GetPreferredAudioParameters(client
.get(), ¶ms
)));
315 EXPECT_TRUE(params
.IsValid());
319 TEST_F(CoreAudioUtilWinTest
, SharedModeInitialize
) {
320 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
322 ScopedComPtr
<IAudioClient
> client
;
323 client
= CoreAudioUtil::CreateDefaultClient(eRender
, eConsole
);
324 EXPECT_TRUE(client
.get());
326 WAVEFORMATPCMEX format
;
328 SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client
.get(), &format
)));
330 // Perform a shared-mode initialization without event-driven buffer handling.
331 uint32 endpoint_buffer_size
= 0;
332 HRESULT hr
= CoreAudioUtil::SharedModeInitialize(client
.get(), &format
, NULL
,
333 &endpoint_buffer_size
, NULL
);
334 EXPECT_TRUE(SUCCEEDED(hr
));
335 EXPECT_GT(endpoint_buffer_size
, 0u);
337 // It is only possible to create a client once.
338 hr
= CoreAudioUtil::SharedModeInitialize(client
.get(), &format
, NULL
,
339 &endpoint_buffer_size
, NULL
);
340 EXPECT_FALSE(SUCCEEDED(hr
));
341 EXPECT_EQ(hr
, AUDCLNT_E_ALREADY_INITIALIZED
);
343 // Verify that it is possible to reinitialize the client after releasing it.
344 client
= CoreAudioUtil::CreateDefaultClient(eRender
, eConsole
);
345 EXPECT_TRUE(client
.get());
346 hr
= CoreAudioUtil::SharedModeInitialize(client
.get(), &format
, NULL
,
347 &endpoint_buffer_size
, NULL
);
348 EXPECT_TRUE(SUCCEEDED(hr
));
349 EXPECT_GT(endpoint_buffer_size
, 0u);
351 // Use a non-supported format and verify that initialization fails.
352 // A simple way to emulate an invalid format is to use the shared-mode
353 // mixing format and modify the preferred sample.
354 client
= CoreAudioUtil::CreateDefaultClient(eRender
, eConsole
);
355 EXPECT_TRUE(client
.get());
356 format
.Format
.nSamplesPerSec
= format
.Format
.nSamplesPerSec
+ 1;
357 EXPECT_FALSE(CoreAudioUtil::IsFormatSupported(
358 client
.get(), AUDCLNT_SHAREMODE_SHARED
, &format
));
359 hr
= CoreAudioUtil::SharedModeInitialize(client
.get(), &format
, NULL
,
360 &endpoint_buffer_size
, NULL
);
361 EXPECT_TRUE(FAILED(hr
));
362 EXPECT_EQ(hr
, E_INVALIDARG
);
364 // Finally, perform a shared-mode initialization using event-driven buffer
365 // handling. The event handle will be signaled when an audio buffer is ready
366 // to be processed by the client (not verified here).
367 // The event handle should be in the nonsignaled state.
368 base::win::ScopedHandle
event_handle(::CreateEvent(NULL
, TRUE
, FALSE
, NULL
));
369 client
= CoreAudioUtil::CreateDefaultClient(eRender
, eConsole
);
370 EXPECT_TRUE(client
.get());
372 SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client
.get(), &format
)));
373 EXPECT_TRUE(CoreAudioUtil::IsFormatSupported(
374 client
.get(), AUDCLNT_SHAREMODE_SHARED
, &format
));
375 hr
= CoreAudioUtil::SharedModeInitialize(
376 client
.get(), &format
, event_handle
.Get(), &endpoint_buffer_size
, NULL
);
377 EXPECT_TRUE(SUCCEEDED(hr
));
378 EXPECT_GT(endpoint_buffer_size
, 0u);
381 TEST_F(CoreAudioUtilWinTest
, CreateRenderAndCaptureClients
) {
382 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
384 EDataFlow data
[] = {eRender
, eCapture
};
386 WAVEFORMATPCMEX format
;
387 uint32 endpoint_buffer_size
= 0;
389 for (int i
= 0; i
< arraysize(data
); ++i
) {
390 ScopedComPtr
<IAudioClient
> client
;
391 ScopedComPtr
<IAudioRenderClient
> render_client
;
392 ScopedComPtr
<IAudioCaptureClient
> capture_client
;
394 client
= CoreAudioUtil::CreateDefaultClient(data
[i
], eConsole
);
395 EXPECT_TRUE(client
.get());
396 EXPECT_TRUE(SUCCEEDED(
397 CoreAudioUtil::GetSharedModeMixFormat(client
.get(), &format
)));
398 if (data
[i
] == eRender
) {
399 // It is not possible to create a render client using an unitialized
401 render_client
= CoreAudioUtil::CreateRenderClient(client
.get());
402 EXPECT_FALSE(render_client
.get());
404 // Do a proper initialization and verify that it works this time.
405 CoreAudioUtil::SharedModeInitialize(client
.get(), &format
, NULL
,
406 &endpoint_buffer_size
, NULL
);
407 render_client
= CoreAudioUtil::CreateRenderClient(client
.get());
408 EXPECT_TRUE(render_client
.get());
409 EXPECT_GT(endpoint_buffer_size
, 0u);
410 } else if (data
[i
] == eCapture
) {
411 // It is not possible to create a capture client using an unitialized
413 capture_client
= CoreAudioUtil::CreateCaptureClient(client
.get());
414 EXPECT_FALSE(capture_client
.get());
416 // Do a proper initialization and verify that it works this time.
417 CoreAudioUtil::SharedModeInitialize(client
.get(), &format
, NULL
,
418 &endpoint_buffer_size
, NULL
);
419 capture_client
= CoreAudioUtil::CreateCaptureClient(client
.get());
420 EXPECT_TRUE(capture_client
.get());
421 EXPECT_GT(endpoint_buffer_size
, 0u);
426 TEST_F(CoreAudioUtilWinTest
, FillRenderEndpointBufferWithSilence
) {
427 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
429 // Create default clients using the default mixing format for shared mode.
430 ScopedComPtr
<IAudioClient
> client(
431 CoreAudioUtil::CreateDefaultClient(eRender
, eConsole
));
432 EXPECT_TRUE(client
.get());
434 WAVEFORMATPCMEX format
;
435 uint32 endpoint_buffer_size
= 0;
437 SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client
.get(), &format
)));
438 CoreAudioUtil::SharedModeInitialize(client
.get(), &format
, NULL
,
439 &endpoint_buffer_size
, NULL
);
440 EXPECT_GT(endpoint_buffer_size
, 0u);
442 ScopedComPtr
<IAudioRenderClient
> render_client(
443 CoreAudioUtil::CreateRenderClient(client
.get()));
444 EXPECT_TRUE(render_client
.get());
446 // The endpoint audio buffer should not be filled up by default after being
448 UINT32 num_queued_frames
= 0;
449 client
->GetCurrentPadding(&num_queued_frames
);
450 EXPECT_EQ(num_queued_frames
, 0u);
452 // Fill it up with zeros and verify that the buffer is full.
453 // It is not possible to verify that the actual data consists of zeros
454 // since we can't access data that has already been sent to the endpoint
456 EXPECT_TRUE(CoreAudioUtil::FillRenderEndpointBufferWithSilence(
457 client
.get(), render_client
.get()));
458 client
->GetCurrentPadding(&num_queued_frames
);
459 EXPECT_EQ(num_queued_frames
, endpoint_buffer_size
);
462 // This test can only run on a machine that has audio hardware
463 // that has both input and output devices.
464 TEST_F(CoreAudioUtilWinTest
, GetMatchingOutputDeviceID
) {
465 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
467 bool found_a_pair
= false;
469 ScopedComPtr
<IMMDeviceEnumerator
> enumerator(
470 CoreAudioUtil::CreateDeviceEnumerator());
471 ASSERT_TRUE(enumerator
.get());
473 // Enumerate all active input and output devices and fetch the ID of
474 // the associated device.
475 ScopedComPtr
<IMMDeviceCollection
> collection
;
476 ASSERT_TRUE(SUCCEEDED(enumerator
->EnumAudioEndpoints(eCapture
,
477 DEVICE_STATE_ACTIVE
, collection
.Receive())));
479 collection
->GetCount(&count
);
480 for (UINT i
= 0; i
< count
&& !found_a_pair
; ++i
) {
481 ScopedComPtr
<IMMDevice
> device
;
482 collection
->Item(i
, device
.Receive());
483 base::win::ScopedCoMem
<WCHAR
> wide_id
;
484 device
->GetId(&wide_id
);
486 base::WideToUTF8(wide_id
, wcslen(wide_id
), &id
);
487 found_a_pair
= !CoreAudioUtil::GetMatchingOutputDeviceID(id
).empty();
490 EXPECT_TRUE(found_a_pair
);
493 TEST_F(CoreAudioUtilWinTest
, GetDefaultOutputDeviceID
) {
494 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
496 std::string
default_device_id(CoreAudioUtil::GetDefaultOutputDeviceID());
497 EXPECT_FALSE(default_device_id
.empty());