- add sources.
[platform/framework/web/crosswalk.git] / src / media / audio / win / core_audio_util_win_unittest.cc
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.
4
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"
14
15 using base::win::ScopedCOMInitializer;
16
17 namespace media {
18
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());
27   }
28   virtual ~CoreAudioUtilWinTest() {}
29
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));
37   }
38
39   ScopedCOMInitializer com_init_;
40 };
41
42 TEST_F(CoreAudioUtilWinTest, NumberOfActiveDevices) {
43   if (!CanRunAudioTest())
44     return;
45
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);
52 }
53
54 TEST_F(CoreAudioUtilWinTest, CreateDeviceEnumerator) {
55   if (!CanRunAudioTest())
56     return;
57
58   ScopedComPtr<IMMDeviceEnumerator> enumerator =
59       CoreAudioUtil::CreateDeviceEnumerator();
60   EXPECT_TRUE(enumerator);
61 }
62
63 TEST_F(CoreAudioUtilWinTest, CreateDefaultDevice) {
64   if (!CanRunAudioTest())
65     return;
66
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}
77   };
78
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));
86   }
87
88   // Only eRender and eCapture are allowed as flow parameter.
89   audio_device = CoreAudioUtil::CreateDefaultDevice(eAll, eConsole);
90   EXPECT_FALSE(audio_device);
91 }
92
93 TEST_F(CoreAudioUtilWinTest, CreateDevice) {
94   if (!CanRunAudioTest())
95     return;
96
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)));
103
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);
109
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);
116 }
117
118 TEST_F(CoreAudioUtilWinTest, GetDefaultDeviceName) {
119   if (!CanRunAudioTest())
120     return;
121
122   struct {
123     EDataFlow flow;
124     ERole role;
125   } data[] = {
126     {eRender, eConsole},
127     {eRender, eCommunications},
128     {eCapture, eConsole},
129     {eCapture, eCommunications}
130   };
131
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());
142   }
143 }
144
145 TEST_F(CoreAudioUtilWinTest, GetAudioControllerID) {
146   if (!CanRunAudioTest())
147     return;
148
149   ScopedComPtr<IMMDeviceEnumerator> enumerator(
150       CoreAudioUtil::CreateDeviceEnumerator());
151   ASSERT_TRUE(enumerator);
152
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());
168     }
169   }
170 }
171
172 TEST_F(CoreAudioUtilWinTest, GetFriendlyName) {
173   if (!CanRunAudioTest())
174     return;
175
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));
182
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);
188
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);
195 }
196
197 TEST_F(CoreAudioUtilWinTest, DeviceIsDefault) {
198   if (!CanRunAudioTest())
199     return;
200
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));
210 }
211
212 TEST_F(CoreAudioUtilWinTest, CreateDefaultClient) {
213   if (!CanRunAudioTest())
214     return;
215
216   EDataFlow data[] = {eRender, eCapture};
217
218   for (int i = 0; i < arraysize(data); ++i) {
219     ScopedComPtr<IAudioClient> client;
220     client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
221     EXPECT_TRUE(client);
222   }
223 }
224
225 TEST_F(CoreAudioUtilWinTest, CreateClient) {
226   if (!CanRunAudioTest())
227     return;
228
229   EDataFlow data[] = {eRender, eCapture};
230
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);
239   }
240 }
241
242 TEST_F(CoreAudioUtilWinTest, GetSharedModeMixFormat) {
243   if (!CanRunAudioTest())
244     return;
245
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);
252
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);
262 }
263
264 TEST_F(CoreAudioUtilWinTest, IsChannelLayoutSupported) {
265   if (!CanRunAudioTest())
266     return;
267
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       std::string(), eRender, eConsole, mix_params.channel_layout()));
278
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         std::string(), eRender, eConsole, channel_layout));
288   }
289 }
290
291 TEST_F(CoreAudioUtilWinTest, GetDevicePeriod) {
292   if (!CanRunAudioTest())
293     return;
294
295   EDataFlow data[] = {eRender, eCapture};
296
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);
312   }
313 }
314
315 TEST_F(CoreAudioUtilWinTest, GetPreferredAudioParameters) {
316   if (!CanRunAudioTest())
317     return;
318
319   EDataFlow data[] = {eRender, eCapture};
320
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());
331   }
332 }
333
334 TEST_F(CoreAudioUtilWinTest, SharedModeInitialize) {
335   if (!CanRunAudioTest())
336     return;
337
338   ScopedComPtr<IAudioClient> client;
339   client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
340   EXPECT_TRUE(client);
341
342   WAVEFORMATPCMEX format;
343   EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client,
344                                                               &format)));
345
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);
352
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);
358
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);
366
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);
379
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);
395 }
396
397 TEST_F(CoreAudioUtilWinTest, CreateRenderAndCaptureClients) {
398   if (!CanRunAudioTest())
399     return;
400
401   EDataFlow data[] = {eRender, eCapture};
402
403   WAVEFORMATPCMEX format;
404   uint32 endpoint_buffer_size = 0;
405
406   for (int i = 0; i < arraysize(data); ++i) {
407     ScopedComPtr<IAudioClient> client;
408     ScopedComPtr<IAudioRenderClient> render_client;
409     ScopedComPtr<IAudioCaptureClient> capture_client;
410
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);
420
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);
432
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);
439     }
440   }
441 }
442
443 TEST_F(CoreAudioUtilWinTest, FillRenderEndpointBufferWithSilence) {
444   if (!CanRunAudioTest())
445     return;
446
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);
451
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);
459
460   ScopedComPtr<IAudioRenderClient> render_client(
461       CoreAudioUtil::CreateRenderClient(client));
462   EXPECT_TRUE(render_client);
463
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);
469
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);
478 }
479
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;
487
488   bool found_a_pair = false;
489
490   ScopedComPtr<IMMDeviceEnumerator> enumerator(
491       CoreAudioUtil::CreateDeviceEnumerator());
492   ASSERT_TRUE(enumerator);
493
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();
509   }
510
511   EXPECT_TRUE(found_a_pair);
512 }
513
514 TEST_F(CoreAudioUtilWinTest, GetDefaultOutputDeviceID) {
515   if (!CanRunAudioTest())
516     return;
517
518   std::string default_device_id(CoreAudioUtil::GetDefaultOutputDeviceID());
519   EXPECT_FALSE(default_device_id.empty());
520 }
521
522 }  // namespace media