From af2dbbcb5343ea253c764e2d660ec8713b879c65 Mon Sep 17 00:00:00 2001
From: L zard <[EMAIL REDACTED]>
Date: Fri, 8 Nov 2024 15:23:52 +0100
Subject: [PATCH] Merge SDL_wasapi_win32 into SDL_wasapi
---
VisualC-GDK/SDL/SDL.vcxproj | 1 -
VisualC-GDK/SDL/SDL.vcxproj.filters | 1 -
VisualC/SDL/SDL.vcxproj | 1 -
VisualC/SDL/SDL.vcxproj.filters | 3 -
src/audio/wasapi/SDL_wasapi.c | 141 ++++++++++++++++++--
src/audio/wasapi/SDL_wasapi.h | 11 --
src/audio/wasapi/SDL_wasapi_win32.c | 200 ----------------------------
7 files changed, 130 insertions(+), 228 deletions(-)
delete mode 100644 src/audio/wasapi/SDL_wasapi_win32.c
diff --git a/VisualC-GDK/SDL/SDL.vcxproj b/VisualC-GDK/SDL/SDL.vcxproj
index a89e2bfecff3e..008af3dff8026 100644
--- a/VisualC-GDK/SDL/SDL.vcxproj
+++ b/VisualC-GDK/SDL/SDL.vcxproj
@@ -631,7 +631,6 @@
<ClCompile Include="..\..\src\audio\SDL_mixer.c" />
<ClCompile Include="..\..\src\audio\SDL_wave.c" />
<ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
- <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi_win32.c" />
<ClCompile Include="..\..\src\core\SDL_core_unsupported.c" />
<ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
<ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />
diff --git a/VisualC-GDK/SDL/SDL.vcxproj.filters b/VisualC-GDK/SDL/SDL.vcxproj.filters
index 3453223eb7b62..230c95d2c22c6 100644
--- a/VisualC-GDK/SDL/SDL.vcxproj.filters
+++ b/VisualC-GDK/SDL/SDL.vcxproj.filters
@@ -26,7 +26,6 @@
<ClCompile Include="..\..\src\audio\SDL_mixer.c" />
<ClCompile Include="..\..\src\audio\SDL_wave.c" />
<ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
- <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi_win32.c" />
<ClCompile Include="..\..\src\core\SDL_core_unsupported.c" />
<ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
<ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />
diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj
index 171a6229aae53..306a883d04d62 100644
--- a/VisualC/SDL/SDL.vcxproj
+++ b/VisualC/SDL/SDL.vcxproj
@@ -528,7 +528,6 @@
<ClCompile Include="..\..\src\audio\SDL_mixer.c" />
<ClCompile Include="..\..\src\audio\SDL_wave.c" />
<ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
- <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi_win32.c" />
<ClCompile Include="..\..\src\core\SDL_core_unsupported.c" />
<ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
<ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />
diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters
index a9c808c71dd4a..aa86194fabc24 100644
--- a/VisualC/SDL/SDL.vcxproj.filters
+++ b/VisualC/SDL/SDL.vcxproj.filters
@@ -1133,9 +1133,6 @@
<ClCompile Include="..\..\src\audio\dummy\SDL_dummyaudio.c">
<Filter>audio\dummy</Filter>
</ClCompile>
- <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi_win32.c">
- <Filter>audio\wasapi</Filter>
- </ClCompile>
<ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c">
<Filter>audio\wasapi</Filter>
</ClCompile>
diff --git a/src/audio/wasapi/SDL_wasapi.c b/src/audio/wasapi/SDL_wasapi.c
index e5e4f48728355..a6f1577455935 100644
--- a/src/audio/wasapi/SDL_wasapi.c
+++ b/src/audio/wasapi/SDL_wasapi.c
@@ -43,13 +43,22 @@
#define AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000
#endif
+// handle to Avrt.dll--Vista and later!--for flagging the callback thread as "Pro Audio" (low latency).
+static HMODULE libavrt = NULL;
+typedef HANDLE(WINAPI *pfnAvSetMmThreadCharacteristicsW)(LPCWSTR, LPDWORD);
+typedef BOOL(WINAPI *pfnAvRevertMmThreadCharacteristics)(HANDLE);
+static pfnAvSetMmThreadCharacteristicsW pAvSetMmThreadCharacteristicsW = NULL;
+static pfnAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL;
+
// Some GUIDs we need to know without linking to libraries that aren't available before Vista.
static const IID SDL_IID_IAudioRenderClient = { 0xf294acfc, 0x3146, 0x4483, { 0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2 } };
static const IID SDL_IID_IAudioCaptureClient = { 0xc8adbd64, 0xe71e, 0x48a0, { 0xa4, 0xde, 0x18, 0x5c, 0x39, 0x5c, 0xd3, 0x17 } };
+static const IID SDL_IID_IAudioClient = { 0x1cb9ad4c, 0xdbfa, 0x4c32, { 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2 } };
#ifdef __IAudioClient3_INTERFACE_DEFINED__
static const IID SDL_IID_IAudioClient3 = { 0x7ed4ee07, 0x8e67, 0x4cd4, { 0x8c, 0x1a, 0x2b, 0x7a, 0x59, 0x87, 0xad, 0x42 } };
#endif //
+static bool immdevice_initialized = false;
// WASAPI is _really_ particular about various things happening on the same thread, for COM and such,
// so we proxy various stuff to a single background thread to manage.
@@ -155,15 +164,83 @@ bool WASAPI_ProxyToManagementThread(ManagementThreadTask task, void *userdata, b
return true; // successfully added (and possibly executed)!
}
+static bool mgmtthrtask_AudioDeviceDisconnected(void *userdata)
+{
+ SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
+ SDL_AudioDeviceDisconnected(device);
+ UnrefPhysicalAudioDevice(device); // make sure this lived until the task completes.
+ return true;
+}
+
+static void AudioDeviceDisconnected(SDL_AudioDevice *device)
+{
+ // don't wait on this, IMMDevice's own thread needs to return or everything will deadlock.
+ if (device) {
+ RefPhysicalAudioDevice(device); // make sure this lives until the task completes.
+ WASAPI_ProxyToManagementThread(mgmtthrtask_AudioDeviceDisconnected, device, NULL);
+ }
+}
+
+static bool mgmtthrtask_DefaultAudioDeviceChanged(void *userdata)
+{
+ SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
+ SDL_DefaultAudioDeviceChanged(device);
+ UnrefPhysicalAudioDevice(device); // make sure this lived until the task completes.
+ return true;
+}
+
+static void DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device)
+{
+ // don't wait on this, IMMDevice's own thread needs to return or everything will deadlock.
+ if (new_default_device) {
+ RefPhysicalAudioDevice(new_default_device); // make sure this lives until the task completes.
+ WASAPI_ProxyToManagementThread(mgmtthrtask_DefaultAudioDeviceChanged, new_default_device, NULL);
+ }
+}
+
+static void StopWasapiHotplug(void)
+{
+ if (immdevice_initialized) {
+ SDL_IMMDevice_Quit();
+ immdevice_initialized = false;
+ }
+}
+
+static void Deinit(void)
+{
+ if (libavrt) {
+ FreeLibrary(libavrt);
+ libavrt = NULL;
+ }
+
+ pAvSetMmThreadCharacteristicsW = NULL;
+ pAvRevertMmThreadCharacteristics = NULL;
+
+ StopWasapiHotplug();
+
+ WIN_CoUninitialize();
+}
+
static bool ManagementThreadPrepare(void)
{
- if (!WASAPI_PlatformInit()) {
- return false;
+ const SDL_IMMDevice_callbacks callbacks = { AudioDeviceDisconnected, DefaultAudioDeviceChanged };
+ if (FAILED(WIN_CoInitialize())) {
+ return SDL_SetError("CoInitialize() failed");
+ } else if (!SDL_IMMDevice_Init(&callbacks)) {
+ return false; // Error string is set by SDL_IMMDevice_Init
+ }
+
+ immdevice_initialized = true;
+
+ libavrt = LoadLibrary(TEXT("avrt.dll")); // this library is available in Vista and later. No WinXP, so have to LoadLibrary to use it for now!
+ if (libavrt) {
+ pAvSetMmThreadCharacteristicsW = (pfnAvSetMmThreadCharacteristicsW)GetProcAddress(libavrt, "AvSetMmThreadCharacteristicsW");
+ pAvRevertMmThreadCharacteristics = (pfnAvRevertMmThreadCharacteristics)GetProcAddress(libavrt, "AvRevertMmThreadCharacteristics");
}
ManagementThreadLock = SDL_CreateMutex();
if (!ManagementThreadLock) {
- WASAPI_PlatformDeinit();
+ Deinit();
return false;
}
@@ -171,7 +248,7 @@ static bool ManagementThreadPrepare(void)
if (!ManagementThreadCondition) {
SDL_DestroyMutex(ManagementThreadLock);
ManagementThreadLock = NULL;
- WASAPI_PlatformDeinit();
+ Deinit();
return false;
}
@@ -197,7 +274,7 @@ static int ManagementThreadEntry(void *userdata)
SDL_SignalSemaphore(data->ready_sem); // unblock calling thread.
ManagementThreadMainloop();
- WASAPI_PlatformDeinit();
+ Deinit();
return 0;
}
@@ -260,7 +337,7 @@ typedef struct
static bool mgmtthrtask_DetectDevices(void *userdata)
{
mgmtthrtask_DetectDevicesData *data = (mgmtthrtask_DetectDevicesData *)userdata;
- WASAPI_EnumerateEndpoints(data->default_playback, data->default_recording);
+ SDL_IMMDevice_EnumerateEndpoints(data->default_playback, data->default_recording);
return true;
}
@@ -373,7 +450,29 @@ static void ResetWasapiDevice(SDL_AudioDevice *device)
static bool mgmtthrtask_ActivateDevice(void *userdata)
{
- return WASAPI_ActivateDevice((SDL_AudioDevice *)userdata);
+ SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
+
+ IMMDevice *immdevice = NULL;
+ if (!SDL_IMMDevice_Get(device, &immdevice, device->recording)) {
+ device->hidden->client = NULL;
+ return false; // This is already set by SDL_IMMDevice_Get
+ }
+
+ // this is _not_ async in standard win32, yay!
+ HRESULT ret = IMMDevice_Activate(immdevice, &SDL_IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&device->hidden->client);
+ IMMDevice_Release(immdevice);
+
+ if (FAILED(ret)) {
+ SDL_assert(device->hidden->client == NULL);
+ return WIN_SetErrorFromHRESULT("WASAPI can't activate audio endpoint", ret);
+ }
+
+ SDL_assert(device->hidden->client != NULL);
+ if (!WASAPI_PrepDevice(device)) { // not async, fire it right away.
+ return false;
+ }
+
+ return true; // good to go.
}
static bool ActivateWasapiDevice(SDL_AudioDevice *device)
@@ -768,17 +867,37 @@ static bool WASAPI_OpenDevice(SDL_AudioDevice *device)
static void WASAPI_ThreadInit(SDL_AudioDevice *device)
{
- WASAPI_PlatformThreadInit(device);
+ // this thread uses COM.
+ if (SUCCEEDED(WIN_CoInitialize())) { // can't report errors, hope it worked!
+ device->hidden->coinitialized = true;
+ }
+
+ // Set this thread to very high "Pro Audio" priority.
+ if (pAvSetMmThreadCharacteristicsW) {
+ DWORD idx = 0;
+ device->hidden->task = pAvSetMmThreadCharacteristicsW(L"Pro Audio", &idx);
+ } else {
+ SDL_SetCurrentThreadPriority(device->recording ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL);
+ }
}
static void WASAPI_ThreadDeinit(SDL_AudioDevice *device)
{
- WASAPI_PlatformThreadDeinit(device);
+ // Set this thread back to normal priority.
+ if (device->hidden->task && pAvRevertMmThreadCharacteristics) {
+ pAvRevertMmThreadCharacteristics(device->hidden->task);
+ device->hidden->task = NULL;
+ }
+
+ if (device->hidden->coinitialized) {
+ WIN_CoUninitialize();
+ device->hidden->coinitialized = false;
+ }
}
static bool mgmtthrtask_FreeDeviceHandle(void *userdata)
{
- WASAPI_PlatformFreeDeviceHandle((SDL_AudioDevice *)userdata);
+ SDL_IMMDevice_FreeDeviceHandle((SDL_AudioDevice *) userdata);
return true;
}
@@ -790,7 +909,7 @@ static void WASAPI_FreeDeviceHandle(SDL_AudioDevice *device)
static bool mgmtthrtask_DeinitializeStart(void *userdata)
{
- WASAPI_PlatformDeinitializeStart();
+ StopWasapiHotplug();
return true;
}
diff --git a/src/audio/wasapi/SDL_wasapi.h b/src/audio/wasapi/SDL_wasapi.h
index 3d4744cf19319..6c5f45f42ef6f 100644
--- a/src/audio/wasapi/SDL_wasapi.h
+++ b/src/audio/wasapi/SDL_wasapi.h
@@ -53,17 +53,6 @@ void WASAPI_DisconnectDevice(SDL_AudioDevice *device); // don't hold the device
typedef bool (*ManagementThreadTask)(void *userdata);
bool WASAPI_ProxyToManagementThread(ManagementThreadTask task, void *userdata, bool *wait_until_complete);
-// These are functions that are (were...?) implemented differently for various Windows versions.
-// UNLESS OTHERWISE NOTED THESE ALL HAPPEN ON THE MANAGEMENT THREAD.
-bool WASAPI_PlatformInit(void);
-void WASAPI_PlatformDeinit(void);
-void WASAPI_PlatformDeinitializeStart(void);
-void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording);
-bool WASAPI_ActivateDevice(SDL_AudioDevice *device);
-void WASAPI_PlatformThreadInit(SDL_AudioDevice *device); // this happens on the audio device thread, not the management thread.
-void WASAPI_PlatformThreadDeinit(SDL_AudioDevice *device); // this happens on the audio device thread, not the management thread.
-void WASAPI_PlatformFreeDeviceHandle(SDL_AudioDevice *device);
-
#ifdef __cplusplus
}
#endif
diff --git a/src/audio/wasapi/SDL_wasapi_win32.c b/src/audio/wasapi/SDL_wasapi_win32.c
deleted file mode 100644
index 5ef776d43e1ba..0000000000000
--- a/src/audio/wasapi/SDL_wasapi_win32.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-#include "SDL_internal.h"
-
-/* !!! FIXME: merge this all into SDL_wasapi.c, now that WinRT is gone.
- This is code that Windows uses to talk to WASAPI-related system APIs.
- This is for non-WinRT desktop apps. The C++/CX implementation of these
- functions, exclusive to WinRT, are in SDL_wasapi_winrt.cpp.
- The code in SDL_wasapi.c is used by both standard Windows and WinRT builds
- to deal with audio and calls into these functions. */
-
-#if defined(SDL_AUDIO_DRIVER_WASAPI)
-
-#include "../../core/windows/SDL_windows.h"
-#include "../../core/windows/SDL_immdevice.h"
-#include "../SDL_sysaudio.h"
-
-#include <audioclient.h>
-
-#include "SDL_wasapi.h"
-
-// handle to Avrt.dll--Vista and later!--for flagging the callback thread as "Pro Audio" (low latency).
-static HMODULE libavrt = NULL;
-typedef HANDLE(WINAPI *pfnAvSetMmThreadCharacteristicsW)(LPCWSTR, LPDWORD);
-typedef BOOL(WINAPI *pfnAvRevertMmThreadCharacteristics)(HANDLE);
-static pfnAvSetMmThreadCharacteristicsW pAvSetMmThreadCharacteristicsW = NULL;
-static pfnAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL;
-
-static bool immdevice_initialized = false;
-
-// Some GUIDs we need to know without linking to libraries that aren't available before Vista.
-static const IID SDL_IID_IAudioClient = { 0x1cb9ad4c, 0xdbfa, 0x4c32, { 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2 } };
-
-static bool mgmtthrtask_AudioDeviceDisconnected(void *userdata)
-{
- SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
- SDL_AudioDeviceDisconnected(device);
- UnrefPhysicalAudioDevice(device); // make sure this lived until the task completes.
- return true;
-}
-
-static void WASAPI_AudioDeviceDisconnected(SDL_AudioDevice *device)
-{
- // don't wait on this, IMMDevice's own thread needs to return or everything will deadlock.
- if (device) {
- RefPhysicalAudioDevice(device); // make sure this lives until the task completes.
- WASAPI_ProxyToManagementThread(mgmtthrtask_AudioDeviceDisconnected, device, NULL);
- }
-}
-
-static bool mgmtthrtask_DefaultAudioDeviceChanged(void *userdata)
-{
- SDL_AudioDevice *device = (SDL_AudioDevice *) userdata;
- SDL_DefaultAudioDeviceChanged(device);
- UnrefPhysicalAudioDevice(device); // make sure this lived until the task completes.
- return true;
-}
-
-static void WASAPI_DefaultAudioDeviceChanged(SDL_AudioDevice *new_default_device)
-{
- // don't wait on this, IMMDevice's own thread needs to return or everything will deadlock.
- if (new_default_device) {
- RefPhysicalAudioDevice(new_default_device); // make sure this lives until the task completes.
- WASAPI_ProxyToManagementThread(mgmtthrtask_DefaultAudioDeviceChanged, new_default_device, NULL);
- }
-}
-
-bool WASAPI_PlatformInit(void)
-{
- const SDL_IMMDevice_callbacks callbacks = { WASAPI_AudioDeviceDisconnected, WASAPI_DefaultAudioDeviceChanged };
- if (FAILED(WIN_CoInitialize())) {
- return SDL_SetError("CoInitialize() failed");
- } else if (!SDL_IMMDevice_Init(&callbacks)) {
- return false; // Error string is set by SDL_IMMDevice_Init
- }
-
- immdevice_initialized = true;
-
- libavrt = LoadLibrary(TEXT("avrt.dll")); // this library is available in Vista and later. No WinXP, so have to LoadLibrary to use it for now!
- if (libavrt) {
- pAvSetMmThreadCharacteristicsW = (pfnAvSetMmThreadCharacteristicsW)GetProcAddress(libavrt, "AvSetMmThreadCharacteristicsW");
- pAvRevertMmThreadCharacteristics = (pfnAvRevertMmThreadCharacteristics)GetProcAddress(libavrt, "AvRevertMmThreadCharacteristics");
- }
-
- return true;
-}
-
-static void StopWasapiHotplug(void)
-{
- if (immdevice_initialized) {
- SDL_IMMDevice_Quit();
- immdevice_initialized = false;
- }
-}
-
-void WASAPI_PlatformDeinit(void)
-{
- if (libavrt) {
- FreeLibrary(libavrt);
- libavrt = NULL;
- }
-
- pAvSetMmThreadCharacteristicsW = NULL;
- pAvRevertMmThreadCharacteristics = NULL;
-
- StopWasapiHotplug();
-
- WIN_CoUninitialize();
-}
-
-void WASAPI_PlatformDeinitializeStart(void)
-{
- StopWasapiHotplug();
-}
-
-void WASAPI_PlatformThreadInit(SDL_AudioDevice *device)
-{
- // this thread uses COM.
- if (SUCCEEDED(WIN_CoInitialize())) { // can't report errors, hope it worked!
- device->hidden->coinitialized = true;
- }
-
- // Set this thread to very high "Pro Audio" priority.
- if (pAvSetMmThreadCharacteristicsW) {
- DWORD idx = 0;
- device->hidden->task = pAvSetMmThreadCharacteristicsW(L"Pro Audio", &idx);
- } else {
- SDL_SetCurrentThreadPriority(device->recording ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL);
- }
-
-}
-
-void WASAPI_PlatformThreadDeinit(SDL_AudioDevice *device)
-{
- // Set this thread back to normal priority.
- if (device->hidden->task && pAvRevertMmThreadCharacteristics) {
- pAvRevertMmThreadCharacteristics(device->hidden->task);
- device->hidden->task = NULL;
- }
-
- if (device->hidden->coinitialized) {
- WIN_CoUninitialize();
- device->hidden->coinitialized = false;
- }
-}
-
-bool WASAPI_ActivateDevice(SDL_AudioDevice *device)
-{
- IMMDevice *immdevice = NULL;
- if (!SDL_IMMDevice_Get(device, &immdevice, device->recording)) {
- device->hidden->client = NULL;
- return false; // This is already set by SDL_IMMDevice_Get
- }
-
- // this is _not_ async in standard win32, yay!
- HRESULT ret = IMMDevice_Activate(immdevice, &SDL_IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&device->hidden->client);
- IMMDevice_Release(immdevice);
-
- if (FAILED(ret)) {
- SDL_assert(device->hidden->client == NULL);
- return WIN_SetErrorFromHRESULT("WASAPI can't activate audio endpoint", ret);
- }
-
- SDL_assert(device->hidden->client != NULL);
- if (!WASAPI_PrepDevice(device)) { // not async, fire it right away.
- return false;
- }
-
- return true; // good to go.
-}
-
-void WASAPI_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
-{
- SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording);
-}
-
-void WASAPI_PlatformFreeDeviceHandle(SDL_AudioDevice *device)
-{
- SDL_IMMDevice_FreeDeviceHandle(device);
-}
-
-#endif // SDL_AUDIO_DRIVER_WASAPI