cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / media / audio / win / core_audio_util_win_unittest.cc
blob140e6496a186a00456f8a2715bee0e123484bdf2
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/win/core_audio_util_win.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
15 using base::win::ScopedCOMInitializer;
17 namespace media {
19 class CoreAudioUtilWinTest : public ::testing::Test {
20 protected:
21 // The test runs on a COM thread in the multithreaded apartment (MTA).
22 // If we don't initialize the COM library on a thread before using COM,
23 // all function calls will return CO_E_NOTINITIALIZED.
24 CoreAudioUtilWinTest()
25 : com_init_(ScopedCOMInitializer::kMTA) {
26 DCHECK(com_init_.succeeded());
28 virtual ~CoreAudioUtilWinTest() {}
30 bool CanRunAudioTest() {
31 bool core_audio = CoreAudioUtil::IsSupported();
32 if (!core_audio)
33 return false;
34 int capture_devices = CoreAudioUtil::NumberOfActiveDevices(eCapture);
35 int render_devices = CoreAudioUtil::NumberOfActiveDevices(eRender);
36 return ((capture_devices > 0) && (render_devices > 0));
39 ScopedCOMInitializer com_init_;
42 TEST_F(CoreAudioUtilWinTest, NumberOfActiveDevices) {
43 if (!CanRunAudioTest())
44 return;
46 int render_devices = CoreAudioUtil::NumberOfActiveDevices(eRender);
47 EXPECT_GT(render_devices, 0);
48 int capture_devices = CoreAudioUtil::NumberOfActiveDevices(eCapture);
49 EXPECT_GT(capture_devices, 0);
50 int total_devices = CoreAudioUtil::NumberOfActiveDevices(eAll);
51 EXPECT_EQ(total_devices, render_devices + capture_devices);
54 TEST_F(CoreAudioUtilWinTest, CreateDeviceEnumerator) {
55 if (!CanRunAudioTest())
56 return;
58 ScopedComPtr<IMMDeviceEnumerator> enumerator =
59 CoreAudioUtil::CreateDeviceEnumerator();
60 EXPECT_TRUE(enumerator);
63 TEST_F(CoreAudioUtilWinTest, CreateDefaultDevice) {
64 if (!CanRunAudioTest())
65 return;
67 struct {
68 EDataFlow flow;
69 ERole role;
70 } data[] = {
71 {eRender, eConsole},
72 {eRender, eCommunications},
73 {eRender, eMultimedia},
74 {eCapture, eConsole},
75 {eCapture, eCommunications},
76 {eCapture, eMultimedia}
79 // Create default devices for all flow/role combinations above.
80 ScopedComPtr<IMMDevice> audio_device;
81 for (int i = 0; i < arraysize(data); ++i) {
82 audio_device =
83 CoreAudioUtil::CreateDefaultDevice(data[i].flow, data[i].role);
84 EXPECT_TRUE(audio_device);
85 EXPECT_EQ(data[i].flow, CoreAudioUtil::GetDataFlow(audio_device));
88 // Only eRender and eCapture are allowed as flow parameter.
89 audio_device = CoreAudioUtil::CreateDefaultDevice(eAll, eConsole);
90 EXPECT_FALSE(audio_device);
93 TEST_F(CoreAudioUtilWinTest, CreateDevice) {
94 if (!CanRunAudioTest())
95 return;
97 // Get name and ID of default device used for playback.
98 ScopedComPtr<IMMDevice> default_render_device =
99 CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
100 AudioDeviceName default_render_name;
101 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(default_render_device,
102 &default_render_name)));
104 // Use the uniqe ID as input to CreateDevice() and create a corresponding
105 // IMMDevice.
106 ScopedComPtr<IMMDevice> audio_device =
107 CoreAudioUtil::CreateDevice(default_render_name.unique_id);
108 EXPECT_TRUE(audio_device);
110 // Verify that the two IMMDevice interfaces represents the same endpoint
111 // by comparing their unique IDs.
112 AudioDeviceName device_name;
113 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(audio_device,
114 &device_name)));
115 EXPECT_EQ(default_render_name.unique_id, device_name.unique_id);
118 TEST_F(CoreAudioUtilWinTest, GetDefaultDeviceName) {
119 if (!CanRunAudioTest())
120 return;
122 struct {
123 EDataFlow flow;
124 ERole role;
125 } data[] = {
126 {eRender, eConsole},
127 {eRender, eCommunications},
128 {eCapture, eConsole},
129 {eCapture, eCommunications}
132 // Get name and ID of default devices for all flow/role combinations above.
133 ScopedComPtr<IMMDevice> audio_device;
134 AudioDeviceName device_name;
135 for (int i = 0; i < arraysize(data); ++i) {
136 audio_device =
137 CoreAudioUtil::CreateDefaultDevice(data[i].flow, data[i].role);
138 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(audio_device,
139 &device_name)));
140 EXPECT_FALSE(device_name.device_name.empty());
141 EXPECT_FALSE(device_name.unique_id.empty());
145 TEST_F(CoreAudioUtilWinTest, GetAudioControllerID) {
146 if (!CanRunAudioTest())
147 return;
149 ScopedComPtr<IMMDeviceEnumerator> enumerator(
150 CoreAudioUtil::CreateDeviceEnumerator());
151 ASSERT_TRUE(enumerator);
153 // Enumerate all active input and output devices and fetch the ID of
154 // the associated device.
155 EDataFlow flows[] = { eRender , eCapture };
156 for (int i = 0; i < arraysize(flows); ++i) {
157 ScopedComPtr<IMMDeviceCollection> collection;
158 ASSERT_TRUE(SUCCEEDED(enumerator->EnumAudioEndpoints(flows[i],
159 DEVICE_STATE_ACTIVE, collection.Receive())));
160 UINT count = 0;
161 collection->GetCount(&count);
162 for (UINT j = 0; j < count; ++j) {
163 ScopedComPtr<IMMDevice> device;
164 collection->Item(j, device.Receive());
165 std::string controller_id(CoreAudioUtil::GetAudioControllerID(
166 device, enumerator));
167 EXPECT_FALSE(controller_id.empty());
172 TEST_F(CoreAudioUtilWinTest, GetFriendlyName) {
173 if (!CanRunAudioTest())
174 return;
176 // Get name and ID of default device used for recording.
177 ScopedComPtr<IMMDevice> audio_device =
178 CoreAudioUtil::CreateDefaultDevice(eCapture, eConsole);
179 AudioDeviceName device_name;
180 HRESULT hr = CoreAudioUtil::GetDeviceName(audio_device, &device_name);
181 EXPECT_TRUE(SUCCEEDED(hr));
183 // Use unique ID as input to GetFriendlyName() and compare the result
184 // with the already obtained friendly name for the default capture device.
185 std::string friendly_name = CoreAudioUtil::GetFriendlyName(
186 device_name.unique_id);
187 EXPECT_EQ(friendly_name, device_name.device_name);
189 // Same test as above but for playback.
190 audio_device = CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
191 hr = CoreAudioUtil::GetDeviceName(audio_device, &device_name);
192 EXPECT_TRUE(SUCCEEDED(hr));
193 friendly_name = CoreAudioUtil::GetFriendlyName(device_name.unique_id);
194 EXPECT_EQ(friendly_name, device_name.device_name);
197 TEST_F(CoreAudioUtilWinTest, DeviceIsDefault) {
198 if (!CanRunAudioTest())
199 return;
201 // Verify that the default render device is correctly identified as a
202 // default device.
203 ScopedComPtr<IMMDevice> audio_device =
204 CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
205 AudioDeviceName name;
206 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(audio_device, &name)));
207 const std::string id = name.unique_id;
208 EXPECT_TRUE(CoreAudioUtil::DeviceIsDefault(eRender, eConsole, id));
209 EXPECT_FALSE(CoreAudioUtil::DeviceIsDefault(eCapture, eConsole, id));
212 TEST_F(CoreAudioUtilWinTest, CreateDefaultClient) {
213 if (!CanRunAudioTest())
214 return;
216 EDataFlow data[] = {eRender, eCapture};
218 for (int i = 0; i < arraysize(data); ++i) {
219 ScopedComPtr<IAudioClient> client;
220 client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
221 EXPECT_TRUE(client);
225 TEST_F(CoreAudioUtilWinTest, CreateClient) {
226 if (!CanRunAudioTest())
227 return;
229 EDataFlow data[] = {eRender, eCapture};
231 for (int i = 0; i < arraysize(data); ++i) {
232 ScopedComPtr<IMMDevice> device;
233 ScopedComPtr<IAudioClient> client;
234 device = CoreAudioUtil::CreateDefaultDevice(data[i], eConsole);
235 EXPECT_TRUE(device);
236 EXPECT_EQ(data[i], CoreAudioUtil::GetDataFlow(device));
237 client = CoreAudioUtil::CreateClient(device);
238 EXPECT_TRUE(client);
242 TEST_F(CoreAudioUtilWinTest, GetSharedModeMixFormat) {
243 if (!CanRunAudioTest())
244 return;
246 ScopedComPtr<IMMDevice> device;
247 ScopedComPtr<IAudioClient> client;
248 device = CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
249 EXPECT_TRUE(device);
250 client = CoreAudioUtil::CreateClient(device);
251 EXPECT_TRUE(client);
253 // Perform a simple sanity test of the aquired format structure.
254 WAVEFORMATPCMEX format;
255 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client,
256 &format)));
257 EXPECT_GE(format.Format.nChannels, 1);
258 EXPECT_GE(format.Format.nSamplesPerSec, 8000u);
259 EXPECT_GE(format.Format.wBitsPerSample, 16);
260 EXPECT_GE(format.Samples.wValidBitsPerSample, 16);
261 EXPECT_EQ(format.Format.wFormatTag, WAVE_FORMAT_EXTENSIBLE);
264 TEST_F(CoreAudioUtilWinTest, IsChannelLayoutSupported) {
265 if (!CanRunAudioTest())
266 return;
268 // The preferred channel layout should always be supported. Being supported
269 // means that it is possible to initialize a shared mode stream with the
270 // particular channel layout.
271 AudioParameters mix_params;
272 HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(eRender, eConsole,
273 &mix_params);
274 EXPECT_TRUE(SUCCEEDED(hr));
275 EXPECT_TRUE(mix_params.IsValid());
276 EXPECT_TRUE(CoreAudioUtil::IsChannelLayoutSupported(
277 eRender, eConsole, mix_params.channel_layout()));
279 // Check if it is possible to modify the channel layout to stereo for a
280 // device which reports that it prefers to be openen up in an other
281 // channel configuration.
282 if (mix_params.channel_layout() != CHANNEL_LAYOUT_STEREO) {
283 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
284 // TODO(henrika): it might be too pessimistic to assume false as return
285 // value here.
286 EXPECT_FALSE(CoreAudioUtil::IsChannelLayoutSupported(
287 eRender, eConsole, channel_layout));
291 TEST_F(CoreAudioUtilWinTest, GetDevicePeriod) {
292 if (!CanRunAudioTest())
293 return;
295 EDataFlow data[] = {eRender, eCapture};
297 // Verify that the device periods are valid for the default render and
298 // capture devices.
299 for (int i = 0; i < arraysize(data); ++i) {
300 ScopedComPtr<IAudioClient> client;
301 REFERENCE_TIME shared_time_period = 0;
302 REFERENCE_TIME exclusive_time_period = 0;
303 client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
304 EXPECT_TRUE(client);
305 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDevicePeriod(
306 client, AUDCLNT_SHAREMODE_SHARED, &shared_time_period)));
307 EXPECT_GT(shared_time_period, 0);
308 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDevicePeriod(
309 client, AUDCLNT_SHAREMODE_EXCLUSIVE, &exclusive_time_period)));
310 EXPECT_GT(exclusive_time_period, 0);
311 EXPECT_LE(exclusive_time_period, shared_time_period);
315 TEST_F(CoreAudioUtilWinTest, GetPreferredAudioParameters) {
316 if (!CanRunAudioTest())
317 return;
319 EDataFlow data[] = {eRender, eCapture};
321 // Verify that the preferred audio parameters are OK for the default render
322 // and capture devices.
323 for (int i = 0; i < arraysize(data); ++i) {
324 ScopedComPtr<IAudioClient> client;
325 AudioParameters params;
326 client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
327 EXPECT_TRUE(client);
328 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters(client,
329 &params)));
330 EXPECT_TRUE(params.IsValid());
334 TEST_F(CoreAudioUtilWinTest, SharedModeInitialize) {
335 if (!CanRunAudioTest())
336 return;
338 ScopedComPtr<IAudioClient> client;
339 client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
340 EXPECT_TRUE(client);
342 WAVEFORMATPCMEX format;
343 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client,
344 &format)));
346 // Perform a shared-mode initialization without event-driven buffer handling.
347 uint32 endpoint_buffer_size = 0;
348 HRESULT hr = CoreAudioUtil::SharedModeInitialize(client, &format, NULL,
349 &endpoint_buffer_size);
350 EXPECT_TRUE(SUCCEEDED(hr));
351 EXPECT_GT(endpoint_buffer_size, 0u);
353 // It is only possible to create a client once.
354 hr = CoreAudioUtil::SharedModeInitialize(client, &format, NULL,
355 &endpoint_buffer_size);
356 EXPECT_FALSE(SUCCEEDED(hr));
357 EXPECT_EQ(hr, AUDCLNT_E_ALREADY_INITIALIZED);
359 // Verify that it is possible to reinitialize the client after releasing it.
360 client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
361 EXPECT_TRUE(client);
362 hr = CoreAudioUtil::SharedModeInitialize(client, &format, NULL,
363 &endpoint_buffer_size);
364 EXPECT_TRUE(SUCCEEDED(hr));
365 EXPECT_GT(endpoint_buffer_size, 0u);
367 // Use a non-supported format and verify that initialization fails.
368 // A simple way to emulate an invalid format is to use the shared-mode
369 // mixing format and modify the preferred sample.
370 client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
371 EXPECT_TRUE(client);
372 format.Format.nSamplesPerSec = format.Format.nSamplesPerSec + 1;
373 EXPECT_FALSE(CoreAudioUtil::IsFormatSupported(
374 client, AUDCLNT_SHAREMODE_SHARED, &format));
375 hr = CoreAudioUtil::SharedModeInitialize(client, &format, NULL,
376 &endpoint_buffer_size);
377 EXPECT_TRUE(FAILED(hr));
378 EXPECT_EQ(hr, E_INVALIDARG);
380 // Finally, perform a shared-mode initialization using event-driven buffer
381 // handling. The event handle will be signaled when an audio buffer is ready
382 // to be processed by the client (not verified here).
383 // The event handle should be in the nonsignaled state.
384 base::win::ScopedHandle event_handle(::CreateEvent(NULL, TRUE, FALSE, NULL));
385 client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
386 EXPECT_TRUE(client);
387 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client,
388 &format)));
389 EXPECT_TRUE(CoreAudioUtil::IsFormatSupported(
390 client, AUDCLNT_SHAREMODE_SHARED, &format));
391 hr = CoreAudioUtil::SharedModeInitialize(client, &format, event_handle.Get(),
392 &endpoint_buffer_size);
393 EXPECT_TRUE(SUCCEEDED(hr));
394 EXPECT_GT(endpoint_buffer_size, 0u);
397 TEST_F(CoreAudioUtilWinTest, CreateRenderAndCaptureClients) {
398 if (!CanRunAudioTest())
399 return;
401 EDataFlow data[] = {eRender, eCapture};
403 WAVEFORMATPCMEX format;
404 uint32 endpoint_buffer_size = 0;
406 for (int i = 0; i < arraysize(data); ++i) {
407 ScopedComPtr<IAudioClient> client;
408 ScopedComPtr<IAudioRenderClient> render_client;
409 ScopedComPtr<IAudioCaptureClient> capture_client;
411 client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
412 EXPECT_TRUE(client);
413 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client,
414 &format)));
415 if (data[i] == eRender) {
416 // It is not possible to create a render client using an unitialized
417 // client interface.
418 render_client = CoreAudioUtil::CreateRenderClient(client);
419 EXPECT_FALSE(render_client);
421 // Do a proper initialization and verify that it works this time.
422 CoreAudioUtil::SharedModeInitialize(client, &format, NULL,
423 &endpoint_buffer_size);
424 render_client = CoreAudioUtil::CreateRenderClient(client);
425 EXPECT_TRUE(render_client);
426 EXPECT_GT(endpoint_buffer_size, 0u);
427 } else if (data[i] == eCapture) {
428 // It is not possible to create a capture client using an unitialized
429 // client interface.
430 capture_client = CoreAudioUtil::CreateCaptureClient(client);
431 EXPECT_FALSE(capture_client);
433 // Do a proper initialization and verify that it works this time.
434 CoreAudioUtil::SharedModeInitialize(client, &format, NULL,
435 &endpoint_buffer_size);
436 capture_client = CoreAudioUtil::CreateCaptureClient(client);
437 EXPECT_TRUE(capture_client);
438 EXPECT_GT(endpoint_buffer_size, 0u);
443 TEST_F(CoreAudioUtilWinTest, FillRenderEndpointBufferWithSilence) {
444 if (!CanRunAudioTest())
445 return;
447 // Create default clients using the default mixing format for shared mode.
448 ScopedComPtr<IAudioClient> client(
449 CoreAudioUtil::CreateDefaultClient(eRender, eConsole));
450 EXPECT_TRUE(client);
452 WAVEFORMATPCMEX format;
453 uint32 endpoint_buffer_size = 0;
454 EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client,
455 &format)));
456 CoreAudioUtil::SharedModeInitialize(client, &format, NULL,
457 &endpoint_buffer_size);
458 EXPECT_GT(endpoint_buffer_size, 0u);
460 ScopedComPtr<IAudioRenderClient> render_client(
461 CoreAudioUtil::CreateRenderClient(client));
462 EXPECT_TRUE(render_client);
464 // The endpoint audio buffer should not be filled up by default after being
465 // created.
466 UINT32 num_queued_frames = 0;
467 client->GetCurrentPadding(&num_queued_frames);
468 EXPECT_EQ(num_queued_frames, 0u);
470 // Fill it up with zeros and verify that the buffer is full.
471 // It is not possible to verify that the actual data consists of zeros
472 // since we can't access data that has already been sent to the endpoint
473 // buffer.
474 EXPECT_TRUE(CoreAudioUtil::FillRenderEndpointBufferWithSilence(
475 client, render_client));
476 client->GetCurrentPadding(&num_queued_frames);
477 EXPECT_EQ(num_queued_frames, endpoint_buffer_size);
480 // This test can only succeed on a machine that has audio hardware
481 // that has both input and output devices. Currently this is the case
482 // with our test bots and the CanRunAudioTest() method should make sure
483 // that the test won't run in unsupported environments, but be warned.
484 TEST_F(CoreAudioUtilWinTest, GetMatchingOutputDeviceID) {
485 if (!CanRunAudioTest())
486 return;
488 bool found_a_pair = false;
490 ScopedComPtr<IMMDeviceEnumerator> enumerator(
491 CoreAudioUtil::CreateDeviceEnumerator());
492 ASSERT_TRUE(enumerator);
494 // Enumerate all active input and output devices and fetch the ID of
495 // the associated device.
496 ScopedComPtr<IMMDeviceCollection> collection;
497 ASSERT_TRUE(SUCCEEDED(enumerator->EnumAudioEndpoints(eCapture,
498 DEVICE_STATE_ACTIVE, collection.Receive())));
499 UINT count = 0;
500 collection->GetCount(&count);
501 for (UINT i = 0; i < count && !found_a_pair; ++i) {
502 ScopedComPtr<IMMDevice> device;
503 collection->Item(i, device.Receive());
504 base::win::ScopedCoMem<WCHAR> wide_id;
505 device->GetId(&wide_id);
506 std::string id;
507 WideToUTF8(wide_id, wcslen(wide_id), &id);
508 found_a_pair = !CoreAudioUtil::GetMatchingOutputDeviceID(id).empty();
511 EXPECT_TRUE(found_a_pair);
514 } // namespace media