Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / media / audio / win / core_audio_util_win_unittest.cc
blobd3dc85e32e2135d86863cd1b003842c703f473e2
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 test runs on a COM thread in the multithreaded apartment (MTA).
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 : com_init_(ScopedCOMInitializer::kMTA) {
27 DCHECK(com_init_.succeeded());
29 ~CoreAudioUtilWinTest() override {}
31 bool DevicesAvailable() {
32 if (!CoreAudioUtil::IsSupported())
33 return false;
34 return CoreAudioUtil::NumberOfActiveDevices(eCapture) > 0 &&
35 CoreAudioUtil::NumberOfActiveDevices(eRender) > 0;
38 ScopedCOMInitializer com_init_;
41 TEST_F(CoreAudioUtilWinTest, NumberOfActiveDevices) {
42 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
44 int render_devices = CoreAudioUtil::NumberOfActiveDevices(eRender);
45 EXPECT_GT(render_devices, 0);
46 int capture_devices = CoreAudioUtil::NumberOfActiveDevices(eCapture);
47 EXPECT_GT(capture_devices, 0);
48 int total_devices = CoreAudioUtil::NumberOfActiveDevices(eAll);
49 EXPECT_EQ(total_devices, render_devices + capture_devices);
52 TEST_F(CoreAudioUtilWinTest, CreateDeviceEnumerator) {
53 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
55 ScopedComPtr<IMMDeviceEnumerator> enumerator =
56 CoreAudioUtil::CreateDeviceEnumerator();
57 EXPECT_TRUE(enumerator.get());
60 TEST_F(CoreAudioUtilWinTest, CreateDefaultDevice) {
61 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
63 struct {
64 EDataFlow flow;
65 ERole role;
66 } data[] = {
67 {eRender, eConsole},
68 {eRender, eCommunications},
69 {eRender, eMultimedia},
70 {eCapture, eConsole},
71 {eCapture, eCommunications},
72 {eCapture, eMultimedia}
75 // Create default devices for all flow/role combinations above.
76 ScopedComPtr<IMMDevice> audio_device;
77 for (int i = 0; i < arraysize(data); ++i) {
78 audio_device =
79 CoreAudioUtil::CreateDefaultDevice(data[i].flow, data[i].role);
80 EXPECT_TRUE(audio_device.get());
81 EXPECT_EQ(data[i].flow, CoreAudioUtil::GetDataFlow(audio_device.get()));
84 // Only eRender and eCapture are allowed as flow parameter.
85 audio_device = CoreAudioUtil::CreateDefaultDevice(eAll, eConsole);
86 EXPECT_FALSE(audio_device.get());
89 TEST_F(CoreAudioUtilWinTest, CreateDevice) {
90 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
92 // Get name and ID of default device used for playback.
93 ScopedComPtr<IMMDevice> default_render_device =
94 CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
95 AudioDeviceName default_render_name;
96 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(
97 default_render_device.get(), &default_render_name)));
99 // Use the uniqe ID as input to CreateDevice() and create a corresponding
100 // IMMDevice.
101 ScopedComPtr<IMMDevice> audio_device =
102 CoreAudioUtil::CreateDevice(default_render_name.unique_id);
103 EXPECT_TRUE(audio_device.get());
105 // Verify that the two IMMDevice interfaces represents the same endpoint
106 // by comparing their unique IDs.
107 AudioDeviceName device_name;
108 EXPECT_TRUE(SUCCEEDED(
109 CoreAudioUtil::GetDeviceName(audio_device.get(), &device_name)));
110 EXPECT_EQ(default_render_name.unique_id, device_name.unique_id);
113 TEST_F(CoreAudioUtilWinTest, GetDefaultDeviceName) {
114 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
116 struct {
117 EDataFlow flow;
118 ERole role;
119 } data[] = {
120 {eRender, eConsole},
121 {eRender, eCommunications},
122 {eCapture, eConsole},
123 {eCapture, eCommunications}
126 // Get name and ID of default devices for all flow/role combinations above.
127 ScopedComPtr<IMMDevice> audio_device;
128 AudioDeviceName device_name;
129 for (int i = 0; i < arraysize(data); ++i) {
130 audio_device =
131 CoreAudioUtil::CreateDefaultDevice(data[i].flow, data[i].role);
132 EXPECT_TRUE(SUCCEEDED(
133 CoreAudioUtil::GetDeviceName(audio_device.get(), &device_name)));
134 EXPECT_FALSE(device_name.device_name.empty());
135 EXPECT_FALSE(device_name.unique_id.empty());
139 TEST_F(CoreAudioUtilWinTest, GetAudioControllerID) {
140 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
142 ScopedComPtr<IMMDeviceEnumerator> enumerator(
143 CoreAudioUtil::CreateDeviceEnumerator());
144 ASSERT_TRUE(enumerator.get());
146 // Enumerate all active input and output devices and fetch the ID of
147 // the associated device.
148 EDataFlow flows[] = { eRender , eCapture };
149 for (int i = 0; i < arraysize(flows); ++i) {
150 ScopedComPtr<IMMDeviceCollection> collection;
151 ASSERT_TRUE(SUCCEEDED(enumerator->EnumAudioEndpoints(flows[i],
152 DEVICE_STATE_ACTIVE, collection.Receive())));
153 UINT count = 0;
154 collection->GetCount(&count);
155 for (UINT j = 0; j < count; ++j) {
156 ScopedComPtr<IMMDevice> device;
157 collection->Item(j, device.Receive());
158 std::string controller_id(
159 CoreAudioUtil::GetAudioControllerID(device.get(), enumerator.get()));
160 EXPECT_FALSE(controller_id.empty());
165 TEST_F(CoreAudioUtilWinTest, GetFriendlyName) {
166 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
168 // Get name and ID of default device used for recording.
169 ScopedComPtr<IMMDevice> audio_device =
170 CoreAudioUtil::CreateDefaultDevice(eCapture, eConsole);
171 AudioDeviceName device_name;
172 HRESULT hr = CoreAudioUtil::GetDeviceName(audio_device.get(), &device_name);
173 EXPECT_TRUE(SUCCEEDED(hr));
175 // Use unique ID as input to GetFriendlyName() and compare the result
176 // with the already obtained friendly name for the default capture device.
177 std::string friendly_name = CoreAudioUtil::GetFriendlyName(
178 device_name.unique_id);
179 EXPECT_EQ(friendly_name, device_name.device_name);
181 // Same test as above but for playback.
182 audio_device = CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
183 hr = CoreAudioUtil::GetDeviceName(audio_device.get(), &device_name);
184 EXPECT_TRUE(SUCCEEDED(hr));
185 friendly_name = CoreAudioUtil::GetFriendlyName(device_name.unique_id);
186 EXPECT_EQ(friendly_name, device_name.device_name);
189 TEST_F(CoreAudioUtilWinTest, DeviceIsDefault) {
190 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
192 // Verify that the default render device is correctly identified as a
193 // default device.
194 ScopedComPtr<IMMDevice> audio_device =
195 CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
196 AudioDeviceName name;
197 EXPECT_TRUE(
198 SUCCEEDED(CoreAudioUtil::GetDeviceName(audio_device.get(), &name)));
199 const std::string id = name.unique_id;
200 EXPECT_TRUE(CoreAudioUtil::DeviceIsDefault(eRender, eConsole, id));
201 EXPECT_FALSE(CoreAudioUtil::DeviceIsDefault(eCapture, eConsole, id));
204 TEST_F(CoreAudioUtilWinTest, CreateDefaultClient) {
205 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
207 EDataFlow data[] = {eRender, eCapture};
209 for (int i = 0; i < arraysize(data); ++i) {
210 ScopedComPtr<IAudioClient> client;
211 client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
212 EXPECT_TRUE(client.get());
216 TEST_F(CoreAudioUtilWinTest, CreateClient) {
217 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
219 EDataFlow data[] = {eRender, eCapture};
221 for (int i = 0; i < arraysize(data); ++i) {
222 ScopedComPtr<IMMDevice> device;
223 ScopedComPtr<IAudioClient> client;
224 device = CoreAudioUtil::CreateDefaultDevice(data[i], eConsole);
225 EXPECT_TRUE(device.get());
226 EXPECT_EQ(data[i], CoreAudioUtil::GetDataFlow(device.get()));
227 client = CoreAudioUtil::CreateClient(device.get());
228 EXPECT_TRUE(client.get());
232 TEST_F(CoreAudioUtilWinTest, GetSharedModeMixFormat) {
233 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
235 ScopedComPtr<IMMDevice> device;
236 ScopedComPtr<IAudioClient> client;
237 device = CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
238 EXPECT_TRUE(device.get());
239 client = CoreAudioUtil::CreateClient(device.get());
240 EXPECT_TRUE(client.get());
242 // Perform a simple sanity test of the aquired format structure.
243 WAVEFORMATPCMEX format;
244 EXPECT_TRUE(
245 SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client.get(), &format)));
246 EXPECT_GE(format.Format.nChannels, 1);
247 EXPECT_GE(format.Format.nSamplesPerSec, 8000u);
248 EXPECT_GE(format.Format.wBitsPerSample, 16);
249 EXPECT_GE(format.Samples.wValidBitsPerSample, 16);
250 EXPECT_EQ(format.Format.wFormatTag, WAVE_FORMAT_EXTENSIBLE);
253 TEST_F(CoreAudioUtilWinTest, IsChannelLayoutSupported) {
254 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
256 // The preferred channel layout should always be supported. Being supported
257 // means that it is possible to initialize a shared mode stream with the
258 // particular channel layout.
259 AudioParameters mix_params;
260 HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(eRender, eConsole,
261 &mix_params);
262 EXPECT_TRUE(SUCCEEDED(hr));
263 EXPECT_TRUE(mix_params.IsValid());
264 EXPECT_TRUE(CoreAudioUtil::IsChannelLayoutSupported(
265 std::string(), eRender, eConsole, mix_params.channel_layout()));
267 // Check if it is possible to modify the channel layout to stereo for a
268 // device which reports that it prefers to be openen up in an other
269 // channel configuration.
270 if (mix_params.channel_layout() != CHANNEL_LAYOUT_STEREO) {
271 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
272 // TODO(henrika): it might be too pessimistic to assume false as return
273 // value here.
274 EXPECT_FALSE(CoreAudioUtil::IsChannelLayoutSupported(
275 std::string(), eRender, eConsole, channel_layout));
279 TEST_F(CoreAudioUtilWinTest, GetDevicePeriod) {
280 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
282 EDataFlow data[] = {eRender, eCapture};
284 // Verify that the device periods are valid for the default render and
285 // capture devices.
286 for (int i = 0; i < arraysize(data); ++i) {
287 ScopedComPtr<IAudioClient> client;
288 REFERENCE_TIME shared_time_period = 0;
289 REFERENCE_TIME exclusive_time_period = 0;
290 client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
291 EXPECT_TRUE(client.get());
292 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDevicePeriod(
293 client.get(), AUDCLNT_SHAREMODE_SHARED, &shared_time_period)));
294 EXPECT_GT(shared_time_period, 0);
295 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDevicePeriod(
296 client.get(), AUDCLNT_SHAREMODE_EXCLUSIVE, &exclusive_time_period)));
297 EXPECT_GT(exclusive_time_period, 0);
298 EXPECT_LE(exclusive_time_period, shared_time_period);
302 TEST_F(CoreAudioUtilWinTest, GetPreferredAudioParameters) {
303 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
305 EDataFlow data[] = {eRender, eCapture};
307 // Verify that the preferred audio parameters are OK for the default render
308 // and capture devices.
309 for (int i = 0; i < arraysize(data); ++i) {
310 ScopedComPtr<IAudioClient> client;
311 AudioParameters params;
312 client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
313 EXPECT_TRUE(client.get());
314 EXPECT_TRUE(SUCCEEDED(
315 CoreAudioUtil::GetPreferredAudioParameters(client.get(), &params)));
316 EXPECT_TRUE(params.IsValid());
320 TEST_F(CoreAudioUtilWinTest, SharedModeInitialize) {
321 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
323 ScopedComPtr<IAudioClient> client;
324 client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
325 EXPECT_TRUE(client.get());
327 WAVEFORMATPCMEX format;
328 EXPECT_TRUE(
329 SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client.get(), &format)));
331 // Perform a shared-mode initialization without event-driven buffer handling.
332 uint32 endpoint_buffer_size = 0;
333 HRESULT hr = CoreAudioUtil::SharedModeInitialize(client.get(), &format, NULL,
334 &endpoint_buffer_size, NULL);
335 EXPECT_TRUE(SUCCEEDED(hr));
336 EXPECT_GT(endpoint_buffer_size, 0u);
338 // It is only possible to create a client once.
339 hr = CoreAudioUtil::SharedModeInitialize(client.get(), &format, NULL,
340 &endpoint_buffer_size, NULL);
341 EXPECT_FALSE(SUCCEEDED(hr));
342 EXPECT_EQ(hr, AUDCLNT_E_ALREADY_INITIALIZED);
344 // Verify that it is possible to reinitialize the client after releasing it.
345 client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
346 EXPECT_TRUE(client.get());
347 hr = CoreAudioUtil::SharedModeInitialize(client.get(), &format, NULL,
348 &endpoint_buffer_size, NULL);
349 EXPECT_TRUE(SUCCEEDED(hr));
350 EXPECT_GT(endpoint_buffer_size, 0u);
352 // Use a non-supported format and verify that initialization fails.
353 // A simple way to emulate an invalid format is to use the shared-mode
354 // mixing format and modify the preferred sample.
355 client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
356 EXPECT_TRUE(client.get());
357 format.Format.nSamplesPerSec = format.Format.nSamplesPerSec + 1;
358 EXPECT_FALSE(CoreAudioUtil::IsFormatSupported(
359 client.get(), AUDCLNT_SHAREMODE_SHARED, &format));
360 hr = CoreAudioUtil::SharedModeInitialize(client.get(), &format, NULL,
361 &endpoint_buffer_size, NULL);
362 EXPECT_TRUE(FAILED(hr));
363 EXPECT_EQ(hr, E_INVALIDARG);
365 // Finally, perform a shared-mode initialization using event-driven buffer
366 // handling. The event handle will be signaled when an audio buffer is ready
367 // to be processed by the client (not verified here).
368 // The event handle should be in the nonsignaled state.
369 base::win::ScopedHandle event_handle(::CreateEvent(NULL, TRUE, FALSE, NULL));
370 client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
371 EXPECT_TRUE(client.get());
372 EXPECT_TRUE(
373 SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client.get(), &format)));
374 EXPECT_TRUE(CoreAudioUtil::IsFormatSupported(
375 client.get(), AUDCLNT_SHAREMODE_SHARED, &format));
376 hr = CoreAudioUtil::SharedModeInitialize(
377 client.get(), &format, event_handle.Get(), &endpoint_buffer_size, NULL);
378 EXPECT_TRUE(SUCCEEDED(hr));
379 EXPECT_GT(endpoint_buffer_size, 0u);
382 TEST_F(CoreAudioUtilWinTest, CreateRenderAndCaptureClients) {
383 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
385 EDataFlow data[] = {eRender, eCapture};
387 WAVEFORMATPCMEX format;
388 uint32 endpoint_buffer_size = 0;
390 for (int i = 0; i < arraysize(data); ++i) {
391 ScopedComPtr<IAudioClient> client;
392 ScopedComPtr<IAudioRenderClient> render_client;
393 ScopedComPtr<IAudioCaptureClient> capture_client;
395 client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
396 EXPECT_TRUE(client.get());
397 EXPECT_TRUE(SUCCEEDED(
398 CoreAudioUtil::GetSharedModeMixFormat(client.get(), &format)));
399 if (data[i] == eRender) {
400 // It is not possible to create a render client using an unitialized
401 // client interface.
402 render_client = CoreAudioUtil::CreateRenderClient(client.get());
403 EXPECT_FALSE(render_client.get());
405 // Do a proper initialization and verify that it works this time.
406 CoreAudioUtil::SharedModeInitialize(client.get(), &format, NULL,
407 &endpoint_buffer_size, NULL);
408 render_client = CoreAudioUtil::CreateRenderClient(client.get());
409 EXPECT_TRUE(render_client.get());
410 EXPECT_GT(endpoint_buffer_size, 0u);
411 } else if (data[i] == eCapture) {
412 // It is not possible to create a capture client using an unitialized
413 // client interface.
414 capture_client = CoreAudioUtil::CreateCaptureClient(client.get());
415 EXPECT_FALSE(capture_client.get());
417 // Do a proper initialization and verify that it works this time.
418 CoreAudioUtil::SharedModeInitialize(client.get(), &format, NULL,
419 &endpoint_buffer_size, NULL);
420 capture_client = CoreAudioUtil::CreateCaptureClient(client.get());
421 EXPECT_TRUE(capture_client.get());
422 EXPECT_GT(endpoint_buffer_size, 0u);
427 TEST_F(CoreAudioUtilWinTest, FillRenderEndpointBufferWithSilence) {
428 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
430 // Create default clients using the default mixing format for shared mode.
431 ScopedComPtr<IAudioClient> client(
432 CoreAudioUtil::CreateDefaultClient(eRender, eConsole));
433 EXPECT_TRUE(client.get());
435 WAVEFORMATPCMEX format;
436 uint32 endpoint_buffer_size = 0;
437 EXPECT_TRUE(
438 SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client.get(), &format)));
439 CoreAudioUtil::SharedModeInitialize(client.get(), &format, NULL,
440 &endpoint_buffer_size, NULL);
441 EXPECT_GT(endpoint_buffer_size, 0u);
443 ScopedComPtr<IAudioRenderClient> render_client(
444 CoreAudioUtil::CreateRenderClient(client.get()));
445 EXPECT_TRUE(render_client.get());
447 // The endpoint audio buffer should not be filled up by default after being
448 // created.
449 UINT32 num_queued_frames = 0;
450 client->GetCurrentPadding(&num_queued_frames);
451 EXPECT_EQ(num_queued_frames, 0u);
453 // Fill it up with zeros and verify that the buffer is full.
454 // It is not possible to verify that the actual data consists of zeros
455 // since we can't access data that has already been sent to the endpoint
456 // buffer.
457 EXPECT_TRUE(CoreAudioUtil::FillRenderEndpointBufferWithSilence(
458 client.get(), render_client.get()));
459 client->GetCurrentPadding(&num_queued_frames);
460 EXPECT_EQ(num_queued_frames, endpoint_buffer_size);
463 // This test can only run on a machine that has audio hardware
464 // that has both input and output devices.
465 TEST_F(CoreAudioUtilWinTest, GetMatchingOutputDeviceID) {
466 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
468 bool found_a_pair = false;
470 ScopedComPtr<IMMDeviceEnumerator> enumerator(
471 CoreAudioUtil::CreateDeviceEnumerator());
472 ASSERT_TRUE(enumerator.get());
474 // Enumerate all active input and output devices and fetch the ID of
475 // the associated device.
476 ScopedComPtr<IMMDeviceCollection> collection;
477 ASSERT_TRUE(SUCCEEDED(enumerator->EnumAudioEndpoints(eCapture,
478 DEVICE_STATE_ACTIVE, collection.Receive())));
479 UINT count = 0;
480 collection->GetCount(&count);
481 for (UINT i = 0; i < count && !found_a_pair; ++i) {
482 ScopedComPtr<IMMDevice> device;
483 collection->Item(i, device.Receive());
484 base::win::ScopedCoMem<WCHAR> wide_id;
485 device->GetId(&wide_id);
486 std::string id;
487 base::WideToUTF8(wide_id, wcslen(wide_id), &id);
488 found_a_pair = !CoreAudioUtil::GetMatchingOutputDeviceID(id).empty();
491 EXPECT_TRUE(found_a_pair);
494 TEST_F(CoreAudioUtilWinTest, GetDefaultOutputDeviceID) {
495 ABORT_AUDIO_TEST_IF_NOT(DevicesAvailable());
497 std::string default_device_id(CoreAudioUtil::GetDefaultOutputDeviceID());
498 EXPECT_FALSE(default_device_id.empty());
501 } // namespace media