mirror of
https://github.com/mackron/miniaudio.git
synced 2026-04-23 16:54:03 +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
|
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_handle hAvrt;
|
||||||
MA_PFN_AvSetMmThreadCharacteristicsA AvSetMmThreadCharacteristicsA;
|
MA_PFN_AvSetMmThreadCharacteristicsA AvSetMmThreadCharacteristicsA;
|
||||||
MA_PFN_AvRevertMmThreadCharacteristics AvRevertMmThreadCharacteristics;
|
MA_PFN_AvRevertMmThreadCharacteristics AvRevertMmThreadCharacteristics;
|
||||||
@@ -22436,192 +22403,21 @@ typedef ma_IUnknown ma_WASAPIDeviceInterface;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define MA_CONTEXT_COMMAND_QUIT__WASAPI 1
|
static ma_result ma_device_create_IAudioClient_service__wasapi(ma_context* pContext, ma_device_type deviceType, ma_IAudioClient* pAudioClient, void** ppAudioClientService)
|
||||||
#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)
|
|
||||||
{
|
{
|
||||||
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_result result;
|
||||||
ma_bool32 isUsingLocalEvent = MA_FALSE;
|
|
||||||
ma_event localEvent;
|
|
||||||
|
|
||||||
MA_ASSERT(pContext != NULL);
|
(void)pContext;
|
||||||
MA_ASSERT(pCmd != NULL);
|
|
||||||
|
|
||||||
if (pCmd->pEvent == NULL) {
|
if (deviceType == ma_device_type_playback) {
|
||||||
isUsingLocalEvent = MA_TRUE;
|
result = ma_result_from_HRESULT(ma_IAudioClient_GetService(pAudioClient, &MA_IID_IAudioRenderClient, ppAudioClientService));
|
||||||
|
} else {
|
||||||
result = ma_event_init(&localEvent);
|
result = ma_result_from_HRESULT(ma_IAudioClient_GetService(pAudioClient, &MA_IID_IAudioCaptureClient, ppAudioClientService));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
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)
|
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;
|
*ppContextState = pContextStateWASAPI;
|
||||||
|
|
||||||
return MA_SUCCESS;
|
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)
|
static void ma_context_uninit__wasapi(ma_context* pContext)
|
||||||
{
|
{
|
||||||
ma_context_state_wasapi* pContextStateWASAPI = ma_context_get_backend_state__wasapi(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_ASSERT(pContext != NULL);
|
||||||
|
|
||||||
ma_context_post_command__wasapi(pContext, &cmd);
|
|
||||||
ma_thread_wait(&pContextStateWASAPI->commandThread);
|
|
||||||
|
|
||||||
if (pContextStateWASAPI->hAvrt) {
|
if (pContextStateWASAPI->hAvrt) {
|
||||||
ma_dlclose(ma_context_get_log(pContext), pContextStateWASAPI->hAvrt);
|
ma_dlclose(ma_context_get_log(pContext), pContextStateWASAPI->hAvrt);
|
||||||
pContextStateWASAPI->hAvrt = NULL;
|
pContextStateWASAPI->hAvrt = NULL;
|
||||||
@@ -23441,10 +23184,6 @@ static void ma_context_uninit__wasapi(ma_context* pContext)
|
|||||||
}
|
}
|
||||||
#endif
|
#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));
|
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. */
|
||||||
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.
|
|
||||||
*/
|
|
||||||
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
|
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
|
||||||
if (pDeviceStateWASAPI->pCaptureClient) {
|
if (pDeviceStateWASAPI->pCaptureClient) {
|
||||||
ma_IAudioCaptureClient_Release(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. */
|
/* 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) {
|
if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) {
|
||||||
pDeviceStateWASAPI->pAudioClientCapture = data.pAudioClient;
|
pDeviceStateWASAPI->pAudioClientCapture = data.pAudioClient;
|
||||||
pDeviceStateWASAPI->pCaptureClient = data.pCaptureClient;
|
pDeviceStateWASAPI->pCaptureClient = data.pCaptureClient;
|
||||||
|
|
||||||
pDevice->capture.internalFormat = data.formatOut;
|
pDevice->capture.internalFormat = data.formatOut;
|
||||||
pDevice->capture.internalChannels = data.channelsOut;
|
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) {
|
if (deviceType == ma_device_type_playback) {
|
||||||
pDeviceStateWASAPI->pAudioClientPlayback = data.pAudioClient;
|
pDeviceStateWASAPI->pAudioClientPlayback = data.pAudioClient;
|
||||||
pDeviceStateWASAPI->pRenderClient = data.pRenderClient;
|
pDeviceStateWASAPI->pRenderClient = data.pRenderClient;
|
||||||
|
|
||||||
pDevice->playback.internalFormat = data.formatOut;
|
pDevice->playback.internalFormat = data.formatOut;
|
||||||
pDevice->playback.internalChannels = data.channelsOut;
|
pDevice->playback.internalChannels = data.channelsOut;
|
||||||
|
|||||||
Reference in New Issue
Block a user