1 /*************************************************************************/
2 /* audio_driver_wasapi.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #ifdef WASAPI_ENABLED
32
33 #include "audio_driver_wasapi.h"
34
35 #include "core/os/os.h"
36 #include "core/project_settings.h"
37
38 #include <functiondiscoverykeys.h>
39
40 #ifndef PKEY_Device_FriendlyName
41
42 #undef DEFINE_PROPERTYKEY
43 /* clang-format off */
44 #define DEFINE_PROPERTYKEY(id, a, b, c, d, e, f, g, h, i, j, k, l) \
45 const PROPERTYKEY id = { { a, b, c, { d, e, f, g, h, i, j, k, } }, l };
46 /* clang-format on */
47
48 DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14);
49 #endif
50
51 const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
52 const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
53 const IID IID_IAudioClient = __uuidof(IAudioClient);
54 const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
55 const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
56
57 #define SAFE_RELEASE(memory) \
58 if ((memory) != NULL) { \
59 (memory)->Release(); \
60 (memory) = NULL; \
61 }
62
63 #define REFTIMES_PER_SEC 10000000
64 #define REFTIMES_PER_MILLISEC 10000
65
66 #define CAPTURE_BUFFER_CHANNELS 2
67
68 static bool default_render_device_changed = false;
69 static bool default_capture_device_changed = false;
70
71 class CMMNotificationClient : public IMMNotificationClient {
72 LONG _cRef;
73 IMMDeviceEnumerator *_pEnumerator;
74
75 public:
CMMNotificationClient()76 CMMNotificationClient() :
77 _cRef(1),
78 _pEnumerator(NULL) {}
~CMMNotificationClient()79 virtual ~CMMNotificationClient() {
80 if ((_pEnumerator) != NULL) {
81 (_pEnumerator)->Release();
82 (_pEnumerator) = NULL;
83 }
84 }
85
AddRef()86 ULONG STDMETHODCALLTYPE AddRef() {
87 return InterlockedIncrement(&_cRef);
88 }
89
Release()90 ULONG STDMETHODCALLTYPE Release() {
91 ULONG ulRef = InterlockedDecrement(&_cRef);
92 if (0 == ulRef) {
93 delete this;
94 }
95 return ulRef;
96 }
97
QueryInterface(REFIID riid,VOID ** ppvInterface)98 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) {
99 if (IID_IUnknown == riid) {
100 AddRef();
101 *ppvInterface = (IUnknown *)this;
102 } else if (__uuidof(IMMNotificationClient) == riid) {
103 AddRef();
104 *ppvInterface = (IMMNotificationClient *)this;
105 } else {
106 *ppvInterface = NULL;
107 return E_NOINTERFACE;
108 }
109 return S_OK;
110 }
111
OnDeviceAdded(LPCWSTR pwstrDeviceId)112 HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId) {
113 return S_OK;
114 };
115
OnDeviceRemoved(LPCWSTR pwstrDeviceId)116 HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId) {
117 return S_OK;
118 }
119
OnDeviceStateChanged(LPCWSTR pwstrDeviceId,DWORD dwNewState)120 HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) {
121 return S_OK;
122 }
123
OnDefaultDeviceChanged(EDataFlow flow,ERole role,LPCWSTR pwstrDeviceId)124 HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId) {
125 if (role == eConsole) {
126 if (flow == eRender) {
127 default_render_device_changed = true;
128 } else if (flow == eCapture) {
129 default_capture_device_changed = true;
130 }
131 }
132
133 return S_OK;
134 }
135
OnPropertyValueChanged(LPCWSTR pwstrDeviceId,const PROPERTYKEY key)136 HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) {
137 return S_OK;
138 }
139 };
140
141 static CMMNotificationClient notif_client;
142
audio_device_init(AudioDeviceWASAPI * p_device,bool p_capture,bool reinit)143 Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit) {
144
145 WAVEFORMATEX *pwfex;
146 IMMDeviceEnumerator *enumerator = NULL;
147 IMMDevice *device = NULL;
148
149 CoInitialize(NULL);
150
151 HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
152 ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
153
154 if (p_device->device_name == "Default") {
155 hr = enumerator->GetDefaultAudioEndpoint(p_capture ? eCapture : eRender, eConsole, &device);
156 } else {
157 IMMDeviceCollection *devices = NULL;
158
159 hr = enumerator->EnumAudioEndpoints(p_capture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices);
160 ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
161
162 LPWSTR strId = NULL;
163 bool found = false;
164
165 UINT count = 0;
166 hr = devices->GetCount(&count);
167 ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
168
169 for (ULONG i = 0; i < count && !found; i++) {
170 IMMDevice *tmp_device = NULL;
171
172 hr = devices->Item(i, &tmp_device);
173 ERR_BREAK(hr != S_OK);
174
175 IPropertyStore *props = NULL;
176 hr = tmp_device->OpenPropertyStore(STGM_READ, &props);
177 ERR_BREAK(hr != S_OK);
178
179 PROPVARIANT propvar;
180 PropVariantInit(&propvar);
181
182 hr = props->GetValue(PKEY_Device_FriendlyName, &propvar);
183 ERR_BREAK(hr != S_OK);
184
185 if (p_device->device_name == String(propvar.pwszVal)) {
186 hr = tmp_device->GetId(&strId);
187 ERR_BREAK(hr != S_OK);
188
189 found = true;
190 }
191
192 PropVariantClear(&propvar);
193 props->Release();
194 tmp_device->Release();
195 }
196
197 if (found) {
198 hr = enumerator->GetDevice(strId, &device);
199 }
200
201 if (strId) {
202 CoTaskMemFree(strId);
203 }
204
205 if (device == NULL) {
206 hr = enumerator->GetDefaultAudioEndpoint(p_capture ? eCapture : eRender, eConsole, &device);
207 }
208 }
209
210 if (reinit) {
211 // In case we're trying to re-initialize the device prevent throwing this error on the console,
212 // otherwise if there is currently no device available this will spam the console.
213 if (hr != S_OK) {
214 return ERR_CANT_OPEN;
215 }
216 } else {
217 ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
218 }
219
220 hr = enumerator->RegisterEndpointNotificationCallback(¬if_client);
221 SAFE_RELEASE(enumerator)
222
223 if (hr != S_OK) {
224 ERR_PRINT("WASAPI: RegisterEndpointNotificationCallback error");
225 }
226
227 hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&p_device->audio_client);
228 SAFE_RELEASE(device)
229
230 if (reinit) {
231 if (hr != S_OK) {
232 return ERR_CANT_OPEN;
233 }
234 } else {
235 ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
236 }
237
238 hr = p_device->audio_client->GetMixFormat(&pwfex);
239 ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
240
241 print_verbose("WASAPI: wFormatTag = " + itos(pwfex->wFormatTag));
242 print_verbose("WASAPI: nChannels = " + itos(pwfex->nChannels));
243 print_verbose("WASAPI: nSamplesPerSec = " + itos(pwfex->nSamplesPerSec));
244 print_verbose("WASAPI: nAvgBytesPerSec = " + itos(pwfex->nAvgBytesPerSec));
245 print_verbose("WASAPI: nBlockAlign = " + itos(pwfex->nBlockAlign));
246 print_verbose("WASAPI: wBitsPerSample = " + itos(pwfex->wBitsPerSample));
247 print_verbose("WASAPI: cbSize = " + itos(pwfex->cbSize));
248
249 WAVEFORMATEX *closest = NULL;
250 hr = p_device->audio_client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, pwfex, &closest);
251 if (hr == S_FALSE) {
252 WARN_PRINT("WASAPI: Mix format is not supported by the Device");
253 if (closest) {
254 print_verbose("WASAPI: closest->wFormatTag = " + itos(closest->wFormatTag));
255 print_verbose("WASAPI: closest->nChannels = " + itos(closest->nChannels));
256 print_verbose("WASAPI: closest->nSamplesPerSec = " + itos(closest->nSamplesPerSec));
257 print_verbose("WASAPI: closest->nAvgBytesPerSec = " + itos(closest->nAvgBytesPerSec));
258 print_verbose("WASAPI: closest->nBlockAlign = " + itos(closest->nBlockAlign));
259 print_verbose("WASAPI: closest->wBitsPerSample = " + itos(closest->wBitsPerSample));
260 print_verbose("WASAPI: closest->cbSize = " + itos(closest->cbSize));
261
262 WARN_PRINT("WASAPI: Using closest match instead");
263 pwfex = closest;
264 }
265 }
266
267 // Since we're using WASAPI Shared Mode we can't control any of these, we just tag along
268 p_device->channels = pwfex->nChannels;
269 p_device->format_tag = pwfex->wFormatTag;
270 p_device->bits_per_sample = pwfex->wBitsPerSample;
271 p_device->frame_size = (p_device->bits_per_sample / 8) * p_device->channels;
272
273 if (p_device->format_tag == WAVE_FORMAT_EXTENSIBLE) {
274 WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE *)pwfex;
275
276 if (wfex->SubFormat == KSDATAFORMAT_SUBTYPE_PCM) {
277 p_device->format_tag = WAVE_FORMAT_PCM;
278 } else if (wfex->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) {
279 p_device->format_tag = WAVE_FORMAT_IEEE_FLOAT;
280 } else {
281 ERR_PRINT("WASAPI: Format not supported");
282 ERR_FAIL_V(ERR_CANT_OPEN);
283 }
284 } else {
285 if (p_device->format_tag != WAVE_FORMAT_PCM && p_device->format_tag != WAVE_FORMAT_IEEE_FLOAT) {
286 ERR_PRINT("WASAPI: Format not supported");
287 ERR_FAIL_V(ERR_CANT_OPEN);
288 }
289 }
290
291 DWORD streamflags = 0;
292 if ((DWORD)mix_rate != pwfex->nSamplesPerSec) {
293 streamflags |= AUDCLNT_STREAMFLAGS_RATEADJUST;
294 pwfex->nSamplesPerSec = mix_rate;
295 pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nChannels * (pwfex->wBitsPerSample / 8);
296 }
297
298 hr = p_device->audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, p_capture ? REFTIMES_PER_SEC : 0, 0, pwfex, NULL);
299 ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_CANT_OPEN, "WASAPI: Initialize failed with error 0x" + String::num_uint64(hr, 16) + ".");
300
301 if (p_capture) {
302 hr = p_device->audio_client->GetService(IID_IAudioCaptureClient, (void **)&p_device->capture_client);
303 } else {
304 hr = p_device->audio_client->GetService(IID_IAudioRenderClient, (void **)&p_device->render_client);
305 }
306 ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
307
308 // Free memory
309 CoTaskMemFree(pwfex);
310 SAFE_RELEASE(device)
311
312 return OK;
313 }
314
init_render_device(bool reinit)315 Error AudioDriverWASAPI::init_render_device(bool reinit) {
316
317 Error err = audio_device_init(&audio_output, false, reinit);
318 if (err != OK)
319 return err;
320
321 switch (audio_output.channels) {
322 case 2: // Stereo
323 case 4: // Surround 3.1
324 case 6: // Surround 5.1
325 case 8: // Surround 7.1
326 channels = audio_output.channels;
327 break;
328
329 default:
330 WARN_PRINTS("WASAPI: Unsupported number of channels: " + itos(audio_output.channels));
331 channels = 2;
332 break;
333 }
334
335 UINT32 max_frames;
336 HRESULT hr = audio_output.audio_client->GetBufferSize(&max_frames);
337 ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
338
339 // Due to WASAPI Shared Mode we have no control of the buffer size
340 buffer_frames = max_frames;
341
342 // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
343 samples_in.resize(buffer_frames * channels);
344
345 input_position = 0;
346 input_size = 0;
347
348 print_verbose("WASAPI: detected " + itos(channels) + " channels");
349 print_verbose("WASAPI: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
350
351 return OK;
352 }
353
init_capture_device(bool reinit)354 Error AudioDriverWASAPI::init_capture_device(bool reinit) {
355
356 Error err = audio_device_init(&audio_input, true, reinit);
357 if (err != OK)
358 return err;
359
360 // Get the max frames
361 UINT32 max_frames;
362 HRESULT hr = audio_input.audio_client->GetBufferSize(&max_frames);
363 ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
364
365 input_buffer_init(max_frames);
366
367 return OK;
368 }
369
audio_device_finish(AudioDeviceWASAPI * p_device)370 Error AudioDriverWASAPI::audio_device_finish(AudioDeviceWASAPI *p_device) {
371
372 if (p_device->active) {
373 if (p_device->audio_client) {
374 p_device->audio_client->Stop();
375 }
376
377 p_device->active = false;
378 }
379
380 SAFE_RELEASE(p_device->audio_client)
381 SAFE_RELEASE(p_device->render_client)
382 SAFE_RELEASE(p_device->capture_client)
383
384 return OK;
385 }
386
finish_render_device()387 Error AudioDriverWASAPI::finish_render_device() {
388
389 return audio_device_finish(&audio_output);
390 }
391
finish_capture_device()392 Error AudioDriverWASAPI::finish_capture_device() {
393
394 return audio_device_finish(&audio_input);
395 }
396
init()397 Error AudioDriverWASAPI::init() {
398
399 mix_rate = GLOBAL_GET("audio/mix_rate");
400
401 Error err = init_render_device();
402 if (err != OK) {
403 ERR_PRINT("WASAPI: init_render_device error");
404 }
405
406 exit_thread = false;
407 thread_exited = false;
408
409 mutex = Mutex::create(true);
410 thread = Thread::create(thread_func, this);
411
412 return OK;
413 }
414
get_mix_rate() const415 int AudioDriverWASAPI::get_mix_rate() const {
416
417 return mix_rate;
418 }
419
get_speaker_mode() const420 AudioDriver::SpeakerMode AudioDriverWASAPI::get_speaker_mode() const {
421
422 return get_speaker_mode_by_total_channels(channels);
423 }
424
audio_device_get_list(bool p_capture)425 Array AudioDriverWASAPI::audio_device_get_list(bool p_capture) {
426
427 Array list;
428 IMMDeviceCollection *devices = NULL;
429 IMMDeviceEnumerator *enumerator = NULL;
430
431 list.push_back(String("Default"));
432
433 CoInitialize(NULL);
434
435 HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
436 ERR_FAIL_COND_V(hr != S_OK, Array());
437
438 hr = enumerator->EnumAudioEndpoints(p_capture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices);
439 ERR_FAIL_COND_V(hr != S_OK, Array());
440
441 UINT count = 0;
442 hr = devices->GetCount(&count);
443 ERR_FAIL_COND_V(hr != S_OK, Array());
444
445 for (ULONG i = 0; i < count; i++) {
446 IMMDevice *device = NULL;
447
448 hr = devices->Item(i, &device);
449 ERR_BREAK(hr != S_OK);
450
451 IPropertyStore *props = NULL;
452 hr = device->OpenPropertyStore(STGM_READ, &props);
453 ERR_BREAK(hr != S_OK);
454
455 PROPVARIANT propvar;
456 PropVariantInit(&propvar);
457
458 hr = props->GetValue(PKEY_Device_FriendlyName, &propvar);
459 ERR_BREAK(hr != S_OK);
460
461 list.push_back(String(propvar.pwszVal));
462
463 PropVariantClear(&propvar);
464 props->Release();
465 device->Release();
466 }
467
468 devices->Release();
469 enumerator->Release();
470 return list;
471 }
472
get_device_list()473 Array AudioDriverWASAPI::get_device_list() {
474
475 return audio_device_get_list(false);
476 }
477
get_device()478 String AudioDriverWASAPI::get_device() {
479
480 lock();
481 String name = audio_output.device_name;
482 unlock();
483
484 return name;
485 }
486
set_device(String device)487 void AudioDriverWASAPI::set_device(String device) {
488
489 lock();
490 audio_output.new_device = device;
491 unlock();
492 }
493
read_sample(WORD format_tag,int bits_per_sample,BYTE * buffer,int i)494 int32_t AudioDriverWASAPI::read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i) {
495 if (format_tag == WAVE_FORMAT_PCM) {
496 int32_t sample = 0;
497 switch (bits_per_sample) {
498 case 8:
499 sample = int32_t(((int8_t *)buffer)[i]) << 24;
500 break;
501
502 case 16:
503 sample = int32_t(((int16_t *)buffer)[i]) << 16;
504 break;
505
506 case 24:
507 sample |= int32_t(((int8_t *)buffer)[i * 3 + 2]) << 24;
508 sample |= int32_t(((int8_t *)buffer)[i * 3 + 1]) << 16;
509 sample |= int32_t(((int8_t *)buffer)[i * 3 + 0]) << 8;
510 break;
511
512 case 32:
513 sample = ((int32_t *)buffer)[i];
514 break;
515 }
516
517 return sample;
518 } else if (format_tag == WAVE_FORMAT_IEEE_FLOAT) {
519 return int32_t(((float *)buffer)[i] * 32768.0) << 16;
520 } else {
521 ERR_PRINT("WASAPI: Unknown format tag");
522 }
523
524 return 0;
525 }
526
write_sample(WORD format_tag,int bits_per_sample,BYTE * buffer,int i,int32_t sample)527 void AudioDriverWASAPI::write_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i, int32_t sample) {
528 if (format_tag == WAVE_FORMAT_PCM) {
529 switch (bits_per_sample) {
530 case 8:
531 ((int8_t *)buffer)[i] = sample >> 24;
532 break;
533
534 case 16:
535 ((int16_t *)buffer)[i] = sample >> 16;
536 break;
537
538 case 24:
539 ((int8_t *)buffer)[i * 3 + 2] = sample >> 24;
540 ((int8_t *)buffer)[i * 3 + 1] = sample >> 16;
541 ((int8_t *)buffer)[i * 3 + 0] = sample >> 8;
542 break;
543
544 case 32:
545 ((int32_t *)buffer)[i] = sample;
546 break;
547 }
548 } else if (format_tag == WAVE_FORMAT_IEEE_FLOAT) {
549 ((float *)buffer)[i] = (sample >> 16) / 32768.f;
550 } else {
551 ERR_PRINT("WASAPI: Unknown format tag");
552 }
553 }
554
thread_func(void * p_udata)555 void AudioDriverWASAPI::thread_func(void *p_udata) {
556
557 AudioDriverWASAPI *ad = (AudioDriverWASAPI *)p_udata;
558 uint32_t avail_frames = 0;
559 uint32_t write_ofs = 0;
560
561 while (!ad->exit_thread) {
562
563 uint32_t read_frames = 0;
564 uint32_t written_frames = 0;
565
566 if (avail_frames == 0) {
567 ad->lock();
568 ad->start_counting_ticks();
569
570 if (ad->audio_output.active) {
571 ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw());
572 } else {
573 for (int i = 0; i < ad->samples_in.size(); i++) {
574 ad->samples_in.write[i] = 0;
575 }
576 }
577
578 avail_frames = ad->buffer_frames;
579 write_ofs = 0;
580
581 ad->stop_counting_ticks();
582 ad->unlock();
583 }
584
585 ad->lock();
586 ad->start_counting_ticks();
587
588 if (avail_frames > 0 && ad->audio_output.audio_client) {
589
590 UINT32 cur_frames;
591 bool invalidated = false;
592 HRESULT hr = ad->audio_output.audio_client->GetCurrentPadding(&cur_frames);
593 if (hr == S_OK) {
594
595 // Check how much frames are available on the WASAPI buffer
596 UINT32 write_frames = MIN(ad->buffer_frames - cur_frames, avail_frames);
597 if (write_frames > 0) {
598 BYTE *buffer = NULL;
599 hr = ad->audio_output.render_client->GetBuffer(write_frames, &buffer);
600 if (hr == S_OK) {
601
602 // We're using WASAPI Shared Mode so we must convert the buffer
603 if (ad->channels == ad->audio_output.channels) {
604 for (unsigned int i = 0; i < write_frames * ad->channels; i++) {
605 ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i, ad->samples_in.write[write_ofs++]);
606 }
607 } else {
608 for (unsigned int i = 0; i < write_frames; i++) {
609 for (unsigned int j = 0; j < MIN(ad->channels, ad->audio_output.channels); j++) {
610 ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i * ad->audio_output.channels + j, ad->samples_in.write[write_ofs++]);
611 }
612 if (ad->audio_output.channels > ad->channels) {
613 for (unsigned int j = ad->channels; j < ad->audio_output.channels; j++) {
614 ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i * ad->audio_output.channels + j, 0);
615 }
616 }
617 }
618 }
619
620 hr = ad->audio_output.render_client->ReleaseBuffer(write_frames, 0);
621 if (hr != S_OK) {
622 ERR_PRINT("WASAPI: Release buffer error");
623 }
624
625 avail_frames -= write_frames;
626 written_frames += write_frames;
627 } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
628 // Device is not valid anymore, reopen it
629
630 Error err = ad->finish_render_device();
631 if (err != OK) {
632 ERR_PRINT("WASAPI: finish_render_device error");
633 } else {
634 // We reopened the device and samples_in may have resized, so invalidate the current avail_frames
635 avail_frames = 0;
636 }
637 } else {
638 ERR_PRINT("WASAPI: Get buffer error");
639 ad->exit_thread = true;
640 }
641 }
642 } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
643 invalidated = true;
644 } else {
645 ERR_PRINT("WASAPI: GetCurrentPadding error");
646 }
647
648 if (invalidated) {
649 // Device is not valid anymore
650 WARN_PRINT("WASAPI: Current device invalidated, closing device");
651
652 Error err = ad->finish_render_device();
653 if (err != OK) {
654 ERR_PRINT("WASAPI: finish_render_device error");
655 }
656 }
657 }
658
659 // If we're using the Default device and it changed finish it so we'll re-init the device
660 if (ad->audio_output.device_name == "Default" && default_render_device_changed) {
661 Error err = ad->finish_render_device();
662 if (err != OK) {
663 ERR_PRINT("WASAPI: finish_render_device error");
664 }
665
666 default_render_device_changed = false;
667 }
668
669 // User selected a new device, finish the current one so we'll init the new device
670 if (ad->audio_output.device_name != ad->audio_output.new_device) {
671 ad->audio_output.device_name = ad->audio_output.new_device;
672 Error err = ad->finish_render_device();
673 if (err != OK) {
674 ERR_PRINT("WASAPI: finish_render_device error");
675 }
676 }
677
678 if (!ad->audio_output.audio_client) {
679 Error err = ad->init_render_device(true);
680 if (err == OK) {
681 ad->start();
682 }
683
684 avail_frames = 0;
685 write_ofs = 0;
686 }
687
688 if (ad->audio_input.active) {
689 UINT32 packet_length = 0;
690 BYTE *data;
691 UINT32 num_frames_available;
692 DWORD flags;
693
694 HRESULT hr = ad->audio_input.capture_client->GetNextPacketSize(&packet_length);
695 if (hr == S_OK) {
696 while (packet_length != 0) {
697 hr = ad->audio_input.capture_client->GetBuffer(&data, &num_frames_available, &flags, NULL, NULL);
698 ERR_BREAK(hr != S_OK);
699
700 // fixme: Only works for floating point atm
701 for (UINT32 j = 0; j < num_frames_available; j++) {
702 int32_t l, r;
703
704 if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
705 l = r = 0;
706 } else {
707 if (ad->audio_input.channels == 2) {
708 l = read_sample(ad->audio_input.format_tag, ad->audio_input.bits_per_sample, data, j * 2);
709 r = read_sample(ad->audio_input.format_tag, ad->audio_input.bits_per_sample, data, j * 2 + 1);
710 } else if (ad->audio_input.channels == 1) {
711 l = r = read_sample(ad->audio_input.format_tag, ad->audio_input.bits_per_sample, data, j);
712 } else {
713 l = r = 0;
714 ERR_PRINT("WASAPI: unsupported channel count in microphone!");
715 }
716 }
717
718 ad->input_buffer_write(l);
719 ad->input_buffer_write(r);
720 }
721
722 read_frames += num_frames_available;
723
724 hr = ad->audio_input.capture_client->ReleaseBuffer(num_frames_available);
725 ERR_BREAK(hr != S_OK);
726
727 hr = ad->audio_input.capture_client->GetNextPacketSize(&packet_length);
728 ERR_BREAK(hr != S_OK);
729 }
730 }
731
732 // If we're using the Default device and it changed finish it so we'll re-init the device
733 if (ad->audio_input.device_name == "Default" && default_capture_device_changed) {
734 Error err = ad->finish_capture_device();
735 if (err != OK) {
736 ERR_PRINT("WASAPI: finish_capture_device error");
737 }
738
739 default_capture_device_changed = false;
740 }
741
742 // User selected a new device, finish the current one so we'll init the new device
743 if (ad->audio_input.device_name != ad->audio_input.new_device) {
744 ad->audio_input.device_name = ad->audio_input.new_device;
745 Error err = ad->finish_capture_device();
746 if (err != OK) {
747 ERR_PRINT("WASAPI: finish_capture_device error");
748 }
749 }
750
751 if (!ad->audio_input.audio_client) {
752 Error err = ad->init_capture_device(true);
753 if (err == OK) {
754 ad->capture_start();
755 }
756 }
757 }
758
759 ad->stop_counting_ticks();
760 ad->unlock();
761
762 // Let the thread rest a while if we haven't read or write anything
763 if (written_frames == 0 && read_frames == 0) {
764 OS::get_singleton()->delay_usec(1000);
765 }
766 }
767
768 ad->thread_exited = true;
769 }
770
start()771 void AudioDriverWASAPI::start() {
772
773 if (audio_output.audio_client) {
774 HRESULT hr = audio_output.audio_client->Start();
775 if (hr != S_OK) {
776 ERR_PRINT("WASAPI: Start failed");
777 } else {
778 audio_output.active = true;
779 }
780 }
781 }
782
lock()783 void AudioDriverWASAPI::lock() {
784
785 if (mutex)
786 mutex->lock();
787 }
788
unlock()789 void AudioDriverWASAPI::unlock() {
790
791 if (mutex)
792 mutex->unlock();
793 }
794
finish()795 void AudioDriverWASAPI::finish() {
796
797 if (thread) {
798 exit_thread = true;
799 Thread::wait_to_finish(thread);
800
801 memdelete(thread);
802 thread = NULL;
803 }
804
805 finish_capture_device();
806 finish_render_device();
807
808 if (mutex) {
809 memdelete(mutex);
810 mutex = NULL;
811 }
812 }
813
capture_start()814 Error AudioDriverWASAPI::capture_start() {
815
816 Error err = init_capture_device();
817 if (err != OK) {
818 ERR_PRINT("WASAPI: init_capture_device error");
819 return err;
820 }
821
822 if (audio_input.active) {
823 return FAILED;
824 }
825
826 audio_input.audio_client->Start();
827 audio_input.active = true;
828 return OK;
829 }
830
capture_stop()831 Error AudioDriverWASAPI::capture_stop() {
832
833 if (audio_input.active) {
834 audio_input.audio_client->Stop();
835 audio_input.active = false;
836
837 return OK;
838 }
839
840 return FAILED;
841 }
842
capture_set_device(const String & p_name)843 void AudioDriverWASAPI::capture_set_device(const String &p_name) {
844
845 lock();
846 audio_input.new_device = p_name;
847 unlock();
848 }
849
capture_get_device_list()850 Array AudioDriverWASAPI::capture_get_device_list() {
851
852 return audio_device_get_list(true);
853 }
854
capture_get_device()855 String AudioDriverWASAPI::capture_get_device() {
856
857 lock();
858 String name = audio_input.device_name;
859 unlock();
860
861 return name;
862 }
863
AudioDriverWASAPI()864 AudioDriverWASAPI::AudioDriverWASAPI() {
865
866 mutex = NULL;
867 thread = NULL;
868
869 samples_in.clear();
870
871 channels = 0;
872 mix_rate = 0;
873 buffer_frames = 0;
874
875 thread_exited = false;
876 exit_thread = false;
877 }
878
879 #endif
880