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