audio_driver_wasapi.cpp 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  1. /**************************************************************************/
  2. /* audio_driver_wasapi.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  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 "core/config/project_settings.h"
  33. #include "core/os/os.h"
  34. #include <stdint.h> // INT32_MAX
  35. #include <functiondiscoverykeys.h>
  36. #include <wrl/client.h>
  37. using Microsoft::WRL::ComPtr;
  38. // Define IAudioClient3 if not already defined by MinGW headers
  39. #if defined __MINGW32__ || defined __MINGW64__
  40. #ifndef __IAudioClient3_FWD_DEFINED__
  41. #define __IAudioClient3_FWD_DEFINED__
  42. typedef interface IAudioClient3 IAudioClient3;
  43. #endif // __IAudioClient3_FWD_DEFINED__
  44. #ifndef __IAudioClient3_INTERFACE_DEFINED__
  45. #define __IAudioClient3_INTERFACE_DEFINED__
  46. // clang-format off
  47. MIDL_INTERFACE("7ED4EE07-8E67-4CD4-8C1A-2B7A5987AD42")
  48. IAudioClient3 : public IAudioClient2 {
  49. public:
  50. virtual HRESULT STDMETHODCALLTYPE GetSharedModeEnginePeriod(
  51. /* [annotation][in] */
  52. _In_ const WAVEFORMATEX *pFormat,
  53. /* [annotation][out] */
  54. _Out_ UINT32 *pDefaultPeriodInFrames,
  55. /* [annotation][out] */
  56. _Out_ UINT32 *pFundamentalPeriodInFrames,
  57. /* [annotation][out] */
  58. _Out_ UINT32 *pMinPeriodInFrames,
  59. /* [annotation][out] */
  60. _Out_ UINT32 *pMaxPeriodInFrames) = 0;
  61. virtual HRESULT STDMETHODCALLTYPE GetCurrentSharedModeEnginePeriod(
  62. /* [unique][annotation][out] */
  63. _Out_ WAVEFORMATEX * *ppFormat,
  64. /* [annotation][out] */
  65. _Out_ UINT32 * pCurrentPeriodInFrames) = 0;
  66. virtual HRESULT STDMETHODCALLTYPE InitializeSharedAudioStream(
  67. /* [annotation][in] */
  68. _In_ DWORD StreamFlags,
  69. /* [annotation][in] */
  70. _In_ UINT32 PeriodInFrames,
  71. /* [annotation][in] */
  72. _In_ const WAVEFORMATEX *pFormat,
  73. /* [annotation][in] */
  74. _In_opt_ LPCGUID AudioSessionGuid) = 0;
  75. };
  76. // clang-format on
  77. __CRT_UUID_DECL(IAudioClient3, 0x7ED4EE07, 0x8E67, 0x4CD4, 0x8C, 0x1A, 0x2B, 0x7A, 0x59, 0x87, 0xAD, 0x42)
  78. #endif // __IAudioClient3_INTERFACE_DEFINED__
  79. #endif // __MINGW32__ || __MINGW64__
  80. #ifndef PKEY_Device_FriendlyNameGodot
  81. #undef DEFINE_PROPERTYKEY
  82. /* clang-format off */
  83. #define DEFINE_PROPERTYKEY(id, a, b, c, d, e, f, g, h, i, j, k, l) \
  84. const PROPERTYKEY id = { { a, b, c, { d, e, f, g, h, i, j, k, } }, l };
  85. /* clang-format on */
  86. DEFINE_PROPERTYKEY(PKEY_Device_FriendlyNameGodot, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14);
  87. #endif
  88. const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
  89. const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
  90. const IID IID_IAudioClient = __uuidof(IAudioClient);
  91. const IID IID_IAudioClient3 = __uuidof(IAudioClient3);
  92. const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
  93. const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
  94. #define SAFE_RELEASE(memory) \
  95. if ((memory) != nullptr) { \
  96. (memory)->Release(); \
  97. (memory) = nullptr; \
  98. }
  99. #define REFTIMES_PER_SEC 10000000
  100. #define REFTIMES_PER_MILLISEC 10000
  101. #define CAPTURE_BUFFER_CHANNELS 2
  102. static bool default_output_device_changed = false;
  103. static bool default_input_device_changed = false;
  104. static int output_reinit_countdown = 0;
  105. static int input_reinit_countdown = 0;
  106. // Silence warning due to a COM API weirdness (GH-35194).
  107. #if defined(__GNUC__) && !defined(__clang__)
  108. #pragma GCC diagnostic push
  109. #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
  110. #endif
  111. class CMMNotificationClient : public IMMNotificationClient {
  112. LONG _cRef = 1;
  113. public:
  114. ComPtr<IMMDeviceEnumerator> enumerator = nullptr;
  115. CMMNotificationClient() {}
  116. virtual ~CMMNotificationClient() {}
  117. ULONG STDMETHODCALLTYPE AddRef() {
  118. return InterlockedIncrement(&_cRef);
  119. }
  120. ULONG STDMETHODCALLTYPE Release() {
  121. ULONG ulRef = InterlockedDecrement(&_cRef);
  122. if (0 == ulRef) {
  123. delete this;
  124. }
  125. return ulRef;
  126. }
  127. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) {
  128. if (IID_IUnknown == riid) {
  129. AddRef();
  130. *ppvInterface = (IUnknown *)this;
  131. } else if (__uuidof(IMMNotificationClient) == riid) {
  132. AddRef();
  133. *ppvInterface = (IMMNotificationClient *)this;
  134. } else {
  135. *ppvInterface = nullptr;
  136. return E_NOINTERFACE;
  137. }
  138. return S_OK;
  139. }
  140. HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId) {
  141. return S_OK;
  142. }
  143. HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId) {
  144. return S_OK;
  145. }
  146. HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState) {
  147. return S_OK;
  148. }
  149. HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId) {
  150. if (role == eConsole) {
  151. if (flow == eRender) {
  152. default_output_device_changed = true;
  153. } else if (flow == eCapture) {
  154. default_input_device_changed = true;
  155. }
  156. }
  157. return S_OK;
  158. }
  159. HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key) {
  160. return S_OK;
  161. }
  162. };
  163. #if defined(__GNUC__) && !defined(__clang__)
  164. #pragma GCC diagnostic pop
  165. #endif
  166. static CMMNotificationClient notif_client;
  167. Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_input, bool p_reinit, bool p_no_audio_client_3) {
  168. // This function can be called recursively, so clean up before starting:
  169. audio_device_finish(p_device);
  170. WAVEFORMATEX *pwfex;
  171. ComPtr<IMMDeviceEnumerator> enumerator = nullptr;
  172. ComPtr<IMMDevice> output_device = nullptr;
  173. HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
  174. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  175. if (p_device->device_name == "Default") {
  176. hr = enumerator->GetDefaultAudioEndpoint(p_input ? eCapture : eRender, eConsole, &output_device);
  177. } else {
  178. ComPtr<IMMDeviceCollection> devices = nullptr;
  179. hr = enumerator->EnumAudioEndpoints(p_input ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices);
  180. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  181. LPWSTR strId = nullptr;
  182. bool found = false;
  183. UINT count = 0;
  184. hr = devices->GetCount(&count);
  185. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  186. for (ULONG i = 0; i < count && !found; i++) {
  187. ComPtr<IMMDevice> tmp_device = nullptr;
  188. hr = devices->Item(i, &tmp_device);
  189. ERR_BREAK_MSG(hr != S_OK, "Cannot get devices item.");
  190. ComPtr<IPropertyStore> props = nullptr;
  191. hr = tmp_device->OpenPropertyStore(STGM_READ, &props);
  192. ERR_BREAK_MSG(hr != S_OK, "Cannot open property store.");
  193. PROPVARIANT propvar;
  194. PropVariantInit(&propvar);
  195. hr = props->GetValue(PKEY_Device_FriendlyNameGodot, &propvar);
  196. ERR_BREAK_MSG(hr != S_OK, "Cannot get value.");
  197. if (p_device->device_name == String(propvar.pwszVal)) {
  198. hr = tmp_device->GetId(&strId);
  199. if (unlikely(hr != S_OK)) {
  200. PropVariantClear(&propvar);
  201. ERR_PRINT("Cannot get device ID string.");
  202. break;
  203. }
  204. found = true;
  205. }
  206. PropVariantClear(&propvar);
  207. }
  208. if (found) {
  209. hr = enumerator->GetDevice(strId, &output_device);
  210. }
  211. if (strId) {
  212. CoTaskMemFree(strId);
  213. }
  214. if (output_device == nullptr) {
  215. hr = enumerator->GetDefaultAudioEndpoint(p_input ? eCapture : eRender, eConsole, &output_device);
  216. }
  217. }
  218. if (p_reinit) {
  219. // In case we're trying to re-initialize the device, prevent throwing this error on the console,
  220. // otherwise if there is currently no device available this will spam the console.
  221. if (hr != S_OK) {
  222. return ERR_CANT_OPEN;
  223. }
  224. } else {
  225. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  226. }
  227. if (notif_client.enumerator != nullptr) {
  228. notif_client.enumerator->UnregisterEndpointNotificationCallback(&notif_client);
  229. notif_client.enumerator = nullptr;
  230. }
  231. hr = enumerator->RegisterEndpointNotificationCallback(&notif_client);
  232. if (hr == S_OK) {
  233. notif_client.enumerator = enumerator;
  234. } else {
  235. ERR_PRINT("WASAPI: RegisterEndpointNotificationCallback error");
  236. }
  237. using_audio_client_3 = !p_input; // IID_IAudioClient3 is only used for adjustable output latency (not input)
  238. if (p_no_audio_client_3) {
  239. using_audio_client_3 = false;
  240. }
  241. if (using_audio_client_3) {
  242. hr = output_device->Activate(IID_IAudioClient3, CLSCTX_ALL, nullptr, (void **)&p_device->audio_client);
  243. if (hr != S_OK) {
  244. // IID_IAudioClient3 will never activate on OS versions before Windows 10.
  245. // Older Windows versions should fall back gracefully.
  246. using_audio_client_3 = false;
  247. print_verbose("WASAPI: Couldn't activate output_device with IAudioClient3 interface, falling back to IAudioClient interface");
  248. } else {
  249. print_verbose("WASAPI: Activated output_device using IAudioClient3 interface");
  250. }
  251. }
  252. if (!using_audio_client_3) {
  253. hr = output_device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void **)&p_device->audio_client);
  254. }
  255. if (p_reinit) {
  256. if (hr != S_OK) {
  257. return ERR_CANT_OPEN;
  258. }
  259. } else {
  260. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  261. }
  262. if (using_audio_client_3) {
  263. AudioClientProperties audioProps{};
  264. audioProps.cbSize = sizeof(AudioClientProperties);
  265. audioProps.bIsOffload = FALSE;
  266. audioProps.eCategory = AudioCategory_GameEffects;
  267. hr = ((IAudioClient3 *)p_device->audio_client)->SetClientProperties(&audioProps);
  268. ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_CANT_OPEN, "WASAPI: SetClientProperties failed with error 0x" + String::num_uint64(hr, 16) + ".");
  269. }
  270. hr = p_device->audio_client->GetMixFormat(&pwfex);
  271. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  272. // From this point onward, CoTaskMemFree(pwfex) must be called before returning or pwfex will leak!
  273. print_verbose("WASAPI: wFormatTag = " + itos(pwfex->wFormatTag));
  274. print_verbose("WASAPI: nChannels = " + itos(pwfex->nChannels));
  275. print_verbose("WASAPI: nSamplesPerSec = " + itos(pwfex->nSamplesPerSec));
  276. print_verbose("WASAPI: nAvgBytesPerSec = " + itos(pwfex->nAvgBytesPerSec));
  277. print_verbose("WASAPI: nBlockAlign = " + itos(pwfex->nBlockAlign));
  278. print_verbose("WASAPI: wBitsPerSample = " + itos(pwfex->wBitsPerSample));
  279. print_verbose("WASAPI: cbSize = " + itos(pwfex->cbSize));
  280. WAVEFORMATEX *closest = nullptr;
  281. hr = p_device->audio_client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, pwfex, &closest);
  282. if (hr == S_FALSE) {
  283. WARN_PRINT("WASAPI: Mix format is not supported by the output_device");
  284. if (closest) {
  285. print_verbose("WASAPI: closest->wFormatTag = " + itos(closest->wFormatTag));
  286. print_verbose("WASAPI: closest->nChannels = " + itos(closest->nChannels));
  287. print_verbose("WASAPI: closest->nSamplesPerSec = " + itos(closest->nSamplesPerSec));
  288. print_verbose("WASAPI: closest->nAvgBytesPerSec = " + itos(closest->nAvgBytesPerSec));
  289. print_verbose("WASAPI: closest->nBlockAlign = " + itos(closest->nBlockAlign));
  290. print_verbose("WASAPI: closest->wBitsPerSample = " + itos(closest->wBitsPerSample));
  291. print_verbose("WASAPI: closest->cbSize = " + itos(closest->cbSize));
  292. WARN_PRINT("WASAPI: Using closest match instead");
  293. CoTaskMemFree(pwfex);
  294. pwfex = closest;
  295. }
  296. }
  297. // Since we're using WASAPI Shared Mode we can't control any of these, we just tag along
  298. p_device->channels = pwfex->nChannels;
  299. p_device->format_tag = pwfex->wFormatTag;
  300. p_device->bits_per_sample = pwfex->wBitsPerSample;
  301. p_device->frame_size = (p_device->bits_per_sample / 8) * p_device->channels;
  302. if (p_device->format_tag == WAVE_FORMAT_EXTENSIBLE) {
  303. WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE *)pwfex;
  304. if (wfex->SubFormat == KSDATAFORMAT_SUBTYPE_PCM) {
  305. p_device->format_tag = WAVE_FORMAT_PCM;
  306. } else if (wfex->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) {
  307. p_device->format_tag = WAVE_FORMAT_IEEE_FLOAT;
  308. } else {
  309. ERR_PRINT("WASAPI: Format not supported");
  310. CoTaskMemFree(pwfex);
  311. ERR_FAIL_V(ERR_CANT_OPEN);
  312. }
  313. } else {
  314. if (p_device->format_tag != WAVE_FORMAT_PCM && p_device->format_tag != WAVE_FORMAT_IEEE_FLOAT) {
  315. ERR_PRINT("WASAPI: Format not supported");
  316. CoTaskMemFree(pwfex);
  317. ERR_FAIL_V(ERR_CANT_OPEN);
  318. }
  319. }
  320. if (!using_audio_client_3) {
  321. DWORD streamflags = 0;
  322. if ((DWORD)mix_rate != pwfex->nSamplesPerSec) {
  323. streamflags |= AUDCLNT_STREAMFLAGS_RATEADJUST;
  324. pwfex->nSamplesPerSec = mix_rate;
  325. pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nChannels * (pwfex->wBitsPerSample / 8);
  326. }
  327. hr = p_device->audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, p_input ? REFTIMES_PER_SEC : 0, 0, pwfex, nullptr);
  328. if (p_reinit) {
  329. // In case we're trying to re-initialize the device, prevent throwing this error on the console,
  330. // otherwise if there is currently no device available this will spam the console.
  331. if (hr != S_OK) {
  332. print_verbose("WASAPI: Initialize failed with error 0x" + String::num_uint64(hr, 16) + ".");
  333. CoTaskMemFree(pwfex);
  334. return ERR_CANT_OPEN;
  335. }
  336. } else {
  337. if (unlikely(hr != S_OK)) {
  338. CoTaskMemFree(pwfex);
  339. ERR_FAIL_V_MSG(ERR_CANT_OPEN, "WASAPI: Initialize failed with error 0x" + String::num_uint64(hr, 16) + ".");
  340. }
  341. }
  342. UINT32 max_frames;
  343. hr = p_device->audio_client->GetBufferSize(&max_frames);
  344. if (unlikely(hr != S_OK)) {
  345. CoTaskMemFree(pwfex);
  346. ERR_FAIL_V(ERR_CANT_OPEN);
  347. }
  348. // Due to WASAPI Shared Mode we have no control of the buffer size
  349. if (!p_input) {
  350. buffer_frames = max_frames;
  351. int64_t latency = 0;
  352. audio_output.audio_client->GetStreamLatency(&latency);
  353. // WASAPI REFERENCE_TIME units are 100 nanoseconds per unit
  354. // https://docs.microsoft.com/en-us/windows/win32/directshow/reference-time
  355. // Convert REFTIME to seconds as godot uses for latency
  356. real_latency = (float)latency / (float)REFTIMES_PER_SEC;
  357. }
  358. } else {
  359. IAudioClient3 *device_audio_client_3 = (IAudioClient3 *)p_device->audio_client;
  360. // AUDCLNT_STREAMFLAGS_RATEADJUST is an invalid flag with IAudioClient3, therefore we have to use
  361. // the closest supported mix rate supported by the audio driver.
  362. mix_rate = pwfex->nSamplesPerSec;
  363. print_verbose("WASAPI: mix_rate = " + itos(mix_rate));
  364. UINT32 default_period_frames, fundamental_period_frames, min_period_frames, max_period_frames;
  365. hr = device_audio_client_3->GetSharedModeEnginePeriod(
  366. pwfex,
  367. &default_period_frames,
  368. &fundamental_period_frames,
  369. &min_period_frames,
  370. &max_period_frames);
  371. if (hr != S_OK) {
  372. print_verbose("WASAPI: GetSharedModeEnginePeriod failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
  373. CoTaskMemFree(pwfex);
  374. return audio_device_init(p_device, p_input, p_reinit, true);
  375. }
  376. // Period frames must be an integral multiple of fundamental_period_frames or IAudioClient3 initialization will fail,
  377. // so we need to select the closest multiple to the user-specified latency.
  378. UINT32 desired_period_frames = target_latency_ms * mix_rate / 1000;
  379. UINT32 period_frames = (desired_period_frames / fundamental_period_frames) * fundamental_period_frames;
  380. if (ABS((int64_t)period_frames - (int64_t)desired_period_frames) > ABS((int64_t)(period_frames + fundamental_period_frames) - (int64_t)desired_period_frames)) {
  381. period_frames = period_frames + fundamental_period_frames;
  382. }
  383. period_frames = CLAMP(period_frames, min_period_frames, max_period_frames);
  384. print_verbose("WASAPI: fundamental_period_frames = " + itos(fundamental_period_frames));
  385. print_verbose("WASAPI: min_period_frames = " + itos(min_period_frames));
  386. print_verbose("WASAPI: max_period_frames = " + itos(max_period_frames));
  387. print_verbose("WASAPI: selected a period frame size of " + itos(period_frames));
  388. buffer_frames = period_frames;
  389. hr = device_audio_client_3->InitializeSharedAudioStream(0, period_frames, pwfex, nullptr);
  390. if (hr != S_OK) {
  391. print_verbose("WASAPI: InitializeSharedAudioStream failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
  392. CoTaskMemFree(pwfex);
  393. return audio_device_init(p_device, p_input, p_reinit, true);
  394. } else {
  395. uint32_t output_latency_in_frames;
  396. WAVEFORMATEX *current_pwfex;
  397. hr = device_audio_client_3->GetCurrentSharedModeEnginePeriod(&current_pwfex, &output_latency_in_frames);
  398. if (hr == OK) {
  399. real_latency = (float)output_latency_in_frames / (float)current_pwfex->nSamplesPerSec;
  400. CoTaskMemFree(current_pwfex);
  401. } else {
  402. print_verbose("WASAPI: GetCurrentSharedModeEnginePeriod failed with error 0x" + String::num_uint64(hr, 16) + ", falling back to IAudioClient.");
  403. CoTaskMemFree(pwfex);
  404. return audio_device_init(p_device, p_input, p_reinit, true);
  405. }
  406. }
  407. }
  408. if (p_input) {
  409. hr = p_device->audio_client->GetService(IID_IAudioCaptureClient, (void **)&p_device->capture_client);
  410. } else {
  411. hr = p_device->audio_client->GetService(IID_IAudioRenderClient, (void **)&p_device->render_client);
  412. }
  413. if (unlikely(hr != S_OK)) {
  414. CoTaskMemFree(pwfex);
  415. ERR_FAIL_V(ERR_CANT_OPEN);
  416. }
  417. // Free memory
  418. CoTaskMemFree(pwfex);
  419. return OK;
  420. }
  421. Error AudioDriverWASAPI::init_output_device(bool p_reinit) {
  422. Error err = audio_device_init(&audio_output, false, p_reinit);
  423. if (err != OK) {
  424. // We've tried to init the device, but have failed. Time to clean up.
  425. Error finish_err = finish_output_device();
  426. if (finish_err != OK) {
  427. ERR_PRINT("WASAPI: finish_output_device error after failed output audio_device_init");
  428. }
  429. return err;
  430. }
  431. switch (audio_output.channels) {
  432. case 1: // Mono
  433. case 3: // Surround 2.1
  434. case 5: // Surround 5.0
  435. case 7: // Surround 7.0
  436. // We will downmix as required.
  437. channels = audio_output.channels + 1;
  438. break;
  439. case 2: // Stereo
  440. case 4: // Surround 3.1
  441. case 6: // Surround 5.1
  442. case 8: // Surround 7.1
  443. channels = audio_output.channels;
  444. break;
  445. default:
  446. WARN_PRINT("WASAPI: Unsupported number of channels: " + itos(audio_output.channels));
  447. channels = 2;
  448. break;
  449. }
  450. // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
  451. samples_in.resize(buffer_frames * channels);
  452. input_position = 0;
  453. input_size = 0;
  454. print_verbose("WASAPI: detected " + itos(audio_output.channels) + " channels");
  455. print_verbose("WASAPI: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
  456. return OK;
  457. }
  458. Error AudioDriverWASAPI::init_input_device(bool p_reinit) {
  459. Error err = audio_device_init(&audio_input, true, p_reinit);
  460. if (err != OK) {
  461. // We've tried to init the device, but have failed. Time to clean up.
  462. Error finish_err = finish_input_device();
  463. if (finish_err != OK) {
  464. ERR_PRINT("WASAPI: finish_input_device error after failed input audio_device_init");
  465. }
  466. return err;
  467. }
  468. // Get the max frames
  469. UINT32 max_frames;
  470. HRESULT hr = audio_input.audio_client->GetBufferSize(&max_frames);
  471. ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
  472. input_buffer_init(max_frames);
  473. return OK;
  474. }
  475. Error AudioDriverWASAPI::audio_device_finish(AudioDeviceWASAPI *p_device) {
  476. if (p_device->active.is_set()) {
  477. if (p_device->audio_client) {
  478. p_device->audio_client->Stop();
  479. }
  480. p_device->active.clear();
  481. }
  482. SAFE_RELEASE(p_device->audio_client)
  483. SAFE_RELEASE(p_device->render_client)
  484. SAFE_RELEASE(p_device->capture_client)
  485. return OK;
  486. }
  487. Error AudioDriverWASAPI::finish_output_device() {
  488. return audio_device_finish(&audio_output);
  489. }
  490. Error AudioDriverWASAPI::finish_input_device() {
  491. return audio_device_finish(&audio_input);
  492. }
  493. Error AudioDriverWASAPI::init() {
  494. mix_rate = _get_configured_mix_rate();
  495. target_latency_ms = Engine::get_singleton()->get_audio_output_latency();
  496. exit_thread.clear();
  497. Error err = init_output_device();
  498. ERR_FAIL_COND_V_MSG(err != OK, err, "WASAPI: init_output_device error.");
  499. thread.start(thread_func, this);
  500. return OK;
  501. }
  502. int AudioDriverWASAPI::get_mix_rate() const {
  503. return mix_rate;
  504. }
  505. float AudioDriverWASAPI::get_latency() {
  506. return real_latency;
  507. }
  508. AudioDriver::SpeakerMode AudioDriverWASAPI::get_speaker_mode() const {
  509. return get_speaker_mode_by_total_channels(channels);
  510. }
  511. PackedStringArray AudioDriverWASAPI::audio_device_get_list(bool p_input) {
  512. PackedStringArray list;
  513. ComPtr<IMMDeviceCollection> devices = nullptr;
  514. ComPtr<IMMDeviceEnumerator> enumerator = nullptr;
  515. list.push_back(String("Default"));
  516. HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
  517. ERR_FAIL_COND_V(hr != S_OK, PackedStringArray());
  518. hr = enumerator->EnumAudioEndpoints(p_input ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices);
  519. ERR_FAIL_COND_V(hr != S_OK, PackedStringArray());
  520. UINT count = 0;
  521. hr = devices->GetCount(&count);
  522. ERR_FAIL_COND_V(hr != S_OK, PackedStringArray());
  523. for (ULONG i = 0; i < count; i++) {
  524. ComPtr<IMMDevice> output_device = nullptr;
  525. hr = devices->Item(i, &output_device);
  526. ERR_BREAK(hr != S_OK);
  527. ComPtr<IPropertyStore> props = nullptr;
  528. hr = output_device->OpenPropertyStore(STGM_READ, &props);
  529. ERR_BREAK(hr != S_OK);
  530. PROPVARIANT propvar;
  531. PropVariantInit(&propvar);
  532. hr = props->GetValue(PKEY_Device_FriendlyNameGodot, &propvar);
  533. ERR_BREAK(hr != S_OK);
  534. list.push_back(String(propvar.pwszVal));
  535. PropVariantClear(&propvar);
  536. }
  537. return list;
  538. }
  539. PackedStringArray AudioDriverWASAPI::get_output_device_list() {
  540. return audio_device_get_list(false);
  541. }
  542. String AudioDriverWASAPI::get_output_device() {
  543. lock();
  544. String name = audio_output.device_name;
  545. unlock();
  546. return name;
  547. }
  548. void AudioDriverWASAPI::set_output_device(const String &p_name) {
  549. lock();
  550. audio_output.new_device = p_name;
  551. unlock();
  552. }
  553. int32_t AudioDriverWASAPI::read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i) {
  554. if (format_tag == WAVE_FORMAT_PCM) {
  555. int32_t sample = 0;
  556. switch (bits_per_sample) {
  557. case 8:
  558. sample = int32_t(((int8_t *)buffer)[i]) << 24;
  559. break;
  560. case 16:
  561. sample = int32_t(((int16_t *)buffer)[i]) << 16;
  562. break;
  563. case 24:
  564. sample |= int32_t(((int8_t *)buffer)[i * 3 + 2]) << 24;
  565. sample |= int32_t(((int8_t *)buffer)[i * 3 + 1]) << 16;
  566. sample |= int32_t(((int8_t *)buffer)[i * 3 + 0]) << 8;
  567. break;
  568. case 32:
  569. sample = ((int32_t *)buffer)[i];
  570. break;
  571. }
  572. return sample;
  573. } else if (format_tag == WAVE_FORMAT_IEEE_FLOAT) {
  574. return int32_t(((float *)buffer)[i] * 32768.0) << 16;
  575. } else {
  576. ERR_PRINT("WASAPI: Unknown format tag");
  577. }
  578. return 0;
  579. }
  580. void AudioDriverWASAPI::write_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i, int32_t sample) {
  581. if (format_tag == WAVE_FORMAT_PCM) {
  582. switch (bits_per_sample) {
  583. case 8:
  584. ((int8_t *)buffer)[i] = sample >> 24;
  585. break;
  586. case 16:
  587. ((int16_t *)buffer)[i] = sample >> 16;
  588. break;
  589. case 24:
  590. ((int8_t *)buffer)[i * 3 + 2] = sample >> 24;
  591. ((int8_t *)buffer)[i * 3 + 1] = sample >> 16;
  592. ((int8_t *)buffer)[i * 3 + 0] = sample >> 8;
  593. break;
  594. case 32:
  595. ((int32_t *)buffer)[i] = sample;
  596. break;
  597. }
  598. } else if (format_tag == WAVE_FORMAT_IEEE_FLOAT) {
  599. ((float *)buffer)[i] = (sample >> 16) / 32768.f;
  600. } else {
  601. ERR_PRINT("WASAPI: Unknown format tag");
  602. }
  603. }
  604. void AudioDriverWASAPI::thread_func(void *p_udata) {
  605. CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
  606. AudioDriverWASAPI *ad = static_cast<AudioDriverWASAPI *>(p_udata);
  607. uint32_t avail_frames = 0;
  608. uint32_t write_ofs = 0;
  609. while (!ad->exit_thread.is_set()) {
  610. uint32_t read_frames = 0;
  611. uint32_t written_frames = 0;
  612. if (avail_frames == 0) {
  613. ad->lock();
  614. ad->start_counting_ticks();
  615. if (ad->audio_output.active.is_set()) {
  616. ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw());
  617. } else {
  618. for (int i = 0; i < ad->samples_in.size(); i++) {
  619. ad->samples_in.write[i] = 0;
  620. }
  621. }
  622. avail_frames = ad->buffer_frames;
  623. write_ofs = 0;
  624. ad->stop_counting_ticks();
  625. ad->unlock();
  626. }
  627. ad->lock();
  628. ad->start_counting_ticks();
  629. if (avail_frames > 0 && ad->audio_output.audio_client) {
  630. UINT32 buffer_size;
  631. UINT32 cur_frames;
  632. bool invalidated = false;
  633. HRESULT hr = ad->audio_output.audio_client->GetBufferSize(&buffer_size);
  634. if (hr != S_OK) {
  635. ERR_PRINT("WASAPI: GetBufferSize error");
  636. }
  637. hr = ad->audio_output.audio_client->GetCurrentPadding(&cur_frames);
  638. if (hr == S_OK) {
  639. // Check how much frames are available on the WASAPI buffer
  640. UINT32 write_frames = MIN(buffer_size - cur_frames, avail_frames);
  641. if (write_frames > 0) {
  642. BYTE *buffer = nullptr;
  643. hr = ad->audio_output.render_client->GetBuffer(write_frames, &buffer);
  644. if (hr == S_OK) {
  645. // We're using WASAPI Shared Mode so we must convert the buffer
  646. if (ad->channels == ad->audio_output.channels) {
  647. for (unsigned int i = 0; i < write_frames * ad->channels; i++) {
  648. ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i, ad->samples_in.write[write_ofs++]);
  649. }
  650. } else if (ad->channels == ad->audio_output.channels + 1) {
  651. // Pass all channels except the last two as-is, and then mix the last two
  652. // together as one channel. E.g. stereo -> mono, or 3.1 -> 2.1.
  653. unsigned int last_chan = ad->audio_output.channels - 1;
  654. for (unsigned int i = 0; i < write_frames; i++) {
  655. for (unsigned int j = 0; j < last_chan; j++) {
  656. 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++]);
  657. }
  658. int32_t l = ad->samples_in.write[write_ofs++];
  659. int32_t r = ad->samples_in.write[write_ofs++];
  660. int32_t c = (int32_t)(((int64_t)l + (int64_t)r) / 2);
  661. ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i * ad->audio_output.channels + last_chan, c);
  662. }
  663. } else {
  664. for (unsigned int i = 0; i < write_frames; i++) {
  665. for (unsigned int j = 0; j < MIN(ad->channels, ad->audio_output.channels); j++) {
  666. 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++]);
  667. }
  668. if (ad->audio_output.channels > ad->channels) {
  669. for (unsigned int j = ad->channels; j < ad->audio_output.channels; j++) {
  670. ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i * ad->audio_output.channels + j, 0);
  671. }
  672. }
  673. }
  674. }
  675. hr = ad->audio_output.render_client->ReleaseBuffer(write_frames, 0);
  676. if (hr != S_OK) {
  677. ERR_PRINT("WASAPI: Release buffer error");
  678. }
  679. avail_frames -= write_frames;
  680. written_frames += write_frames;
  681. } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
  682. // output_device is not valid anymore, reopen it
  683. Error err = ad->finish_output_device();
  684. if (err != OK) {
  685. ERR_PRINT("WASAPI: finish_output_device error");
  686. } else {
  687. // We reopened the output device and samples_in may have resized, so invalidate the current avail_frames
  688. avail_frames = 0;
  689. }
  690. } else {
  691. ERR_PRINT("WASAPI: Get buffer error");
  692. ad->exit_thread.set();
  693. }
  694. }
  695. } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
  696. invalidated = true;
  697. } else {
  698. ERR_PRINT("WASAPI: GetCurrentPadding error");
  699. }
  700. if (invalidated) {
  701. // output_device is not valid anymore
  702. WARN_PRINT("WASAPI: Current output_device invalidated, closing output_device");
  703. Error err = ad->finish_output_device();
  704. if (err != OK) {
  705. ERR_PRINT("WASAPI: finish_output_device error");
  706. }
  707. }
  708. }
  709. // If we're using the Default output device and it changed finish it so we'll re-init the output device
  710. if (ad->audio_output.device_name == "Default" && default_output_device_changed) {
  711. Error err = ad->finish_output_device();
  712. if (err != OK) {
  713. ERR_PRINT("WASAPI: finish_output_device error");
  714. }
  715. default_output_device_changed = false;
  716. }
  717. // User selected a new output device, finish the current one so we'll init the new output device
  718. if (ad->audio_output.device_name != ad->audio_output.new_device) {
  719. ad->audio_output.device_name = ad->audio_output.new_device;
  720. Error err = ad->finish_output_device();
  721. if (err != OK) {
  722. ERR_PRINT("WASAPI: finish_output_device error");
  723. }
  724. }
  725. if (!ad->audio_output.audio_client) {
  726. if (output_reinit_countdown < 1) {
  727. Error err = ad->init_output_device(true);
  728. if (err == OK) {
  729. ad->start();
  730. } else {
  731. output_reinit_countdown = 1000;
  732. }
  733. } else {
  734. output_reinit_countdown--;
  735. }
  736. avail_frames = 0;
  737. write_ofs = 0;
  738. }
  739. if (ad->audio_input.active.is_set()) {
  740. UINT32 packet_length = 0;
  741. BYTE *data;
  742. UINT32 num_frames_available;
  743. DWORD flags;
  744. HRESULT hr = ad->audio_input.capture_client->GetNextPacketSize(&packet_length);
  745. if (hr == S_OK) {
  746. while (packet_length != 0) {
  747. hr = ad->audio_input.capture_client->GetBuffer(&data, &num_frames_available, &flags, nullptr, nullptr);
  748. ERR_BREAK(hr != S_OK);
  749. // fixme: Only works for floating point atm
  750. for (UINT32 j = 0; j < num_frames_available; j++) {
  751. int32_t l, r;
  752. if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
  753. l = r = 0;
  754. } else {
  755. if (ad->audio_input.channels == 2) {
  756. l = read_sample(ad->audio_input.format_tag, ad->audio_input.bits_per_sample, data, j * 2);
  757. r = read_sample(ad->audio_input.format_tag, ad->audio_input.bits_per_sample, data, j * 2 + 1);
  758. } else if (ad->audio_input.channels == 1) {
  759. l = r = read_sample(ad->audio_input.format_tag, ad->audio_input.bits_per_sample, data, j);
  760. } else {
  761. l = r = 0;
  762. ERR_PRINT("WASAPI: unsupported channel count in microphone!");
  763. }
  764. }
  765. ad->input_buffer_write(l);
  766. ad->input_buffer_write(r);
  767. }
  768. read_frames += num_frames_available;
  769. hr = ad->audio_input.capture_client->ReleaseBuffer(num_frames_available);
  770. ERR_BREAK(hr != S_OK);
  771. hr = ad->audio_input.capture_client->GetNextPacketSize(&packet_length);
  772. ERR_BREAK(hr != S_OK);
  773. }
  774. }
  775. // If we're using the Default output device and it changed finish it so we'll re-init the output device
  776. if (ad->audio_input.device_name == "Default" && default_input_device_changed) {
  777. Error err = ad->finish_input_device();
  778. if (err != OK) {
  779. ERR_PRINT("WASAPI: finish_input_device error");
  780. }
  781. default_input_device_changed = false;
  782. }
  783. // User selected a new input device, finish the current one so we'll init the new input device
  784. if (ad->audio_input.device_name != ad->audio_input.new_device) {
  785. ad->audio_input.device_name = ad->audio_input.new_device;
  786. Error err = ad->finish_input_device();
  787. if (err != OK) {
  788. ERR_PRINT("WASAPI: finish_input_device error");
  789. }
  790. }
  791. if (!ad->audio_input.audio_client) {
  792. if (input_reinit_countdown < 1) {
  793. Error err = ad->init_input_device(true);
  794. if (err == OK) {
  795. ad->input_start();
  796. } else {
  797. input_reinit_countdown = 1000;
  798. }
  799. } else {
  800. input_reinit_countdown--;
  801. }
  802. }
  803. }
  804. ad->stop_counting_ticks();
  805. ad->unlock();
  806. // Let the thread rest a while if we haven't read or write anything
  807. if (written_frames == 0 && read_frames == 0) {
  808. OS::get_singleton()->delay_usec(1000);
  809. }
  810. }
  811. CoUninitialize();
  812. }
  813. void AudioDriverWASAPI::start() {
  814. if (audio_output.audio_client) {
  815. HRESULT hr = audio_output.audio_client->Start();
  816. if (hr != S_OK) {
  817. ERR_PRINT("WASAPI: Start failed");
  818. } else {
  819. audio_output.active.set();
  820. }
  821. }
  822. }
  823. void AudioDriverWASAPI::lock() {
  824. mutex.lock();
  825. }
  826. void AudioDriverWASAPI::unlock() {
  827. mutex.unlock();
  828. }
  829. void AudioDriverWASAPI::finish() {
  830. exit_thread.set();
  831. if (thread.is_started()) {
  832. thread.wait_to_finish();
  833. }
  834. finish_input_device();
  835. finish_output_device();
  836. }
  837. Error AudioDriverWASAPI::input_start() {
  838. Error err = init_input_device();
  839. if (err != OK) {
  840. ERR_PRINT("WASAPI: init_input_device error");
  841. return err;
  842. }
  843. if (audio_input.active.is_set()) {
  844. return FAILED;
  845. }
  846. audio_input.audio_client->Start();
  847. audio_input.active.set();
  848. return OK;
  849. }
  850. Error AudioDriverWASAPI::input_stop() {
  851. if (audio_input.active.is_set()) {
  852. audio_input.audio_client->Stop();
  853. audio_input.active.clear();
  854. return OK;
  855. }
  856. return FAILED;
  857. }
  858. PackedStringArray AudioDriverWASAPI::get_input_device_list() {
  859. return audio_device_get_list(true);
  860. }
  861. String AudioDriverWASAPI::get_input_device() {
  862. lock();
  863. String name = audio_input.device_name;
  864. unlock();
  865. return name;
  866. }
  867. void AudioDriverWASAPI::set_input_device(const String &p_name) {
  868. lock();
  869. audio_input.new_device = p_name;
  870. unlock();
  871. }
  872. AudioDriverWASAPI::AudioDriverWASAPI() {
  873. samples_in.clear();
  874. }
  875. #endif // WASAPI_ENABLED