Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / media / audio / win / core_audio_util_win_unittest.cc
blobf337849eafb02c1ed809fb1a76e3b2884587609a
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_unittest_util.h"
12 #include "media/audio/win/core_audio_util_win.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 using base::win::ScopedCOMInitializer;
18 namespace media {
20 class CoreAudioUtilWinTest : public ::testing::Test {
21 protected:
22 // The tests must run on a COM thread.
23 // If we don't initialize the COM library on a thread before using COM,
24 // all function calls will return CO_E_NOTINITIALIZED.
25 CoreAudioUtilWinTest() {
26 DCHECK(com_init_.succeeded());
28 ~CoreAudioUtilWinTest() override {}
30 bool DevicesAvailable() {
31 return CoreAudioUtil::IsSupported() &&
32 CoreAudioUtil::NumberOfActiveDevices(eCapture) > 0 &&
33 CoreAudioUtil::NumberOfActiveDevices(eRender) > 0;
36 ScopedCOMInitializer com_init_;
39 TEST_F(CoreAudioUtilWinTest, NumberOfActiveDevices) {
40 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
42 int render_devices = CoreAudioUtil::NumberOfActiveDevices(eRender);
43 EXPECT_GT(render_devices, 0);
44 int capture_devices = CoreAudioUtil::NumberOfActiveDevices(eCapture);
45 EXPECT_GT(capture_devices, 0);
46 int total_devices = CoreAudioUtil::NumberOfActiveDevices(eAll);
47 EXPECT_EQ(total_devices, render_devices + capture_devices);
50 TEST_F(CoreAudioUtilWinTest, CreateDeviceEnumerator) {
51 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
53 ScopedComPtr<IMMDeviceEnumerator> enumerator =
54 CoreAudioUtil::CreateDeviceEnumerator();
55 EXPECT_TRUE(enumerator.get());
58 TEST_F(CoreAudioUtilWinTest, CreateDefaultDevice) {
59 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
61 struct {
62 EDataFlow flow;
63 ERole role;
64 } data[] = {
65 {eRender, eConsole},
66 {eRender, eCommunications},
67 {eRender, eMultimedia},
68 {eCapture, eConsole},
69 {eCapture, eCommunications},
70 {eCapture, eMultimedia}
73 // Create default devices for all flow/role combinations above.
74 ScopedComPtr<IMMDevice> audio_device;
75 for (int i = 0; i < arraysize(data); ++i) {
76 audio_device =
77 CoreAudioUtil::CreateDefaultDevice(data[i].flow, data[i].role);
78 EXPECT_TRUE(audio_device.get());
79 EXPECT_EQ(data[i].flow, CoreAudioUtil::GetDataFlow(audio_device.get()));
82 // Only eRender and eCapture are allowed as flow parameter.
83 audio_device = CoreAudioUtil::CreateDefaultDevice(eAll, eConsole);
84 EXPECT_FALSE(audio_device.get());
87 TEST_F(CoreAudioUtilWinTest, CreateDevice) {
88 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
90 // Get name and ID of default device used for playback.
91 ScopedComPtr<IMMDevice> default_render_device =
92 CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
93 AudioDeviceName default_render_name;
94 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(
95 default_render_device.get(), &default_render_name)));
97 // Use the uniqe ID as input to CreateDevice() and create a corresponding
98 // IMMDevice.
99 ScopedComPtr<IMMDevice> audio_device =
100 CoreAudioUtil::CreateDevice(default_render_name.unique_id);
101 EXPECT_TRUE(audio_device.get());
103 // Verify that the two IMMDevice interfaces represents the same endpoint
104 // by comparing their unique IDs.
105 AudioDeviceName device_name;
106 EXPECT_TRUE(SUCCEEDED(
107 CoreAudioUtil::GetDeviceName(audio_device.get(), &device_name)));
108 EXPECT_EQ(default_render_name.unique_id, device_name.unique_id);
111 TEST_F(CoreAudioUtilWinTest, GetDefaultDeviceName) {
112 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
114 struct {
115 EDataFlow flow;
116 ERole role;
117 } data[] = {
118 {eRender, eConsole},
119 {eRender, eCommunications},
120 {eCapture, eConsole},
121 {eCapture, eCommunications}
124 // Get name and ID of default devices for all flow/role combinations above.
125 ScopedComPtr<IMMDevice> audio_device;
126 AudioDeviceName device_name;
127 for (int i = 0; i < arraysize(data); ++i) {
128 audio_device =
129 CoreAudioUtil::CreateDefaultDevice(data[i].flow, data[i].role);
130 EXPECT_TRUE(SUCCEEDED(
131 CoreAudioUtil::GetDeviceName(audio_device.get(), &device_name)));
132 EXPECT_FALSE(device_name.device_name.empty());
133 EXPECT_FALSE(device_name.unique_id.empty());
137 TEST_F(CoreAudioUtilWinTest, GetAudioControllerID) {
138 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
140 ScopedComPtr<IMMDeviceEnumerator> enumerator(
141 CoreAudioUtil::CreateDeviceEnumerator());
142 ASSERT_TRUE(enumerator.get());
144 // Enumerate all active input and output devices and fetch the ID of
145 // the associated device.
146 EDataFlow flows[] = { eRender , eCapture };
147 for (int i = 0; i < arraysize(flows); ++i) {
148 ScopedComPtr<IMMDeviceCollection> collection;
149 ASSERT_TRUE(SUCCEEDED(enumerator->EnumAudioEndpoints(flows[i],
150 DEVICE_STATE_ACTIVE, collection.Receive())));
151 UINT count = 0;
152 collection->GetCount(&count);
153 for (UINT j = 0; j < count; ++j) {
154 ScopedComPtr<IMMDevice> device;
155 collection->Item(j, device.Receive());
156 std::string controller_id(
157 CoreAudioUtil::GetAudioControllerID(device.get(), enumerator.get()));
158 EXPECT_FALSE(controller_id.empty());
163 TEST_F(CoreAudioUtilWinTest, GetFriendlyName) {
164 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
166 // Get name and ID of default device used for recording.
167 ScopedComPtr<IMMDevice> audio_device =
168 CoreAudioUtil::CreateDefaultDevice(eCapture, eConsole);
169 AudioDeviceName device_name;
170 HRESULT hr = CoreAudioUtil::GetDeviceName(audio_device.get(), &device_name);
171 EXPECT_TRUE(SUCCEEDED(hr));
173 // Use unique ID as input to GetFriendlyName() and compare the result
174 // with the already obtained friendly name for the default capture device.
175 std::string friendly_name = CoreAudioUtil::GetFriendlyName(
176 device_name.unique_id);
177 EXPECT_EQ(friendly_name, device_name.device_name);
179 // Same test as above but for playback.
180 audio_device = CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
181 hr = CoreAudioUtil::GetDeviceName(audio_device.get(), &device_name);
182 EXPECT_TRUE(SUCCEEDED(hr));
183 friendly_name = CoreAudioUtil::GetFriendlyName(device_name.unique_id);
184 EXPECT_EQ(friendly_name, device_name.device_name);
187 TEST_F(CoreAudioUtilWinTest, DeviceIsDefault) {
188 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
190 // Verify that the default render device is correctly identified as a
191 // default device.
192 ScopedComPtr<IMMDevice> audio_device =
193 CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
194 AudioDeviceName name;
195 EXPECT_TRUE(
196 SUCCEEDED(CoreAudioUtil::GetDeviceName(audio_device.get(), &name)));
197 const std::string id = name.unique_id;
198 EXPECT_TRUE(CoreAudioUtil::DeviceIsDefault(eRender, eConsole, id));
199 EXPECT_FALSE(CoreAudioUtil::DeviceIsDefault(eCapture, eConsole, id));
202 TEST_F(CoreAudioUtilWinTest, CreateDefaultClient) {
203 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
205 EDataFlow data[] = {eRender, eCapture};
207 for (int i = 0; i < arraysize(data); ++i) {
208 ScopedComPtr<IAudioClient> client;
209 client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
210 EXPECT_TRUE(client.get());
214 TEST_F(CoreAudioUtilWinTest, CreateClient) {
215 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
217 EDataFlow data[] = {eRender, eCapture};
219 for (int i = 0; i < arraysize(data); ++i) {
220 ScopedComPtr<IMMDevice> device;
221 ScopedComPtr<IAudioClient> client;
222 device = CoreAudioUtil::CreateDefaultDevice(data[i], eConsole);
223 EXPECT_TRUE(device.get());
224 EXPECT_EQ(data[i], CoreAudioUtil::GetDataFlow(device.get()));
225 client = CoreAudioUtil::CreateClient(device.get());
226 EXPECT_TRUE(client.get());
230 TEST_F(CoreAudioUtilWinTest, GetSharedModeMixFormat) {
231 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
233 ScopedComPtr<IMMDevice> device;
234 ScopedComPtr<IAudioClient> client;
235 device = CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
236 EXPECT_TRUE(device.get());
237 client = CoreAudioUtil::CreateClient(device.get());
238 EXPECT_TRUE(client.get());
240 // Perform a simple sanity test of the aquired format structure.
241 WAVEFORMATPCMEX format;
242 EXPECT_TRUE(
243 SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client.get(), &format)));
244 EXPECT_GE(format.Format.nChannels, 1);
245 EXPECT_GE(format.Format.nSamplesPerSec, 8000u);
246 EXPECT_GE(format.Format.wBitsPerSample, 16);
247 EXPECT_GE(format.Samples.wValidBitsPerSample, 16);
248 EXPECT_EQ(format.Format.wFormatTag, WAVE_FORMAT_EXTENSIBLE);
251 TEST_F(CoreAudioUtilWinTest, IsChannelLayoutSupported) {
252 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
254 // The preferred channel layout should always be supported. Being supported
255 // means that it is possible to initialize a shared mode stream with the
256 // particular channel layout.
257 AudioParameters mix_params;
258 HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(eRender, eConsole,
259 &mix_params);
260 EXPECT_TRUE(SUCCEEDED(hr));
261 EXPECT_TRUE(mix_params.IsValid());
262 EXPECT_TRUE(CoreAudioUtil::IsChannelLayoutSupported(
263 std::string(), eRender, eConsole, mix_params.channel_layout()));
265 // Check if it is possible to modify the channel layout to stereo for a
266 // device which reports that it prefers to be openen up in an other
267 // channel configuration.
268 if (mix_params.channel_layout() != CHANNEL_LAYOUT_STEREO) {
269 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
270 // TODO(henrika): it might be too pessimistic to assume false as return
271 // value here.
272 EXPECT_FALSE(CoreAudioUtil::IsChannelLayoutSupported(
273 std::string(), eRender, eConsole, channel_layout));
277 TEST_F(CoreAudioUtilWinTest, GetDevicePeriod) {
278 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
280 EDataFlow data[] = {eRender, eCapture};
282 // Verify that the device periods are valid for the default render and
283 // capture devices.
284 for (int i = 0; i < arraysize(data); ++i) {
285 ScopedComPtr<IAudioClient> client;
286 REFERENCE_TIME shared_time_period = 0;
287 REFERENCE_TIME exclusive_time_period = 0;
288 client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
289 EXPECT_TRUE(client.get());
290 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDevicePeriod(
291 client.get(), AUDCLNT_SHAREMODE_SHARED, &shared_time_period)));
292 EXPECT_GT(shared_time_period, 0);
293 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDevicePeriod(
294 client.get(), AUDCLNT_SHAREMODE_EXCLUSIVE, &exclusive_time_period)));
295 EXPECT_GT(exclusive_time_period, 0);
296 EXPECT_LE(exclusive_time_period, shared_time_period);
300 TEST_F(CoreAudioUtilWinTest, GetPreferredAudioParameters) {
301 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
303 EDataFlow data[] = {eRender, eCapture};
305 // Verify that the preferred audio parameters are OK for the default render
306 // and capture devices.
307 for (int i = 0; i < arraysize(data); ++i) {
308 ScopedComPtr<IAudioClient> client;
309 AudioParameters params;
310 client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
311 EXPECT_TRUE(client.get());
312 EXPECT_TRUE(SUCCEEDED(
313 CoreAudioUtil::GetPreferredAudioParameters(client.get(), &params)));
314 EXPECT_TRUE(params.IsValid());
318 TEST_F(CoreAudioUtilWinTest, SharedModeInitialize) {
319 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
321 ScopedComPtr<IAudioClient> client;
322 client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
323 EXPECT_TRUE(client.get());
325 WAVEFORMATPCMEX format;
326 EXPECT_TRUE(
327 SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client.get(), &format)));
329 // Perform a shared-mode initialization without event-driven buffer handling.
330 uint32 endpoint_buffer_size = 0;
331 HRESULT hr = CoreAudioUtil::SharedModeInitialize(client.get(), &format, NULL,
332 &endpoint_buffer_size, NULL);
333 EXPECT_TRUE(SUCCEEDED(hr));
334 EXPECT_GT(endpoint_buffer_size, 0u);
336 // It is only possible to create a client once.
337 hr = CoreAudioUtil::SharedModeInitialize(client.get(), &format, NULL,
338 &endpoint_buffer_size, NULL);
339 EXPECT_FALSE(SUCCEEDED(hr));
340 EXPECT_EQ(hr, AUDCLNT_E_ALREADY_INITIALIZED);
342 // Verify that it is possible to reinitialize the client after releasing it.
343 client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
344 EXPECT_TRUE(client.get());
345 hr = CoreAudioUtil::SharedModeInitialize(client.get(), &format, NULL,
346 &endpoint_buffer_size, NULL);
347 EXPECT_TRUE(SUCCEEDED(hr));
348 EXPECT_GT(endpoint_buffer_size, 0u);
350 // Use a non-supported format and verify that initialization fails.
351 // A simple way to emulate an invalid format is to use the shared-mode
352 // mixing format and modify the preferred sample.
353 client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
354 EXPECT_TRUE(client.get());
355 format.Format.nSamplesPerSec = format.Format.nSamplesPerSec + 1;
356 EXPECT_FALSE(CoreAudioUtil::IsFormatSupported(
357 client.get(), AUDCLNT_SHAREMODE_SHARED, &format));
358 hr = CoreAudioUtil::SharedModeInitialize(client.get(), &format, NULL,
359 &endpoint_buffer_size, NULL);
360 EXPECT_TRUE(FAILED(hr));
361 EXPECT_EQ(hr, E_INVALIDARG);
363 // Finally, perform a shared-mode initialization using event-driven buffer
364 // handling. The event handle will be signaled when an audio buffer is ready
365 // to be processed by the client (not verified here).
366 // The event handle should be in the nonsignaled state.
367 base::win::ScopedHandle event_handle(::CreateEvent(NULL, TRUE, FALSE, NULL));
368 client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
369 EXPECT_TRUE(client.get());
370 EXPECT_TRUE(
371 SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client.get(), &format)));
372 EXPECT_TRUE(CoreAudioUtil::IsFormatSupported(
373 client.get(), AUDCLNT_SHAREMODE_SHARED, &format));
374 hr = CoreAudioUtil::SharedModeInitialize(
375 client.get(), &format, event_handle.Get(), &endpoint_buffer_size, NULL);
376 EXPECT_TRUE(SUCCEEDED(hr));
377 EXPECT_GT(endpoint_buffer_size, 0u);
380 TEST_F(CoreAudioUtilWinTest, CreateRenderAndCaptureClients) {
381 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
383 EDataFlow data[] = {eRender, eCapture};
385 WAVEFORMATPCMEX format;
386 uint32 endpoint_buffer_size = 0;
388 for (int i = 0; i < arraysize(data); ++i) {
389 ScopedComPtr<IAudioClient> client;
390 ScopedComPtr<IAudioRenderClient> render_client;
391 ScopedComPtr<IAudioCaptureClient> capture_client;
393 client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
394 EXPECT_TRUE(client.get());
395 EXPECT_TRUE(SUCCEEDED(
396 CoreAudioUtil::GetSharedModeMixFormat(client.get(), &format)));
397 if (data[i] == eRender) {
398 // It is not possible to create a render client using an unitialized
399 // client interface.
400 render_client = CoreAudioUtil::CreateRenderClient(client.get());
401 EXPECT_FALSE(render_client.get());
403 // Do a proper initialization and verify that it works this time.
404 CoreAudioUtil::SharedModeInitialize(client.get(), &format, NULL,
405 &endpoint_buffer_size, NULL);
406 render_client = CoreAudioUtil::CreateRenderClient(client.get());
407 EXPECT_TRUE(render_client.get());
408 EXPECT_GT(endpoint_buffer_size, 0u);
409 } else if (data[i] == eCapture) {
410 // It is not possible to create a capture client using an unitialized
411 // client interface.
412 capture_client = CoreAudioUtil::CreateCaptureClient(client.get());
413 EXPECT_FALSE(capture_client.get());
415 // Do a proper initialization and verify that it works this time.
416 CoreAudioUtil::SharedModeInitialize(client.get(), &format, NULL,
417 &endpoint_buffer_size, NULL);
418 capture_client = CoreAudioUtil::CreateCaptureClient(client.get());
419 EXPECT_TRUE(capture_client.get());
420 EXPECT_GT(endpoint_buffer_size, 0u);
425 TEST_F(CoreAudioUtilWinTest, FillRenderEndpointBufferWithSilence) {
426 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
428 // Create default clients using the default mixing format for shared mode.
429 ScopedComPtr<IAudioClient> client(
430 CoreAudioUtil::CreateDefaultClient(eRender, eConsole));
431 EXPECT_TRUE(client.get());
433 WAVEFORMATPCMEX format;
434 uint32 endpoint_buffer_size = 0;
435 EXPECT_TRUE(
436 SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client.get(), &format)));
437 CoreAudioUtil::SharedModeInitialize(client.get(), &format, NULL,
438 &endpoint_buffer_size, NULL);
439 EXPECT_GT(endpoint_buffer_size, 0u);
441 ScopedComPtr<IAudioRenderClient> render_client(
442 CoreAudioUtil::CreateRenderClient(client.get()));
443 EXPECT_TRUE(render_client.get());
445 // The endpoint audio buffer should not be filled up by default after being
446 // created.
447 UINT32 num_queued_frames = 0;
448 client->GetCurrentPadding(&num_queued_frames);
449 EXPECT_EQ(num_queued_frames, 0u);
451 // Fill it up with zeros and verify that the buffer is full.
452 // It is not possible to verify that the actual data consists of zeros
453 // since we can't access data that has already been sent to the endpoint
454 // buffer.
455 EXPECT_TRUE(CoreAudioUtil::FillRenderEndpointBufferWithSilence(
456 client.get(), render_client.get()));
457 client->GetCurrentPadding(&num_queued_frames);
458 EXPECT_EQ(num_queued_frames, endpoint_buffer_size);
461 // This test can only run on a machine that has audio hardware
462 // that has both input and output devices.
463 TEST_F(CoreAudioUtilWinTest, GetMatchingOutputDeviceID) {
464 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
466 bool found_a_pair = false;
468 ScopedComPtr<IMMDeviceEnumerator> enumerator(
469 CoreAudioUtil::CreateDeviceEnumerator());
470 ASSERT_TRUE(enumerator.get());
472 // Enumerate all active input and output devices and fetch the ID of
473 // the associated device.
474 ScopedComPtr<IMMDeviceCollection> collection;
475 ASSERT_TRUE(SUCCEEDED(enumerator->EnumAudioEndpoints(eCapture,
476 DEVICE_STATE_ACTIVE, collection.Receive())));
477 UINT count = 0;
478 collection->GetCount(&count);
479 for (UINT i = 0; i < count && !found_a_pair; ++i) {
480 ScopedComPtr<IMMDevice> device;
481 collection->Item(i, device.Receive());
482 base::win::ScopedCoMem<WCHAR> wide_id;
483 device->GetId(&wide_id);
484 std::string id;
485 base::WideToUTF8(wide_id, wcslen(wide_id), &id);
486 found_a_pair = !CoreAudioUtil::GetMatchingOutputDeviceID(id).empty();
489 EXPECT_TRUE(found_a_pair);
492 TEST_F(CoreAudioUtilWinTest, GetDefaultOutputDeviceID) {
493 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
495 std::string default_device_id(CoreAudioUtil::GetDefaultOutputDeviceID());
496 EXPECT_FALSE(default_device_id.empty());
499 } // namespace media