audio_driver_wasapi.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  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-2018 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2018 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. #ifdef WASAPI_ENABLED
  31. #include "audio_driver_wasapi.h"
  32. #include "os/os.h"
  33. #include "project_settings.h"
  34. #include <functiondiscoverykeys.h>
  35. const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
  36. const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
  37. const IID IID_IAudioClient = __uuidof(IAudioClient);
  38. const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
  39. static bool default_device_changed = false;
  40. class CMMNotificationClient : public IMMNotificationClient {
  41. LONG _cRef;
  42. IMMDeviceEnumerator *_pEnumerator;
  43. public:
  44. CMMNotificationClient() :
  45. _cRef(1),
  46. _pEnumerator(NULL) {}
  47. ~CMMNotificationClient() {
  48. if ((_pEnumerator) != NULL) {
  49. (_pEnumerator)->Release();
  50. (_pEnumerator) = NULL;
  51. }
  52. }
  53. ULONG STDMETHODCALLTYPE AddRef() {
  54. return InterlockedIncrement(&_cRef);
  55. }
  56. ULONG STDMETHODCALLTYPE Release() {
  57. ULONG ulRef = InterlockedDecrement(&_cRef);
  58. if (0 == ulRef) {
  59. delete this;
  60. }
  61. return ulRef;
  62. }
  63. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) {
  64. if (IID_IUnknown == riid) {
  65. AddRef();
  66. *ppvInterface = (IUnknown *)this;
  67. } else if (__uuidof(IMMNotificationClient) == riid) {
  68. AddRef();
  69. *ppvInterface = (IMMNotificationClient *)this;
  70. } else {
  71. *ppvInterface = NULL;
  72. return E_NOINTERFACE;
  73. }
  74. return S_OK;
  75. }
  76. HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId) {
  77. return S_OK;
  78. };
  79. HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId) {
  80. return S_OK;
  81. }
  82. HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) {
  83. return S_OK;
  84. }
  85. HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId) {
  86. if (flow == eRender && role == eConsole) {
  87. default_device_changed = true;
  88. }
  89. return S_OK;
  90. }
  91. HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) {
  92. return S_OK;
  93. }
  94. };
  95. static CMMNotificationClient notif_client;
  96. Error AudioDriverWASAPI::init_device(bool reinit) {
  97. WAVEFORMATEX *pwfex;
  98. IMMDeviceEnumerator *enumerator = NULL;
  99. IMMDevice *device = NULL;
  100. CoInitialize(NULL);
  101. HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
  102. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  103. if (device_name == "Default") {
  104. hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device);
  105. } else {
  106. IMMDeviceCollection *devices = NULL;
  107. hr = enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devices);
  108. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  109. LPWSTR strId = NULL;
  110. bool found = false;
  111. UINT count = 0;
  112. hr = devices->GetCount(&count);
  113. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  114. for (ULONG i = 0; i < count && !found; i++) {
  115. IMMDevice *device = NULL;
  116. hr = devices->Item(i, &device);
  117. ERR_BREAK(hr != S_OK);
  118. IPropertyStore *props = NULL;
  119. hr = device->OpenPropertyStore(STGM_READ, &props);
  120. ERR_BREAK(hr != S_OK);
  121. PROPVARIANT propvar;
  122. PropVariantInit(&propvar);
  123. hr = props->GetValue(PKEY_Device_FriendlyName, &propvar);
  124. ERR_BREAK(hr != S_OK);
  125. if (device_name == String(propvar.pwszVal)) {
  126. hr = device->GetId(&strId);
  127. ERR_BREAK(hr != S_OK);
  128. found = true;
  129. }
  130. PropVariantClear(&propvar);
  131. props->Release();
  132. device->Release();
  133. }
  134. if (found) {
  135. hr = enumerator->GetDevice(strId, &device);
  136. }
  137. if (strId) {
  138. CoTaskMemFree(strId);
  139. }
  140. if (device == NULL) {
  141. hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device);
  142. }
  143. }
  144. if (reinit) {
  145. // In case we're trying to re-initialize the device prevent throwing this error on the console,
  146. // otherwise if there is currently no device available this will spam the console.
  147. if (hr != S_OK) {
  148. return ERR_CANT_OPEN;
  149. }
  150. } else {
  151. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  152. }
  153. hr = enumerator->RegisterEndpointNotificationCallback(&notif_client);
  154. if (hr != S_OK) {
  155. ERR_PRINT("WASAPI: RegisterEndpointNotificationCallback error");
  156. }
  157. hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&audio_client);
  158. if (reinit) {
  159. if (hr != S_OK) {
  160. return ERR_CANT_OPEN;
  161. }
  162. } else {
  163. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  164. }
  165. hr = audio_client->GetMixFormat(&pwfex);
  166. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  167. // Since we're using WASAPI Shared Mode we can't control any of these, we just tag along
  168. wasapi_channels = pwfex->nChannels;
  169. format_tag = pwfex->wFormatTag;
  170. bits_per_sample = pwfex->wBitsPerSample;
  171. switch (wasapi_channels) {
  172. case 2: // Stereo
  173. case 4: // Surround 3.1
  174. case 6: // Surround 5.1
  175. case 8: // Surround 7.1
  176. channels = wasapi_channels;
  177. break;
  178. default:
  179. WARN_PRINTS("WASAPI: Unsupported number of channels: " + itos(wasapi_channels));
  180. channels = 2;
  181. break;
  182. }
  183. if (format_tag == WAVE_FORMAT_EXTENSIBLE) {
  184. WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE *)pwfex;
  185. if (wfex->SubFormat == KSDATAFORMAT_SUBTYPE_PCM) {
  186. format_tag = WAVE_FORMAT_PCM;
  187. } else if (wfex->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) {
  188. format_tag = WAVE_FORMAT_IEEE_FLOAT;
  189. } else {
  190. ERR_PRINT("WASAPI: Format not supported");
  191. ERR_FAIL_V(ERR_CANT_OPEN);
  192. }
  193. } else {
  194. if (format_tag != WAVE_FORMAT_PCM && format_tag != WAVE_FORMAT_IEEE_FLOAT) {
  195. ERR_PRINT("WASAPI: Format not supported");
  196. ERR_FAIL_V(ERR_CANT_OPEN);
  197. }
  198. }
  199. DWORD streamflags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
  200. if (mix_rate != pwfex->nSamplesPerSec) {
  201. streamflags |= AUDCLNT_STREAMFLAGS_RATEADJUST;
  202. pwfex->nSamplesPerSec = mix_rate;
  203. pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nChannels * (pwfex->wBitsPerSample / 8);
  204. }
  205. hr = audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, 0, 0, pwfex, NULL);
  206. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  207. event = CreateEvent(NULL, FALSE, FALSE, NULL);
  208. ERR_FAIL_COND_V(event == NULL, ERR_CANT_OPEN);
  209. hr = audio_client->SetEventHandle(event);
  210. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  211. hr = audio_client->GetService(IID_IAudioRenderClient, (void **)&render_client);
  212. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  213. UINT32 max_frames;
  214. hr = audio_client->GetBufferSize(&max_frames);
  215. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  216. // Due to WASAPI Shared Mode we have no control of the buffer size
  217. buffer_frames = max_frames;
  218. // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
  219. buffer_size = buffer_frames * channels;
  220. samples_in.resize(buffer_size);
  221. if (OS::get_singleton()->is_stdout_verbose()) {
  222. print_line("WASAPI: detected " + itos(channels) + " channels");
  223. print_line("WASAPI: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
  224. }
  225. return OK;
  226. }
  227. Error AudioDriverWASAPI::finish_device() {
  228. if (audio_client) {
  229. if (active) {
  230. audio_client->Stop();
  231. active = false;
  232. }
  233. audio_client->Release();
  234. audio_client = NULL;
  235. }
  236. if (render_client) {
  237. render_client->Release();
  238. render_client = NULL;
  239. }
  240. if (audio_client) {
  241. audio_client->Release();
  242. audio_client = NULL;
  243. }
  244. return OK;
  245. }
  246. Error AudioDriverWASAPI::init() {
  247. mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE);
  248. Error err = init_device();
  249. if (err != OK) {
  250. ERR_PRINT("WASAPI: init_device error");
  251. }
  252. active = false;
  253. exit_thread = false;
  254. thread_exited = false;
  255. mutex = Mutex::create(true);
  256. thread = Thread::create(thread_func, this);
  257. return OK;
  258. }
  259. Error AudioDriverWASAPI::reopen() {
  260. Error err = finish_device();
  261. if (err != OK) {
  262. ERR_PRINT("WASAPI: finish_device error");
  263. } else {
  264. err = init_device();
  265. if (err != OK) {
  266. ERR_PRINT("WASAPI: init_device error");
  267. } else {
  268. start();
  269. }
  270. }
  271. return err;
  272. }
  273. int AudioDriverWASAPI::get_mix_rate() const {
  274. return mix_rate;
  275. }
  276. AudioDriver::SpeakerMode AudioDriverWASAPI::get_speaker_mode() const {
  277. return get_speaker_mode_by_total_channels(channels);
  278. }
  279. Array AudioDriverWASAPI::get_device_list() {
  280. Array list;
  281. IMMDeviceCollection *devices = NULL;
  282. IMMDeviceEnumerator *enumerator = NULL;
  283. list.push_back(String("Default"));
  284. CoInitialize(NULL);
  285. HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
  286. ERR_FAIL_COND_V(hr != S_OK, Array());
  287. hr = enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devices);
  288. ERR_FAIL_COND_V(hr != S_OK, Array());
  289. UINT count = 0;
  290. hr = devices->GetCount(&count);
  291. ERR_FAIL_COND_V(hr != S_OK, Array());
  292. for (ULONG i = 0; i < count; i++) {
  293. IMMDevice *device = NULL;
  294. hr = devices->Item(i, &device);
  295. ERR_BREAK(hr != S_OK);
  296. IPropertyStore *props = NULL;
  297. hr = device->OpenPropertyStore(STGM_READ, &props);
  298. ERR_BREAK(hr != S_OK);
  299. PROPVARIANT propvar;
  300. PropVariantInit(&propvar);
  301. hr = props->GetValue(PKEY_Device_FriendlyName, &propvar);
  302. ERR_BREAK(hr != S_OK);
  303. list.push_back(String(propvar.pwszVal));
  304. PropVariantClear(&propvar);
  305. props->Release();
  306. device->Release();
  307. }
  308. devices->Release();
  309. enumerator->Release();
  310. return list;
  311. }
  312. String AudioDriverWASAPI::get_device() {
  313. return device_name;
  314. }
  315. void AudioDriverWASAPI::set_device(String device) {
  316. new_device = device;
  317. }
  318. void AudioDriverWASAPI::write_sample(AudioDriverWASAPI *ad, BYTE *buffer, int i, int32_t sample) {
  319. if (ad->format_tag == WAVE_FORMAT_PCM) {
  320. switch (ad->bits_per_sample) {
  321. case 8:
  322. ((int8_t *)buffer)[i] = sample >> 24;
  323. break;
  324. case 16:
  325. ((int16_t *)buffer)[i] = sample >> 16;
  326. break;
  327. case 24:
  328. ((int8_t *)buffer)[i * 3 + 2] = sample >> 24;
  329. ((int8_t *)buffer)[i * 3 + 1] = sample >> 16;
  330. ((int8_t *)buffer)[i * 3 + 0] = sample >> 8;
  331. break;
  332. case 32:
  333. ((int32_t *)buffer)[i] = sample;
  334. break;
  335. }
  336. } else if (ad->format_tag == WAVE_FORMAT_IEEE_FLOAT) {
  337. ((float *)buffer)[i] = (sample >> 16) / 32768.f;
  338. } else {
  339. ERR_PRINT("WASAPI: Unknown format tag");
  340. ad->exit_thread = true;
  341. }
  342. }
  343. void AudioDriverWASAPI::thread_func(void *p_udata) {
  344. AudioDriverWASAPI *ad = (AudioDriverWASAPI *)p_udata;
  345. while (!ad->exit_thread) {
  346. if (ad->active) {
  347. ad->lock();
  348. ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw());
  349. ad->unlock();
  350. } else {
  351. for (unsigned int i = 0; i < ad->buffer_size; i++) {
  352. ad->samples_in[i] = 0;
  353. }
  354. }
  355. unsigned int left_frames = ad->buffer_frames;
  356. unsigned int buffer_idx = 0;
  357. while (left_frames > 0 && ad->audio_client) {
  358. WaitForSingleObject(ad->event, 1000);
  359. UINT32 cur_frames;
  360. HRESULT hr = ad->audio_client->GetCurrentPadding(&cur_frames);
  361. if (hr == S_OK) {
  362. // Check how much frames are available on the WASAPI buffer
  363. UINT32 avail_frames = ad->buffer_frames - cur_frames;
  364. UINT32 write_frames = avail_frames > left_frames ? left_frames : avail_frames;
  365. BYTE *buffer = NULL;
  366. hr = ad->render_client->GetBuffer(write_frames, &buffer);
  367. if (hr == S_OK) {
  368. // We're using WASAPI Shared Mode so we must convert the buffer
  369. if (ad->channels == ad->wasapi_channels) {
  370. for (unsigned int i = 0; i < write_frames * ad->channels; i++) {
  371. ad->write_sample(ad, buffer, i, ad->samples_in[buffer_idx++]);
  372. }
  373. } else {
  374. for (unsigned int i = 0; i < write_frames; i++) {
  375. for (unsigned int j = 0; j < MIN(ad->channels, ad->wasapi_channels); j++) {
  376. ad->write_sample(ad, buffer, i * ad->wasapi_channels + j, ad->samples_in[buffer_idx++]);
  377. }
  378. if (ad->wasapi_channels > ad->channels) {
  379. for (unsigned int j = ad->channels; j < ad->wasapi_channels; j++) {
  380. ad->write_sample(ad, buffer, i * ad->wasapi_channels + j, 0);
  381. }
  382. }
  383. }
  384. }
  385. hr = ad->render_client->ReleaseBuffer(write_frames, 0);
  386. if (hr != S_OK) {
  387. ERR_PRINT("WASAPI: Release buffer error");
  388. }
  389. left_frames -= write_frames;
  390. } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
  391. // Device is not valid anymore, reopen it
  392. Error err = ad->finish_device();
  393. if (err != OK) {
  394. ERR_PRINT("WASAPI: finish_device error");
  395. } else {
  396. // We reopened the device and samples_in may have resized, so invalidate the current left_frames
  397. left_frames = 0;
  398. }
  399. } else {
  400. ERR_PRINT("WASAPI: Get buffer error");
  401. ad->exit_thread = true;
  402. }
  403. } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
  404. // Device is not valid anymore, reopen it
  405. Error err = ad->finish_device();
  406. if (err != OK) {
  407. ERR_PRINT("WASAPI: finish_device error");
  408. } else {
  409. // We reopened the device and samples_in may have resized, so invalidate the current left_frames
  410. left_frames = 0;
  411. }
  412. } else {
  413. ERR_PRINT("WASAPI: GetCurrentPadding error");
  414. }
  415. }
  416. // If we're using the Default device and it changed finish it so we'll re-init the device
  417. if (ad->device_name == "Default" && default_device_changed) {
  418. Error err = ad->finish_device();
  419. if (err != OK) {
  420. ERR_PRINT("WASAPI: finish_device error");
  421. }
  422. default_device_changed = false;
  423. }
  424. // User selected a new device, finish the current one so we'll init the new device
  425. if (ad->device_name != ad->new_device) {
  426. ad->device_name = ad->new_device;
  427. Error err = ad->finish_device();
  428. if (err != OK) {
  429. ERR_PRINT("WASAPI: finish_device error");
  430. }
  431. }
  432. if (!ad->audio_client) {
  433. Error err = ad->init_device(true);
  434. if (err == OK) {
  435. ad->start();
  436. }
  437. }
  438. }
  439. ad->thread_exited = true;
  440. }
  441. void AudioDriverWASAPI::start() {
  442. if (audio_client) {
  443. HRESULT hr = audio_client->Start();
  444. if (hr != S_OK) {
  445. ERR_PRINT("WASAPI: Start failed");
  446. } else {
  447. active = true;
  448. }
  449. }
  450. }
  451. void AudioDriverWASAPI::lock() {
  452. if (mutex)
  453. mutex->lock();
  454. }
  455. void AudioDriverWASAPI::unlock() {
  456. if (mutex)
  457. mutex->unlock();
  458. }
  459. void AudioDriverWASAPI::finish() {
  460. if (thread) {
  461. exit_thread = true;
  462. Thread::wait_to_finish(thread);
  463. memdelete(thread);
  464. thread = NULL;
  465. }
  466. finish_device();
  467. if (mutex) {
  468. memdelete(mutex);
  469. mutex = NULL;
  470. }
  471. }
  472. AudioDriverWASAPI::AudioDriverWASAPI() {
  473. audio_client = NULL;
  474. render_client = NULL;
  475. mutex = NULL;
  476. thread = NULL;
  477. format_tag = 0;
  478. bits_per_sample = 0;
  479. samples_in.clear();
  480. buffer_size = 0;
  481. channels = 0;
  482. wasapi_channels = 0;
  483. mix_rate = 0;
  484. buffer_frames = 0;
  485. thread_exited = false;
  486. exit_thread = false;
  487. active = false;
  488. device_name = "Default";
  489. new_device = "Default";
  490. }
  491. #endif