mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-22 00:06:59 +02:00
WASAPI: Remove old unused code.
This commit is contained in:
+11
-281
@@ -21951,41 +21951,8 @@ static MA_INLINE ma_client_notification_wasapi ma_client_notification_wasapi_ini
|
||||
}
|
||||
|
||||
|
||||
/* WASAPI specific structure for some commands which must run on a common thread due to bugs in WASAPI. */
|
||||
typedef struct
|
||||
{
|
||||
int code;
|
||||
ma_event* pEvent; /* This will be signalled when the event is complete. */
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int _unused;
|
||||
} quit;
|
||||
struct
|
||||
{
|
||||
ma_device_type deviceType;
|
||||
ma_IAudioClient* pAudioClient;
|
||||
void** ppAudioClientService;
|
||||
ma_result* pResult; /* The result from creating the audio client service. */
|
||||
} createAudioClient;
|
||||
struct
|
||||
{
|
||||
ma_device* pDevice;
|
||||
ma_device_type deviceType;
|
||||
} releaseAudioClient;
|
||||
} data;
|
||||
} ma_context_command__wasapi;
|
||||
|
||||
|
||||
typedef struct ma_context_state_wasapi
|
||||
{
|
||||
ma_thread commandThread;
|
||||
ma_mutex commandLock;
|
||||
ma_semaphore commandSem;
|
||||
ma_uint32 commandIndex;
|
||||
ma_uint32 commandCount;
|
||||
ma_context_command__wasapi commands[4];
|
||||
ma_handle hAvrt;
|
||||
MA_PFN_AvSetMmThreadCharacteristicsA AvSetMmThreadCharacteristicsA;
|
||||
MA_PFN_AvRevertMmThreadCharacteristics AvRevertMmThreadCharacteristics;
|
||||
@@ -22436,192 +22403,21 @@ typedef ma_IUnknown ma_WASAPIDeviceInterface;
|
||||
#endif
|
||||
|
||||
|
||||
#define MA_CONTEXT_COMMAND_QUIT__WASAPI 1
|
||||
#define MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI 2
|
||||
#define MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI 3
|
||||
|
||||
static ma_context_command__wasapi ma_context_init_command__wasapi(int code)
|
||||
static ma_result ma_device_create_IAudioClient_service__wasapi(ma_context* pContext, ma_device_type deviceType, ma_IAudioClient* pAudioClient, void** ppAudioClientService)
|
||||
{
|
||||
ma_context_command__wasapi cmd;
|
||||
|
||||
MA_ZERO_OBJECT(&cmd);
|
||||
cmd.code = code;
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
static ma_result ma_context_post_command__wasapi(ma_context* pContext, const ma_context_command__wasapi* pCmd)
|
||||
{
|
||||
/* For now we are doing everything synchronously, but I might relax this later if the need arises. */
|
||||
ma_context_state_wasapi* pContextStateWASAPI = ma_context_get_backend_state__wasapi(pContext);
|
||||
ma_result result;
|
||||
ma_bool32 isUsingLocalEvent = MA_FALSE;
|
||||
ma_event localEvent;
|
||||
|
||||
MA_ASSERT(pContext != NULL);
|
||||
MA_ASSERT(pCmd != NULL);
|
||||
(void)pContext;
|
||||
|
||||
if (pCmd->pEvent == NULL) {
|
||||
isUsingLocalEvent = MA_TRUE;
|
||||
|
||||
result = ma_event_init(&localEvent);
|
||||
if (result != MA_SUCCESS) {
|
||||
return result; /* Failed to create the event for this command. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Here is where we add the command to the list. If there's not enough room we'll spin until there is. */
|
||||
ma_mutex_lock(&pContextStateWASAPI->commandLock);
|
||||
{
|
||||
ma_uint32 index;
|
||||
|
||||
/* Spin until we've got some space available. */
|
||||
while (pContextStateWASAPI->commandCount == ma_countof(pContextStateWASAPI->commands)) {
|
||||
ma_yield();
|
||||
}
|
||||
|
||||
/* Space is now available. Can safely add to the list. */
|
||||
index = (pContextStateWASAPI->commandIndex + pContextStateWASAPI->commandCount) % ma_countof(pContextStateWASAPI->commands);
|
||||
pContextStateWASAPI->commands[index] = *pCmd;
|
||||
pContextStateWASAPI->commands[index].pEvent = &localEvent;
|
||||
pContextStateWASAPI->commandCount += 1;
|
||||
|
||||
/* Now that the command has been added, release the semaphore so ma_context_next_command__wasapi() can return. */
|
||||
ma_semaphore_release(&pContextStateWASAPI->commandSem);
|
||||
}
|
||||
ma_mutex_unlock(&pContextStateWASAPI->commandLock);
|
||||
|
||||
if (isUsingLocalEvent) {
|
||||
ma_event_wait(&localEvent);
|
||||
ma_event_uninit(&localEvent);
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
|
||||
static ma_result ma_context_next_command__wasapi(ma_context_state_wasapi* pContextStateWASAPI, ma_context_command__wasapi* pCmd)
|
||||
{
|
||||
ma_result result = MA_SUCCESS;
|
||||
|
||||
MA_ASSERT(pCmd != NULL);
|
||||
|
||||
result = ma_semaphore_wait(&pContextStateWASAPI->commandSem);
|
||||
if (result == MA_SUCCESS) {
|
||||
ma_mutex_lock(&pContextStateWASAPI->commandLock);
|
||||
{
|
||||
*pCmd = pContextStateWASAPI->commands[pContextStateWASAPI->commandIndex];
|
||||
pContextStateWASAPI->commandIndex = (pContextStateWASAPI->commandIndex + 1) % ma_countof(pContextStateWASAPI->commands);
|
||||
pContextStateWASAPI->commandCount -= 1;
|
||||
}
|
||||
ma_mutex_unlock(&pContextStateWASAPI->commandLock);
|
||||
if (deviceType == ma_device_type_playback) {
|
||||
result = ma_result_from_HRESULT(ma_IAudioClient_GetService(pAudioClient, &MA_IID_IAudioRenderClient, ppAudioClientService));
|
||||
} else {
|
||||
result = ma_result_from_HRESULT(ma_IAudioClient_GetService(pAudioClient, &MA_IID_IAudioCaptureClient, ppAudioClientService));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ma_thread_result MA_THREADCALL ma_context_command_thread__wasapi(void* pUserData)
|
||||
{
|
||||
ma_result result;
|
||||
ma_context_state_wasapi* pContextStateWASAPI = (ma_context_state_wasapi*)pUserData;
|
||||
MA_ASSERT(pContextStateWASAPI != NULL);
|
||||
|
||||
for (;;) {
|
||||
ma_context_command__wasapi cmd;
|
||||
result = ma_context_next_command__wasapi(pContextStateWASAPI, &cmd);
|
||||
if (result != MA_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cmd.code)
|
||||
{
|
||||
case MA_CONTEXT_COMMAND_QUIT__WASAPI:
|
||||
{
|
||||
/* Do nothing. Handled after the switch. */
|
||||
} break;
|
||||
|
||||
case MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI:
|
||||
{
|
||||
if (cmd.data.createAudioClient.deviceType == ma_device_type_playback) {
|
||||
*cmd.data.createAudioClient.pResult = ma_result_from_HRESULT(ma_IAudioClient_GetService(cmd.data.createAudioClient.pAudioClient, &MA_IID_IAudioRenderClient, cmd.data.createAudioClient.ppAudioClientService));
|
||||
} else {
|
||||
*cmd.data.createAudioClient.pResult = ma_result_from_HRESULT(ma_IAudioClient_GetService(cmd.data.createAudioClient.pAudioClient, &MA_IID_IAudioCaptureClient, cmd.data.createAudioClient.ppAudioClientService));
|
||||
}
|
||||
} break;
|
||||
|
||||
case MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI:
|
||||
{
|
||||
ma_device* pDevice = cmd.data.releaseAudioClient.pDevice;
|
||||
ma_device_state_wasapi* pDeviceStateWASAPI = ma_device_get_backend_state__wasapi(pDevice);
|
||||
|
||||
if (cmd.data.releaseAudioClient.deviceType == ma_device_type_playback) {
|
||||
if (pDeviceStateWASAPI->pAudioClientPlayback != NULL) {
|
||||
ma_IAudioClient_Release(pDeviceStateWASAPI->pAudioClientPlayback);
|
||||
pDeviceStateWASAPI->pAudioClientPlayback = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd.data.releaseAudioClient.deviceType == ma_device_type_capture) {
|
||||
if (pDeviceStateWASAPI->pAudioClientCapture != NULL) {
|
||||
ma_IAudioClient_Release(pDeviceStateWASAPI->pAudioClientCapture);
|
||||
pDeviceStateWASAPI->pAudioClientCapture = NULL;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
{
|
||||
/* Unknown command. Ignore it, but trigger an assert in debug mode so we're aware of it. */
|
||||
MA_ASSERT(MA_FALSE);
|
||||
} break;
|
||||
}
|
||||
|
||||
if (cmd.pEvent != NULL) {
|
||||
ma_event_signal(cmd.pEvent);
|
||||
}
|
||||
|
||||
if (cmd.code == MA_CONTEXT_COMMAND_QUIT__WASAPI) {
|
||||
break; /* Received a quit message. Get out of here. */
|
||||
}
|
||||
}
|
||||
|
||||
return (ma_thread_result)0;
|
||||
}
|
||||
|
||||
static ma_result ma_device_create_IAudioClient_service__wasapi(ma_context* pContext, ma_device_type deviceType, ma_IAudioClient* pAudioClient, void** ppAudioClientService)
|
||||
{
|
||||
ma_result result;
|
||||
ma_result cmdResult;
|
||||
ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_CREATE_IAUDIOCLIENT__WASAPI);
|
||||
cmd.data.createAudioClient.deviceType = deviceType;
|
||||
cmd.data.createAudioClient.pAudioClient = pAudioClient;
|
||||
cmd.data.createAudioClient.ppAudioClientService = ppAudioClientService;
|
||||
cmd.data.createAudioClient.pResult = &cmdResult; /* Declared locally, but won't be dereferenced after this function returns since execution of the command will wait here. */
|
||||
|
||||
result = ma_context_post_command__wasapi(pContext, &cmd); /* This will not return until the command has actually been run. */
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return *cmd.data.createAudioClient.pResult;
|
||||
}
|
||||
|
||||
#if 0 /* Not used at the moment, but leaving here for future use. */
|
||||
static ma_result ma_device_release_IAudioClient_service__wasapi(ma_device* pDevice, ma_device_type deviceType)
|
||||
{
|
||||
ma_result result;
|
||||
ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI);
|
||||
cmd.data.releaseAudioClient.pDevice = pDevice;
|
||||
cmd.data.releaseAudioClient.deviceType = deviceType;
|
||||
|
||||
result = ma_context_post_command__wasapi(pDevice->pContext, &cmd); /* This will not return until the command has actually been run. */
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return MA_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void ma_add_native_data_format_to_device_info_from_WAVEFORMATEX(const MA_WAVEFORMATEX* pWF, ma_share_mode shareMode, ma_device_info* pInfo)
|
||||
{
|
||||
@@ -23363,55 +23159,6 @@ static ma_result ma_context_init__wasapi(ma_context* pContext, const void* pCont
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Annoyingly, WASAPI does not allow you to release an IAudioClient object from a different thread
|
||||
than the one that retrieved it with GetService(). This can result in a deadlock in two
|
||||
situations:
|
||||
|
||||
1) When calling ma_device_uninit() from a different thread to ma_device_init(); and
|
||||
2) When uninitializing and reinitializing the internal IAudioClient object in response to
|
||||
automatic stream routing.
|
||||
|
||||
We could define ma_device_uninit() such that it must be called on the same thread as
|
||||
ma_device_init(). We could also just not release the IAudioClient when performing automatic
|
||||
stream routing to avoid the deadlock. Neither of these are acceptable solutions in my view so
|
||||
we're going to have to work around this with a worker thread. This is not ideal, but I can't
|
||||
think of a better way to do this.
|
||||
|
||||
More information about this can be found here:
|
||||
|
||||
https://docs.microsoft.com/en-us/windows/win32/api/audioclient/nn-audioclient-iaudiorenderclient
|
||||
|
||||
Note this section:
|
||||
|
||||
When releasing an IAudioRenderClient interface instance, the client must call the interface's
|
||||
Release method from the same thread as the call to IAudioClient::GetService that created the
|
||||
object.
|
||||
*/
|
||||
{
|
||||
result = ma_mutex_init(&pContextStateWASAPI->commandLock);
|
||||
if (result != MA_SUCCESS) {
|
||||
ma_free(pContextStateWASAPI, ma_context_get_allocation_callbacks(pContext));
|
||||
return result;
|
||||
}
|
||||
|
||||
result = ma_semaphore_init(0, &pContextStateWASAPI->commandSem);
|
||||
if (result != MA_SUCCESS) {
|
||||
ma_mutex_uninit(&pContextStateWASAPI->commandLock);
|
||||
ma_free(pContextStateWASAPI, ma_context_get_allocation_callbacks(pContext));
|
||||
return result;
|
||||
}
|
||||
|
||||
result = ma_thread_create(&pContextStateWASAPI->commandThread, ma_thread_priority_normal, 0, ma_context_command_thread__wasapi, pContextStateWASAPI, &pContext->allocationCallbacks);
|
||||
if (result != MA_SUCCESS) {
|
||||
ma_semaphore_uninit(&pContextStateWASAPI->commandSem);
|
||||
ma_mutex_uninit(&pContextStateWASAPI->commandLock);
|
||||
ma_free(pContextStateWASAPI, ma_context_get_allocation_callbacks(pContext));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
*ppContextState = pContextStateWASAPI;
|
||||
|
||||
return MA_SUCCESS;
|
||||
@@ -23420,13 +23167,9 @@ static ma_result ma_context_init__wasapi(ma_context* pContext, const void* pCont
|
||||
static void ma_context_uninit__wasapi(ma_context* pContext)
|
||||
{
|
||||
ma_context_state_wasapi* pContextStateWASAPI = ma_context_get_backend_state__wasapi(pContext);
|
||||
ma_context_command__wasapi cmd = ma_context_init_command__wasapi(MA_CONTEXT_COMMAND_QUIT__WASAPI);
|
||||
|
||||
MA_ASSERT(pContext != NULL);
|
||||
|
||||
ma_context_post_command__wasapi(pContext, &cmd);
|
||||
ma_thread_wait(&pContextStateWASAPI->commandThread);
|
||||
|
||||
if (pContextStateWASAPI->hAvrt) {
|
||||
ma_dlclose(ma_context_get_log(pContext), pContextStateWASAPI->hAvrt);
|
||||
pContextStateWASAPI->hAvrt = NULL;
|
||||
@@ -23441,10 +23184,6 @@ static void ma_context_uninit__wasapi(ma_context* pContext)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Only after the thread has been terminated can we uninitialize the sync objects for the command thread. */
|
||||
ma_semaphore_uninit(&pContextStateWASAPI->commandSem);
|
||||
ma_mutex_uninit(&pContextStateWASAPI->commandLock);
|
||||
|
||||
ma_free(pContextStateWASAPI, ma_context_get_allocation_callbacks(pContext));
|
||||
}
|
||||
|
||||
@@ -24106,16 +23845,7 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Before reinitializing the device we need to free the previous audio clients.
|
||||
|
||||
There's a known memory leak here. We will be calling this from the routing change callback that
|
||||
is fired by WASAPI. If we attempt to release the IAudioClient we will deadlock. In my opinion
|
||||
this is a bug. I'm not sure what I need to do to handle this cleanly, but I think we'll probably
|
||||
need some system where we post an event, but delay the execution of it until the callback has
|
||||
returned. I'm not sure how to do this reliably, however. I have set up some infrastructure for
|
||||
a command thread which might be useful for this.
|
||||
*/
|
||||
/* Before reinitializing the device we need to free the previous audio clients. */
|
||||
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
|
||||
if (pDeviceStateWASAPI->pCaptureClient) {
|
||||
ma_IAudioCaptureClient_Release(pDeviceStateWASAPI->pCaptureClient);
|
||||
@@ -24169,8 +23899,8 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev
|
||||
|
||||
/* At this point we have some new objects ready to go. We need to uninitialize the previous ones and then set the new ones. */
|
||||
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
|
||||
pDeviceStateWASAPI->pAudioClientCapture = data.pAudioClient;
|
||||
pDeviceStateWASAPI->pCaptureClient = data.pCaptureClient;
|
||||
pDeviceStateWASAPI->pAudioClientCapture = data.pAudioClient;
|
||||
pDeviceStateWASAPI->pCaptureClient = data.pCaptureClient;
|
||||
|
||||
pDevice->capture.internalFormat = data.formatOut;
|
||||
pDevice->capture.internalChannels = data.channelsOut;
|
||||
@@ -24189,8 +23919,8 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev
|
||||
}
|
||||
|
||||
if (deviceType == ma_device_type_playback) {
|
||||
pDeviceStateWASAPI->pAudioClientPlayback = data.pAudioClient;
|
||||
pDeviceStateWASAPI->pRenderClient = data.pRenderClient;
|
||||
pDeviceStateWASAPI->pAudioClientPlayback = data.pAudioClient;
|
||||
pDeviceStateWASAPI->pRenderClient = data.pRenderClient;
|
||||
|
||||
pDevice->playback.internalFormat = data.formatOut;
|
||||
pDevice->playback.internalChannels = data.channelsOut;
|
||||
|
||||
Reference in New Issue
Block a user