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(), ¶ms)));
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