xref: /aosp_15_r20/external/webrtc/modules/audio_device/win/core_audio_utility_win_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/audio_device/win/core_audio_utility_win.h"
12 #include "rtc_base/arraysize.h"
13 #include "rtc_base/logging.h"
14 #include "rtc_base/win/scoped_com_initializer.h"
15 #include "rtc_base/win/windows_version.h"
16 #include "test/gtest.h"
17 
18 using Microsoft::WRL::ComPtr;
19 using webrtc::AudioDeviceName;
20 
21 namespace webrtc {
22 namespace webrtc_win {
23 namespace {
24 
25 #define ABORT_TEST_IF_NOT(requirements_satisfied)                        \
26   do {                                                                   \
27     bool fail = false;                                                   \
28     if (ShouldAbortTest(requirements_satisfied, #requirements_satisfied, \
29                         &fail)) {                                        \
30       if (fail)                                                          \
31         FAIL();                                                          \
32       else                                                               \
33         return;                                                          \
34     }                                                                    \
35   } while (false)
36 
ShouldAbortTest(bool requirements_satisfied,const char * requirements_expression,bool * should_fail)37 bool ShouldAbortTest(bool requirements_satisfied,
38                      const char* requirements_expression,
39                      bool* should_fail) {
40   if (!requirements_satisfied) {
41     RTC_LOG(LS_ERROR) << "Requirement(s) not satisfied ("
42                       << requirements_expression << ")";
43     // TODO(henrika): improve hard-coded condition to determine if test should
44     // fail or be ignored. Could use e.g. a command-line argument here to
45     // determine if the test should fail or not.
46     *should_fail = false;
47     return true;
48   }
49   *should_fail = false;
50   return false;
51 }
52 
53 }  // namespace
54 
55 // CoreAudioUtilityWinTest test fixture.
56 class CoreAudioUtilityWinTest : public ::testing::Test {
57  protected:
CoreAudioUtilityWinTest()58   CoreAudioUtilityWinTest() : com_init_(ScopedCOMInitializer::kMTA) {
59     // We must initialize the COM library on a thread before we calling any of
60     // the library functions. All COM functions will return CO_E_NOTINITIALIZED
61     // otherwise.
62     EXPECT_TRUE(com_init_.Succeeded());
63 
64     // Configure logging.
65     rtc::LogMessage::LogToDebug(rtc::LS_INFO);
66     rtc::LogMessage::LogTimestamps();
67     rtc::LogMessage::LogThreads();
68   }
69 
~CoreAudioUtilityWinTest()70   virtual ~CoreAudioUtilityWinTest() {}
71 
DevicesAvailable()72   bool DevicesAvailable() {
73     return core_audio_utility::IsSupported() &&
74            core_audio_utility::NumberOfActiveDevices(eCapture) > 0 &&
75            core_audio_utility::NumberOfActiveDevices(eRender) > 0;
76   }
77 
78  private:
79   ScopedCOMInitializer com_init_;
80 };
81 
TEST_F(CoreAudioUtilityWinTest,WaveFormatWrapper)82 TEST_F(CoreAudioUtilityWinTest, WaveFormatWrapper) {
83   // Use default constructor for WAVEFORMATEX and verify its size.
84   WAVEFORMATEX format = {};
85   core_audio_utility::WaveFormatWrapper wave_format(&format);
86   EXPECT_FALSE(wave_format.IsExtensible());
87   EXPECT_EQ(wave_format.size(), sizeof(WAVEFORMATEX));
88   EXPECT_EQ(wave_format->cbSize, 0);
89 
90   // Ensure that the stand-alone WAVEFORMATEX structure has a valid format tag
91   // and that all accessors work.
92   format.wFormatTag = WAVE_FORMAT_PCM;
93   EXPECT_FALSE(wave_format.IsExtensible());
94   EXPECT_EQ(wave_format.size(), sizeof(WAVEFORMATEX));
95   EXPECT_EQ(wave_format.get()->wFormatTag, WAVE_FORMAT_PCM);
96   EXPECT_EQ(wave_format->wFormatTag, WAVE_FORMAT_PCM);
97 
98   // Next, ensure that the size is valid. Stand-alone is not extended.
99   EXPECT_EQ(wave_format.size(), sizeof(WAVEFORMATEX));
100 
101   // Verify format types for the stand-alone version.
102   EXPECT_TRUE(wave_format.IsPcm());
103   EXPECT_FALSE(wave_format.IsFloat());
104   format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
105   EXPECT_TRUE(wave_format.IsFloat());
106 }
107 
TEST_F(CoreAudioUtilityWinTest,WaveFormatWrapperExtended)108 TEST_F(CoreAudioUtilityWinTest, WaveFormatWrapperExtended) {
109   // Use default constructor for WAVEFORMATEXTENSIBLE and verify that it
110   // results in same size as for WAVEFORMATEX even if the size of `format_ex`
111   // equals the size of WAVEFORMATEXTENSIBLE.
112   WAVEFORMATEXTENSIBLE format_ex = {};
113   core_audio_utility::WaveFormatWrapper wave_format_ex(&format_ex);
114   EXPECT_FALSE(wave_format_ex.IsExtensible());
115   EXPECT_EQ(wave_format_ex.size(), sizeof(WAVEFORMATEX));
116   EXPECT_EQ(wave_format_ex->cbSize, 0);
117 
118   // Ensure that the extended structure has a valid format tag and that all
119   // accessors work.
120   format_ex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
121   EXPECT_FALSE(wave_format_ex.IsExtensible());
122   EXPECT_EQ(wave_format_ex.size(), sizeof(WAVEFORMATEX));
123   EXPECT_EQ(wave_format_ex->wFormatTag, WAVE_FORMAT_EXTENSIBLE);
124   EXPECT_EQ(wave_format_ex.get()->wFormatTag, WAVE_FORMAT_EXTENSIBLE);
125 
126   // Next, ensure that the size is valid (sum of stand-alone and extended).
127   // Now the structure qualifies as extended.
128   format_ex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
129   EXPECT_TRUE(wave_format_ex.IsExtensible());
130   EXPECT_EQ(wave_format_ex.size(), sizeof(WAVEFORMATEXTENSIBLE));
131   EXPECT_TRUE(wave_format_ex.GetExtensible());
132   EXPECT_EQ(wave_format_ex.GetExtensible()->Format.wFormatTag,
133             WAVE_FORMAT_EXTENSIBLE);
134 
135   // Verify format types for the extended version.
136   EXPECT_FALSE(wave_format_ex.IsPcm());
137   format_ex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
138   EXPECT_TRUE(wave_format_ex.IsPcm());
139   EXPECT_FALSE(wave_format_ex.IsFloat());
140   format_ex.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
141   EXPECT_TRUE(wave_format_ex.IsFloat());
142 }
143 
TEST_F(CoreAudioUtilityWinTest,NumberOfActiveDevices)144 TEST_F(CoreAudioUtilityWinTest, NumberOfActiveDevices) {
145   ABORT_TEST_IF_NOT(DevicesAvailable());
146   int render_devices = core_audio_utility::NumberOfActiveDevices(eRender);
147   EXPECT_GT(render_devices, 0);
148   int capture_devices = core_audio_utility::NumberOfActiveDevices(eCapture);
149   EXPECT_GT(capture_devices, 0);
150   int total_devices = core_audio_utility::NumberOfActiveDevices(eAll);
151   EXPECT_EQ(total_devices, render_devices + capture_devices);
152 }
153 
TEST_F(CoreAudioUtilityWinTest,GetAudioClientVersion)154 TEST_F(CoreAudioUtilityWinTest, GetAudioClientVersion) {
155   uint32_t client_version = core_audio_utility::GetAudioClientVersion();
156   EXPECT_GE(client_version, 1u);
157   EXPECT_LE(client_version, 3u);
158 }
159 
TEST_F(CoreAudioUtilityWinTest,CreateDeviceEnumerator)160 TEST_F(CoreAudioUtilityWinTest, CreateDeviceEnumerator) {
161   ABORT_TEST_IF_NOT(DevicesAvailable());
162   ComPtr<IMMDeviceEnumerator> enumerator =
163       core_audio_utility::CreateDeviceEnumerator();
164   EXPECT_TRUE(enumerator.Get());
165 }
166 
TEST_F(CoreAudioUtilityWinTest,GetDefaultInputDeviceID)167 TEST_F(CoreAudioUtilityWinTest, GetDefaultInputDeviceID) {
168   ABORT_TEST_IF_NOT(DevicesAvailable());
169   std::string default_device_id = core_audio_utility::GetDefaultInputDeviceID();
170   EXPECT_FALSE(default_device_id.empty());
171 }
172 
TEST_F(CoreAudioUtilityWinTest,GetDefaultOutputDeviceID)173 TEST_F(CoreAudioUtilityWinTest, GetDefaultOutputDeviceID) {
174   ABORT_TEST_IF_NOT(DevicesAvailable());
175   std::string default_device_id =
176       core_audio_utility::GetDefaultOutputDeviceID();
177   EXPECT_FALSE(default_device_id.empty());
178 }
179 
TEST_F(CoreAudioUtilityWinTest,GetCommunicationsInputDeviceID)180 TEST_F(CoreAudioUtilityWinTest, GetCommunicationsInputDeviceID) {
181   ABORT_TEST_IF_NOT(DevicesAvailable());
182   std::string default_device_id =
183       core_audio_utility::GetCommunicationsInputDeviceID();
184   EXPECT_FALSE(default_device_id.empty());
185 }
186 
TEST_F(CoreAudioUtilityWinTest,GetCommunicationsOutputDeviceID)187 TEST_F(CoreAudioUtilityWinTest, GetCommunicationsOutputDeviceID) {
188   ABORT_TEST_IF_NOT(DevicesAvailable());
189   std::string default_device_id =
190       core_audio_utility::GetCommunicationsOutputDeviceID();
191   EXPECT_FALSE(default_device_id.empty());
192 }
193 
TEST_F(CoreAudioUtilityWinTest,CreateDefaultDevice)194 TEST_F(CoreAudioUtilityWinTest, CreateDefaultDevice) {
195   ABORT_TEST_IF_NOT(DevicesAvailable());
196 
197   struct {
198     EDataFlow flow;
199     ERole role;
200   } data[] = {{eRender, eConsole},         {eRender, eCommunications},
201               {eRender, eMultimedia},      {eCapture, eConsole},
202               {eCapture, eCommunications}, {eCapture, eMultimedia}};
203 
204   // Create default devices for all flow/role combinations above.
205   ComPtr<IMMDevice> audio_device;
206   for (size_t i = 0; i < arraysize(data); ++i) {
207     audio_device = core_audio_utility::CreateDevice(
208         AudioDeviceName::kDefaultDeviceId, data[i].flow, data[i].role);
209     EXPECT_TRUE(audio_device.Get());
210     EXPECT_EQ(data[i].flow,
211               core_audio_utility::GetDataFlow(audio_device.Get()));
212   }
213 
214   // Only eRender and eCapture are allowed as flow parameter.
215   audio_device = core_audio_utility::CreateDevice(
216       AudioDeviceName::kDefaultDeviceId, eAll, eConsole);
217   EXPECT_FALSE(audio_device.Get());
218 }
219 
TEST_F(CoreAudioUtilityWinTest,CreateDevice)220 TEST_F(CoreAudioUtilityWinTest, CreateDevice) {
221   ABORT_TEST_IF_NOT(DevicesAvailable());
222 
223   // Get name and ID of default device used for playback.
224   ComPtr<IMMDevice> default_render_device = core_audio_utility::CreateDevice(
225       AudioDeviceName::kDefaultDeviceId, eRender, eConsole);
226   AudioDeviceName default_render_name =
227       core_audio_utility::GetDeviceName(default_render_device.Get());
228   EXPECT_TRUE(default_render_name.IsValid());
229 
230   // Use the unique ID as input to CreateDevice() and create a corresponding
231   // IMMDevice. The data-flow direction and role parameters are ignored for
232   // this scenario.
233   ComPtr<IMMDevice> audio_device = core_audio_utility::CreateDevice(
234       default_render_name.unique_id, EDataFlow(), ERole());
235   EXPECT_TRUE(audio_device.Get());
236 
237   // Verify that the two IMMDevice interfaces represents the same endpoint
238   // by comparing their unique IDs.
239   AudioDeviceName device_name =
240       core_audio_utility::GetDeviceName(audio_device.Get());
241   EXPECT_EQ(default_render_name.unique_id, device_name.unique_id);
242 }
243 
TEST_F(CoreAudioUtilityWinTest,GetDefaultDeviceName)244 TEST_F(CoreAudioUtilityWinTest, GetDefaultDeviceName) {
245   ABORT_TEST_IF_NOT(DevicesAvailable());
246 
247   struct {
248     EDataFlow flow;
249     ERole role;
250   } data[] = {{eRender, eConsole},
251               {eRender, eCommunications},
252               {eCapture, eConsole},
253               {eCapture, eCommunications}};
254 
255   // Get name and ID of default devices for all flow/role combinations above.
256   ComPtr<IMMDevice> audio_device;
257   AudioDeviceName device_name;
258   for (size_t i = 0; i < arraysize(data); ++i) {
259     audio_device = core_audio_utility::CreateDevice(
260         AudioDeviceName::kDefaultDeviceId, data[i].flow, data[i].role);
261     device_name = core_audio_utility::GetDeviceName(audio_device.Get());
262     EXPECT_TRUE(device_name.IsValid());
263   }
264 }
265 
TEST_F(CoreAudioUtilityWinTest,GetFriendlyName)266 TEST_F(CoreAudioUtilityWinTest, GetFriendlyName) {
267   ABORT_TEST_IF_NOT(DevicesAvailable());
268 
269   // Get name and ID of default device used for recording.
270   ComPtr<IMMDevice> audio_device = core_audio_utility::CreateDevice(
271       AudioDeviceName::kDefaultDeviceId, eCapture, eConsole);
272   AudioDeviceName device_name =
273       core_audio_utility::GetDeviceName(audio_device.Get());
274   EXPECT_TRUE(device_name.IsValid());
275 
276   // Use unique ID as input to GetFriendlyName() and compare the result
277   // with the already obtained friendly name for the default capture device.
278   std::string friendly_name = core_audio_utility::GetFriendlyName(
279       device_name.unique_id, eCapture, eConsole);
280   EXPECT_EQ(friendly_name, device_name.device_name);
281 
282   // Same test as above but for playback.
283   audio_device = core_audio_utility::CreateDevice(
284       AudioDeviceName::kDefaultDeviceId, eRender, eConsole);
285   device_name = core_audio_utility::GetDeviceName(audio_device.Get());
286   friendly_name = core_audio_utility::GetFriendlyName(device_name.unique_id,
287                                                       eRender, eConsole);
288   EXPECT_EQ(friendly_name, device_name.device_name);
289 }
290 
TEST_F(CoreAudioUtilityWinTest,GetInputDeviceNames)291 TEST_F(CoreAudioUtilityWinTest, GetInputDeviceNames) {
292   ABORT_TEST_IF_NOT(DevicesAvailable());
293 
294   webrtc::AudioDeviceNames device_names;
295   EXPECT_TRUE(core_audio_utility::GetInputDeviceNames(&device_names));
296   // Number of elements in the list should be two more than the number of
297   // active devices since we always add default and default communication
298   // devices on index 0 and 1.
299   EXPECT_EQ(static_cast<int>(device_names.size()),
300             2 + core_audio_utility::NumberOfActiveDevices(eCapture));
301 }
302 
TEST_F(CoreAudioUtilityWinTest,GetOutputDeviceNames)303 TEST_F(CoreAudioUtilityWinTest, GetOutputDeviceNames) {
304   ABORT_TEST_IF_NOT(DevicesAvailable());
305 
306   webrtc::AudioDeviceNames device_names;
307   EXPECT_TRUE(core_audio_utility::GetOutputDeviceNames(&device_names));
308   // Number of elements in the list should be two more than the number of
309   // active devices since we always add default and default communication
310   // devices on index 0 and 1.
311   EXPECT_EQ(static_cast<int>(device_names.size()),
312             2 + core_audio_utility::NumberOfActiveDevices(eRender));
313 }
314 
TEST_F(CoreAudioUtilityWinTest,CreateSessionManager2)315 TEST_F(CoreAudioUtilityWinTest, CreateSessionManager2) {
316   ABORT_TEST_IF_NOT(DevicesAvailable() &&
317                     rtc::rtc_win::GetVersion() >= rtc::rtc_win::VERSION_WIN7);
318 
319   EDataFlow data_flow[] = {eRender, eCapture};
320 
321   // Obtain reference to an IAudioSessionManager2 interface for a default audio
322   // endpoint device specified by two different data flows and the `eConsole`
323   // role.
324   for (size_t i = 0; i < arraysize(data_flow); ++i) {
325     ComPtr<IMMDevice> device(core_audio_utility::CreateDevice(
326         AudioDeviceName::kDefaultDeviceId, data_flow[i], eConsole));
327     EXPECT_TRUE(device.Get());
328     ComPtr<IAudioSessionManager2> session_manager =
329         core_audio_utility::CreateSessionManager2(device.Get());
330     EXPECT_TRUE(session_manager.Get());
331   }
332 }
333 
TEST_F(CoreAudioUtilityWinTest,CreateSessionEnumerator)334 TEST_F(CoreAudioUtilityWinTest, CreateSessionEnumerator) {
335   ABORT_TEST_IF_NOT(DevicesAvailable() &&
336                     rtc::rtc_win::GetVersion() >= rtc::rtc_win::VERSION_WIN7);
337 
338   EDataFlow data_flow[] = {eRender, eCapture};
339 
340   // Obtain reference to an IAudioSessionEnumerator interface for a default
341   // audio endpoint device specified by two different data flows and the
342   // `eConsole` role.
343   for (size_t i = 0; i < arraysize(data_flow); ++i) {
344     ComPtr<IMMDevice> device(core_audio_utility::CreateDevice(
345         AudioDeviceName::kDefaultDeviceId, data_flow[i], eConsole));
346     EXPECT_TRUE(device.Get());
347     ComPtr<IAudioSessionEnumerator> session_enumerator =
348         core_audio_utility::CreateSessionEnumerator(device.Get());
349     EXPECT_TRUE(session_enumerator.Get());
350 
351     // Perform a sanity test of the interface by asking for the total number
352     // of audio sessions that are open on the audio device. Note that, we do
353     // not check if the session is active or not.
354     int session_count = 0;
355     EXPECT_TRUE(SUCCEEDED(session_enumerator->GetCount(&session_count)));
356     EXPECT_GE(session_count, 0);
357   }
358 }
359 
TEST_F(CoreAudioUtilityWinTest,NumberOfActiveSessions)360 TEST_F(CoreAudioUtilityWinTest, NumberOfActiveSessions) {
361   ABORT_TEST_IF_NOT(DevicesAvailable() &&
362                     rtc::rtc_win::GetVersion() >= rtc::rtc_win::VERSION_WIN7);
363 
364   EDataFlow data_flow[] = {eRender, eCapture};
365 
366   // Count number of active audio session for a default audio endpoint device
367   // specified by two different data flows and the `eConsole` role.
368   // Ensure that the number of active audio sessions is less than or equal to
369   // the total number of audio sessions on that same device.
370   for (size_t i = 0; i < arraysize(data_flow); ++i) {
371     // Create an audio endpoint device.
372     ComPtr<IMMDevice> device(core_audio_utility::CreateDevice(
373         AudioDeviceName::kDefaultDeviceId, data_flow[i], eConsole));
374     EXPECT_TRUE(device.Get());
375 
376     // Ask for total number of audio sessions on the created device.
377     ComPtr<IAudioSessionEnumerator> session_enumerator =
378         core_audio_utility::CreateSessionEnumerator(device.Get());
379     EXPECT_TRUE(session_enumerator.Get());
380     int total_session_count = 0;
381     EXPECT_TRUE(SUCCEEDED(session_enumerator->GetCount(&total_session_count)));
382     EXPECT_GE(total_session_count, 0);
383 
384     // Use NumberOfActiveSessions and get number of active audio sessions.
385     int active_session_count =
386         core_audio_utility::NumberOfActiveSessions(device.Get());
387     EXPECT_LE(active_session_count, total_session_count);
388   }
389 }
390 
TEST_F(CoreAudioUtilityWinTest,CreateClient)391 TEST_F(CoreAudioUtilityWinTest, CreateClient) {
392   ABORT_TEST_IF_NOT(DevicesAvailable());
393 
394   EDataFlow data_flow[] = {eRender, eCapture};
395 
396   // Obtain reference to an IAudioClient interface for a default audio endpoint
397   // device specified by two different data flows and the `eConsole` role.
398   for (size_t i = 0; i < arraysize(data_flow); ++i) {
399     ComPtr<IAudioClient> client = core_audio_utility::CreateClient(
400         AudioDeviceName::kDefaultDeviceId, data_flow[i], eConsole);
401     EXPECT_TRUE(client.Get());
402   }
403 }
404 
TEST_F(CoreAudioUtilityWinTest,CreateClient2)405 TEST_F(CoreAudioUtilityWinTest, CreateClient2) {
406   ABORT_TEST_IF_NOT(DevicesAvailable() &&
407                     core_audio_utility::GetAudioClientVersion() >= 2);
408 
409   EDataFlow data_flow[] = {eRender, eCapture};
410 
411   // Obtain reference to an IAudioClient2 interface for a default audio endpoint
412   // device specified by two different data flows and the `eConsole` role.
413   for (size_t i = 0; i < arraysize(data_flow); ++i) {
414     ComPtr<IAudioClient2> client2 = core_audio_utility::CreateClient2(
415         AudioDeviceName::kDefaultDeviceId, data_flow[i], eConsole);
416     EXPECT_TRUE(client2.Get());
417   }
418 }
419 
TEST_F(CoreAudioUtilityWinTest,CreateClient3)420 TEST_F(CoreAudioUtilityWinTest, CreateClient3) {
421   ABORT_TEST_IF_NOT(DevicesAvailable() &&
422                     core_audio_utility::GetAudioClientVersion() >= 3);
423 
424   EDataFlow data_flow[] = {eRender, eCapture};
425 
426   // Obtain reference to an IAudioClient3 interface for a default audio endpoint
427   // device specified by two different data flows and the `eConsole` role.
428   for (size_t i = 0; i < arraysize(data_flow); ++i) {
429     ComPtr<IAudioClient3> client3 = core_audio_utility::CreateClient3(
430         AudioDeviceName::kDefaultDeviceId, data_flow[i], eConsole);
431     EXPECT_TRUE(client3.Get());
432   }
433 }
434 
TEST_F(CoreAudioUtilityWinTest,SetClientProperties)435 TEST_F(CoreAudioUtilityWinTest, SetClientProperties) {
436   ABORT_TEST_IF_NOT(DevicesAvailable() &&
437                     core_audio_utility::GetAudioClientVersion() >= 2);
438 
439   ComPtr<IAudioClient2> client2 = core_audio_utility::CreateClient2(
440       AudioDeviceName::kDefaultDeviceId, eRender, eConsole);
441   EXPECT_TRUE(client2.Get());
442   EXPECT_TRUE(
443       SUCCEEDED(core_audio_utility::SetClientProperties(client2.Get())));
444 
445   ComPtr<IAudioClient3> client3 = core_audio_utility::CreateClient3(
446       AudioDeviceName::kDefaultDeviceId, eRender, eConsole);
447   EXPECT_TRUE(client3.Get());
448   EXPECT_TRUE(
449       SUCCEEDED(core_audio_utility::SetClientProperties(client3.Get())));
450 }
451 
TEST_F(CoreAudioUtilityWinTest,GetSharedModeEnginePeriod)452 TEST_F(CoreAudioUtilityWinTest, GetSharedModeEnginePeriod) {
453   ABORT_TEST_IF_NOT(DevicesAvailable() &&
454                     core_audio_utility::GetAudioClientVersion() >= 3);
455 
456   ComPtr<IAudioClient3> client3 = core_audio_utility::CreateClient3(
457       AudioDeviceName::kDefaultDeviceId, eRender, eConsole);
458   EXPECT_TRUE(client3.Get());
459 
460   WAVEFORMATPCMEX format;
461   EXPECT_TRUE(SUCCEEDED(
462       core_audio_utility::GetSharedModeMixFormat(client3.Get(), &format)));
463 
464   uint32_t default_period = 0;
465   uint32_t fundamental_period = 0;
466   uint32_t min_period = 0;
467   uint32_t max_period = 0;
468   EXPECT_TRUE(SUCCEEDED(core_audio_utility::GetSharedModeEnginePeriod(
469       client3.Get(), &format, &default_period, &fundamental_period, &min_period,
470       &max_period)));
471 }
472 
473 // TODO(henrika): figure out why usage of this API always reports
474 // AUDCLNT_E_OFFLOAD_MODE_ONLY.
TEST_F(CoreAudioUtilityWinTest,DISABLED_GetBufferSizeLimits)475 TEST_F(CoreAudioUtilityWinTest, DISABLED_GetBufferSizeLimits) {
476   ABORT_TEST_IF_NOT(DevicesAvailable() &&
477                     core_audio_utility::GetAudioClientVersion() >= 2);
478 
479   ComPtr<IAudioClient2> client2 = core_audio_utility::CreateClient2(
480       AudioDeviceName::kDefaultDeviceId, eRender, eConsole);
481   EXPECT_TRUE(client2.Get());
482 
483   WAVEFORMATPCMEX format;
484   EXPECT_TRUE(SUCCEEDED(
485       core_audio_utility::GetSharedModeMixFormat(client2.Get(), &format)));
486 
487   REFERENCE_TIME min_buffer_duration = 0;
488   REFERENCE_TIME max_buffer_duration = 0;
489   EXPECT_TRUE(SUCCEEDED(core_audio_utility::GetBufferSizeLimits(
490       client2.Get(), &format, &min_buffer_duration, &max_buffer_duration)));
491 }
492 
TEST_F(CoreAudioUtilityWinTest,GetSharedModeMixFormat)493 TEST_F(CoreAudioUtilityWinTest, GetSharedModeMixFormat) {
494   ABORT_TEST_IF_NOT(DevicesAvailable());
495 
496   ComPtr<IAudioClient> client = core_audio_utility::CreateClient(
497       AudioDeviceName::kDefaultDeviceId, eRender, eConsole);
498   EXPECT_TRUE(client.Get());
499 
500   // Perform a simple sanity test of the acquired format structure.
501   WAVEFORMATEXTENSIBLE format;
502   EXPECT_TRUE(SUCCEEDED(
503       core_audio_utility::GetSharedModeMixFormat(client.Get(), &format)));
504   core_audio_utility::WaveFormatWrapper wformat(&format);
505   EXPECT_GE(wformat->nChannels, 1);
506   EXPECT_GE(wformat->nSamplesPerSec, 8000u);
507   EXPECT_GE(wformat->wBitsPerSample, 16);
508   if (wformat.IsExtensible()) {
509     EXPECT_EQ(wformat->wFormatTag, WAVE_FORMAT_EXTENSIBLE);
510     EXPECT_GE(wformat->cbSize, 22);
511     EXPECT_GE(wformat.GetExtensible()->Samples.wValidBitsPerSample, 16);
512   } else {
513     EXPECT_EQ(wformat->cbSize, 0);
514   }
515 }
516 
TEST_F(CoreAudioUtilityWinTest,IsFormatSupported)517 TEST_F(CoreAudioUtilityWinTest, IsFormatSupported) {
518   ABORT_TEST_IF_NOT(DevicesAvailable());
519 
520   // Create a default render client.
521   ComPtr<IAudioClient> client = core_audio_utility::CreateClient(
522       AudioDeviceName::kDefaultDeviceId, eRender, eConsole);
523   EXPECT_TRUE(client.Get());
524 
525   // Get the default, shared mode, mixing format.
526   WAVEFORMATEXTENSIBLE format;
527   EXPECT_TRUE(SUCCEEDED(
528       core_audio_utility::GetSharedModeMixFormat(client.Get(), &format)));
529 
530   // In shared mode, the audio engine always supports the mix format.
531   EXPECT_TRUE(core_audio_utility::IsFormatSupported(
532       client.Get(), AUDCLNT_SHAREMODE_SHARED, &format));
533 
534   // Use an invalid format and verify that it is not supported.
535   format.Format.nSamplesPerSec += 1;
536   EXPECT_FALSE(core_audio_utility::IsFormatSupported(
537       client.Get(), AUDCLNT_SHAREMODE_SHARED, &format));
538 }
539 
TEST_F(CoreAudioUtilityWinTest,GetDevicePeriod)540 TEST_F(CoreAudioUtilityWinTest, GetDevicePeriod) {
541   ABORT_TEST_IF_NOT(DevicesAvailable());
542 
543   EDataFlow data_flow[] = {eRender, eCapture};
544 
545   // Verify that the device periods are valid for the default render and
546   // capture devices.
547   ComPtr<IAudioClient> client;
548   for (size_t i = 0; i < arraysize(data_flow); ++i) {
549     REFERENCE_TIME shared_time_period = 0;
550     REFERENCE_TIME exclusive_time_period = 0;
551     client = core_audio_utility::CreateClient(AudioDeviceName::kDefaultDeviceId,
552                                               data_flow[i], eConsole);
553     EXPECT_TRUE(client.Get());
554     EXPECT_TRUE(SUCCEEDED(core_audio_utility::GetDevicePeriod(
555         client.Get(), AUDCLNT_SHAREMODE_SHARED, &shared_time_period)));
556     EXPECT_GT(shared_time_period, 0);
557     EXPECT_TRUE(SUCCEEDED(core_audio_utility::GetDevicePeriod(
558         client.Get(), AUDCLNT_SHAREMODE_EXCLUSIVE, &exclusive_time_period)));
559     EXPECT_GT(exclusive_time_period, 0);
560     EXPECT_LE(exclusive_time_period, shared_time_period);
561   }
562 }
563 
TEST_F(CoreAudioUtilityWinTest,GetPreferredAudioParameters)564 TEST_F(CoreAudioUtilityWinTest, GetPreferredAudioParameters) {
565   ABORT_TEST_IF_NOT(DevicesAvailable());
566 
567   struct {
568     EDataFlow flow;
569     ERole role;
570   } data[] = {{eRender, eConsole},
571               {eRender, eCommunications},
572               {eCapture, eConsole},
573               {eCapture, eCommunications}};
574 
575   // Verify that the preferred audio parameters are OK for all flow/role
576   // combinations above.
577   ComPtr<IAudioClient> client;
578   webrtc::AudioParameters params;
579   for (size_t i = 0; i < arraysize(data); ++i) {
580     client = core_audio_utility::CreateClient(AudioDeviceName::kDefaultDeviceId,
581                                               data[i].flow, data[i].role);
582     EXPECT_TRUE(client.Get());
583     EXPECT_TRUE(SUCCEEDED(core_audio_utility::GetPreferredAudioParameters(
584         client.Get(), &params)));
585     EXPECT_TRUE(params.is_valid());
586     EXPECT_TRUE(params.is_complete());
587   }
588 }
589 
TEST_F(CoreAudioUtilityWinTest,SharedModeInitialize)590 TEST_F(CoreAudioUtilityWinTest, SharedModeInitialize) {
591   ABORT_TEST_IF_NOT(DevicesAvailable());
592 
593   ComPtr<IAudioClient> client;
594   client = core_audio_utility::CreateClient(AudioDeviceName::kDefaultDeviceId,
595                                             eRender, eConsole);
596   EXPECT_TRUE(client.Get());
597 
598   WAVEFORMATPCMEX format;
599   EXPECT_TRUE(SUCCEEDED(
600       core_audio_utility::GetSharedModeMixFormat(client.Get(), &format)));
601 
602   // Perform a shared-mode initialization without event-driven buffer handling.
603   uint32_t endpoint_buffer_size = 0;
604   HRESULT hr = core_audio_utility::SharedModeInitialize(
605       client.Get(), &format, nullptr, 0, false, &endpoint_buffer_size);
606   EXPECT_TRUE(SUCCEEDED(hr));
607   EXPECT_GT(endpoint_buffer_size, 0u);
608 
609   // It is only possible to create a client once.
610   hr = core_audio_utility::SharedModeInitialize(
611       client.Get(), &format, nullptr, 0, false, &endpoint_buffer_size);
612   EXPECT_FALSE(SUCCEEDED(hr));
613   EXPECT_EQ(hr, AUDCLNT_E_ALREADY_INITIALIZED);
614 
615   // Verify that it is possible to reinitialize the client after releasing it
616   // and then creating a new client.
617   client = core_audio_utility::CreateClient(AudioDeviceName::kDefaultDeviceId,
618                                             eRender, eConsole);
619   EXPECT_TRUE(client.Get());
620   hr = core_audio_utility::SharedModeInitialize(
621       client.Get(), &format, nullptr, 0, false, &endpoint_buffer_size);
622   EXPECT_TRUE(SUCCEEDED(hr));
623   EXPECT_GT(endpoint_buffer_size, 0u);
624 
625   // Use a non-supported format and verify that initialization fails.
626   // A simple way to emulate an invalid format is to use the shared-mode
627   // mixing format and modify the preferred sample rate.
628   client = core_audio_utility::CreateClient(AudioDeviceName::kDefaultDeviceId,
629                                             eRender, eConsole);
630   EXPECT_TRUE(client.Get());
631   format.Format.nSamplesPerSec = format.Format.nSamplesPerSec + 1;
632   EXPECT_FALSE(core_audio_utility::IsFormatSupported(
633       client.Get(), AUDCLNT_SHAREMODE_SHARED, &format));
634   hr = core_audio_utility::SharedModeInitialize(
635       client.Get(), &format, nullptr, 0, false, &endpoint_buffer_size);
636   EXPECT_TRUE(FAILED(hr));
637   EXPECT_EQ(hr, E_INVALIDARG);
638 
639   // Finally, perform a shared-mode initialization using event-driven buffer
640   // handling. The event handle will be signaled when an audio buffer is ready
641   // to be processed by the client (not verified here). The event handle should
642   // be in the non-signaled state.
643   ScopedHandle event_handle(::CreateEvent(nullptr, TRUE, FALSE, nullptr));
644   client = core_audio_utility::CreateClient(AudioDeviceName::kDefaultDeviceId,
645                                             eRender, eConsole);
646   EXPECT_TRUE(client.Get());
647   EXPECT_TRUE(SUCCEEDED(
648       core_audio_utility::GetSharedModeMixFormat(client.Get(), &format)));
649   EXPECT_TRUE(core_audio_utility::IsFormatSupported(
650       client.Get(), AUDCLNT_SHAREMODE_SHARED, &format));
651   hr = core_audio_utility::SharedModeInitialize(
652       client.Get(), &format, event_handle, 0, false, &endpoint_buffer_size);
653   EXPECT_TRUE(SUCCEEDED(hr));
654   EXPECT_GT(endpoint_buffer_size, 0u);
655 
656   // TODO(henrika): possibly add test for signature which overrides the default
657   // sample rate.
658 }
659 
TEST_F(CoreAudioUtilityWinTest,CreateRenderAndCaptureClients)660 TEST_F(CoreAudioUtilityWinTest, CreateRenderAndCaptureClients) {
661   ABORT_TEST_IF_NOT(DevicesAvailable());
662 
663   EDataFlow data_flow[] = {eRender, eCapture};
664 
665   WAVEFORMATPCMEX format;
666   uint32_t endpoint_buffer_size = 0;
667 
668   for (size_t i = 0; i < arraysize(data_flow); ++i) {
669     ComPtr<IAudioClient> client;
670     ComPtr<IAudioRenderClient> render_client;
671     ComPtr<IAudioCaptureClient> capture_client;
672 
673     // Create a default client for the given data-flow direction.
674     client = core_audio_utility::CreateClient(AudioDeviceName::kDefaultDeviceId,
675                                               data_flow[i], eConsole);
676     EXPECT_TRUE(client.Get());
677     EXPECT_TRUE(SUCCEEDED(
678         core_audio_utility::GetSharedModeMixFormat(client.Get(), &format)));
679     if (data_flow[i] == eRender) {
680       // It is not possible to create a render client using an unitialized
681       // client interface.
682       render_client = core_audio_utility::CreateRenderClient(client.Get());
683       EXPECT_FALSE(render_client.Get());
684 
685       // Do a proper initialization and verify that it works this time.
686       core_audio_utility::SharedModeInitialize(client.Get(), &format, nullptr,
687                                                0, false, &endpoint_buffer_size);
688       render_client = core_audio_utility::CreateRenderClient(client.Get());
689       EXPECT_TRUE(render_client.Get());
690       EXPECT_GT(endpoint_buffer_size, 0u);
691     } else if (data_flow[i] == eCapture) {
692       // It is not possible to create a capture client using an unitialized
693       // client interface.
694       capture_client = core_audio_utility::CreateCaptureClient(client.Get());
695       EXPECT_FALSE(capture_client.Get());
696 
697       // Do a proper initialization and verify that it works this time.
698       core_audio_utility::SharedModeInitialize(client.Get(), &format, nullptr,
699                                                0, false, &endpoint_buffer_size);
700       capture_client = core_audio_utility::CreateCaptureClient(client.Get());
701       EXPECT_TRUE(capture_client.Get());
702       EXPECT_GT(endpoint_buffer_size, 0u);
703     }
704   }
705 }
706 
TEST_F(CoreAudioUtilityWinTest,CreateAudioClock)707 TEST_F(CoreAudioUtilityWinTest, CreateAudioClock) {
708   ABORT_TEST_IF_NOT(DevicesAvailable());
709 
710   EDataFlow data_flow[] = {eRender, eCapture};
711 
712   WAVEFORMATPCMEX format;
713   uint32_t endpoint_buffer_size = 0;
714 
715   for (size_t i = 0; i < arraysize(data_flow); ++i) {
716     ComPtr<IAudioClient> client;
717     ComPtr<IAudioClock> audio_clock;
718 
719     // Create a default client for the given data-flow direction.
720     client = core_audio_utility::CreateClient(AudioDeviceName::kDefaultDeviceId,
721                                               data_flow[i], eConsole);
722     EXPECT_TRUE(client.Get());
723     EXPECT_TRUE(SUCCEEDED(
724         core_audio_utility::GetSharedModeMixFormat(client.Get(), &format)));
725 
726     // It is not possible to create an audio clock using an unitialized client
727     // interface.
728     audio_clock = core_audio_utility::CreateAudioClock(client.Get());
729     EXPECT_FALSE(audio_clock.Get());
730 
731     // Do a proper initialization and verify that it works this time.
732     core_audio_utility::SharedModeInitialize(client.Get(), &format, nullptr, 0,
733                                              false, &endpoint_buffer_size);
734     audio_clock = core_audio_utility::CreateAudioClock(client.Get());
735     EXPECT_TRUE(audio_clock.Get());
736     EXPECT_GT(endpoint_buffer_size, 0u);
737 
738     // Use the audio clock and verify that querying the device frequency works.
739     UINT64 frequency = 0;
740     EXPECT_TRUE(SUCCEEDED(audio_clock->GetFrequency(&frequency)));
741     EXPECT_GT(frequency, 0u);
742   }
743 }
744 
TEST_F(CoreAudioUtilityWinTest,CreateAudioSessionControl)745 TEST_F(CoreAudioUtilityWinTest, CreateAudioSessionControl) {
746   ABORT_TEST_IF_NOT(DevicesAvailable());
747 
748   EDataFlow data_flow[] = {eRender, eCapture};
749 
750   WAVEFORMATPCMEX format;
751   uint32_t endpoint_buffer_size = 0;
752 
753   for (size_t i = 0; i < arraysize(data_flow); ++i) {
754     ComPtr<IAudioClient> client;
755     ComPtr<IAudioSessionControl> audio_session_control;
756 
757     // Create a default client for the given data-flow direction.
758     client = core_audio_utility::CreateClient(AudioDeviceName::kDefaultDeviceId,
759                                               data_flow[i], eConsole);
760     EXPECT_TRUE(client.Get());
761     EXPECT_TRUE(SUCCEEDED(
762         core_audio_utility::GetSharedModeMixFormat(client.Get(), &format)));
763 
764     // It is not possible to create an audio session control using an
765     // unitialized client interface.
766     audio_session_control =
767         core_audio_utility::CreateAudioSessionControl(client.Get());
768     EXPECT_FALSE(audio_session_control.Get());
769 
770     // Do a proper initialization and verify that it works this time.
771     core_audio_utility::SharedModeInitialize(client.Get(), &format, nullptr, 0,
772                                              false, &endpoint_buffer_size);
773     audio_session_control =
774         core_audio_utility::CreateAudioSessionControl(client.Get());
775     EXPECT_TRUE(audio_session_control.Get());
776     EXPECT_GT(endpoint_buffer_size, 0u);
777 
778     // Use the audio session control and verify that the session state can be
779     // queried. When a client opens a session by assigning the first stream to
780     // the session (by calling the IAudioClient::Initialize method), the initial
781     // session state is inactive. The session state changes from inactive to
782     // active when a stream in the session begins running (because the client
783     // has called the IAudioClient::Start method).
784     AudioSessionState state;
785     EXPECT_TRUE(SUCCEEDED(audio_session_control->GetState(&state)));
786     EXPECT_EQ(state, AudioSessionStateInactive);
787   }
788 }
789 
TEST_F(CoreAudioUtilityWinTest,CreateSimpleAudioVolume)790 TEST_F(CoreAudioUtilityWinTest, CreateSimpleAudioVolume) {
791   ABORT_TEST_IF_NOT(DevicesAvailable());
792 
793   EDataFlow data_flow[] = {eRender, eCapture};
794 
795   WAVEFORMATPCMEX format;
796   uint32_t endpoint_buffer_size = 0;
797 
798   for (size_t i = 0; i < arraysize(data_flow); ++i) {
799     ComPtr<IAudioClient> client;
800     ComPtr<ISimpleAudioVolume> simple_audio_volume;
801 
802     // Create a default client for the given data-flow direction.
803     client = core_audio_utility::CreateClient(AudioDeviceName::kDefaultDeviceId,
804                                               data_flow[i], eConsole);
805     EXPECT_TRUE(client.Get());
806     EXPECT_TRUE(SUCCEEDED(
807         core_audio_utility::GetSharedModeMixFormat(client.Get(), &format)));
808 
809     // It is not possible to create an audio volume using an uninitialized
810     // client interface.
811     simple_audio_volume =
812         core_audio_utility::CreateSimpleAudioVolume(client.Get());
813     EXPECT_FALSE(simple_audio_volume.Get());
814 
815     // Do a proper initialization and verify that it works this time.
816     core_audio_utility::SharedModeInitialize(client.Get(), &format, nullptr, 0,
817                                              false, &endpoint_buffer_size);
818     simple_audio_volume =
819         core_audio_utility::CreateSimpleAudioVolume(client.Get());
820     EXPECT_TRUE(simple_audio_volume.Get());
821     EXPECT_GT(endpoint_buffer_size, 0u);
822 
823     // Use the audio volume interface and validate that it works. The volume
824     // level should be value in the range 0.0 to 1.0 at first call.
825     float volume = 0.0;
826     EXPECT_TRUE(SUCCEEDED(simple_audio_volume->GetMasterVolume(&volume)));
827     EXPECT_GE(volume, 0.0);
828     EXPECT_LE(volume, 1.0);
829 
830     // Next, set a new volume and verify that the setter does its job.
831     const float target_volume = 0.5;
832     EXPECT_TRUE(SUCCEEDED(
833         simple_audio_volume->SetMasterVolume(target_volume, nullptr)));
834     EXPECT_TRUE(SUCCEEDED(simple_audio_volume->GetMasterVolume(&volume)));
835     EXPECT_EQ(volume, target_volume);
836   }
837 }
838 
TEST_F(CoreAudioUtilityWinTest,FillRenderEndpointBufferWithSilence)839 TEST_F(CoreAudioUtilityWinTest, FillRenderEndpointBufferWithSilence) {
840   ABORT_TEST_IF_NOT(DevicesAvailable());
841 
842   // Create default clients using the default mixing format for shared mode.
843   ComPtr<IAudioClient> client(core_audio_utility::CreateClient(
844       AudioDeviceName::kDefaultDeviceId, eRender, eConsole));
845   EXPECT_TRUE(client.Get());
846 
847   WAVEFORMATPCMEX format;
848   uint32_t endpoint_buffer_size = 0;
849   EXPECT_TRUE(SUCCEEDED(
850       core_audio_utility::GetSharedModeMixFormat(client.Get(), &format)));
851   core_audio_utility::SharedModeInitialize(client.Get(), &format, nullptr, 0,
852                                            false, &endpoint_buffer_size);
853   EXPECT_GT(endpoint_buffer_size, 0u);
854 
855   ComPtr<IAudioRenderClient> render_client(
856       core_audio_utility::CreateRenderClient(client.Get()));
857   EXPECT_TRUE(render_client.Get());
858 
859   // The endpoint audio buffer should not be filled up by default after being
860   // created.
861   UINT32 num_queued_frames = 0;
862   client->GetCurrentPadding(&num_queued_frames);
863   EXPECT_EQ(num_queued_frames, 0u);
864 
865   // Fill it up with zeros and verify that the buffer is full.
866   // It is not possible to verify that the actual data consists of zeros
867   // since we can't access data that has already been sent to the endpoint
868   // buffer.
869   EXPECT_TRUE(core_audio_utility::FillRenderEndpointBufferWithSilence(
870       client.Get(), render_client.Get()));
871   client->GetCurrentPadding(&num_queued_frames);
872   EXPECT_EQ(num_queued_frames, endpoint_buffer_size);
873 }
874 
875 }  // namespace webrtc_win
876 }  // namespace webrtc
877