Commit 2fed9dd3 authored by David Reid's avatar David Reid

Clean up the WinMM and WASAPI backends.

parent 30918273
......@@ -1939,10 +1939,6 @@ MAL_ALIGNED_STRUCT(MAL_SIMD_ALIGNMENT) mal_device
mal_IMMNotificationClient notificationClient;
/*HANDLE*/ mal_handle hEventPlayback; /* Used with the blocking API. Manual reset. Initialized to signaled. */
/*HANDLE*/ mal_handle hEventCapture; /* Used with the blocking API. Manual reset. Initialized to unsignaled. */
#if 0
/*HANDLE*/ mal_handle hEvent;
/*HANDLE*/ mal_handle hBreakEvent; /* <-- Used to break from WaitForMultipleObjects() in the main loop. */
#endif
void* pDeviceBufferPlayback;
void* pDeviceBufferCapture;
mal_uint32 deviceBufferFramesRemainingPlayback;
......@@ -1950,7 +1946,6 @@ MAL_ALIGNED_STRUCT(MAL_SIMD_ALIGNMENT) mal_device
mal_uint32 deviceBufferFramesCapacityPlayback;
mal_uint32 deviceBufferFramesCapacityCapture;
mal_bool32 isStarted;
mal_bool32 breakFromMainLoop; /* TODO: Delete me once the new main loop is finialized. */
mal_bool32 hasDefaultDeviceChanged; /* <-- Make sure this is always a whole 32-bits because we use atomic assignments. */
} wasapi;
#endif
......@@ -1986,7 +1981,6 @@ MAL_ALIGNED_STRUCT(MAL_SIMD_ALIGNMENT) mal_device
mal_uint8* pIntermediaryBuffer;
mal_uint8* _pHeapData; /* Used internally and is used for the heap allocated data for the intermediary buffer and the WAVEHDR structures. */
mal_bool32 isStarted;
mal_bool32 breakFromMainLoop; /* TODO: Delete me once the new main loop is finialized. */
} winmm;
#endif
#ifdef MAL_SUPPORT_ALSA
......@@ -6424,15 +6418,6 @@ void mal_device_uninit__wasapi(mal_device* pDevice)
if (pDevice->wasapi.hEventCapture) {
CloseHandle(pDevice->wasapi.hEventCapture);
}
#if 0
if (pDevice->wasapi.hEvent) {
CloseHandle(pDevice->wasapi.hEvent);
}
if (pDevice->wasapi.hBreakEvent) {
CloseHandle(pDevice->wasapi.hBreakEvent);
}
#endif
}
typedef struct
......@@ -6812,7 +6797,7 @@ mal_result mal_device_reinit__wasapi(mal_device* pDevice)
pDevice->wasapi.pAudioClient = data.pAudioClient;
pDevice->wasapi.pRenderClient = data.pRenderClient;
pDevice->wasapi.pCaptureClient = data.pCaptureClient;
pDevice->wasapi.isStarted = MAL_FALSE;
mal_atomic_exchange_32(&pDevice->wasapi.isStarted, MAL_FALSE);
pDevice->internalFormat = data.formatOut;
pDevice->internalChannels = data.channelsOut;
......@@ -6829,10 +6814,6 @@ mal_result mal_device_reinit__wasapi(mal_device* pDevice)
mal_IAudioClient_SetEventHandle((mal_IAudioClient*)pDevice->wasapi.pAudioClient, pDevice->wasapi.hEventCapture);
}
#if 0
mal_IAudioClient_SetEventHandle((mal_IAudioClient*)pDevice->wasapi.pAudioClient, pDevice->wasapi.hEvent);
#endif
return MAL_SUCCESS;
}
......@@ -6867,7 +6848,7 @@ mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type type,
pDevice->wasapi.pAudioClient = data.pAudioClient;
pDevice->wasapi.pRenderClient = data.pRenderClient;
pDevice->wasapi.pCaptureClient = data.pCaptureClient;
pDevice->wasapi.isStarted = MAL_FALSE;
mal_atomic_exchange_32(&pDevice->wasapi.isStarted, MAL_FALSE);
pDevice->internalFormat = data.formatOut;
pDevice->internalChannels = data.channelsOut;
......@@ -6935,26 +6916,6 @@ mal_result mal_device_init__wasapi(mal_context* pContext, mal_device_type type,
mal_IAudioClient_SetEventHandle((mal_IAudioClient*)pDevice->wasapi.pAudioClient, pDevice->wasapi.hEventCapture);
}
#if 0
// We need to create and set the event for event-driven mode. This event is signaled whenever a new chunk of audio
// data needs to be written or read from the device.
pDevice->wasapi.hEvent = CreateEventA(NULL, FALSE, TRUE, NULL);
if (pDevice->wasapi.hEvent == NULL) {
errorMsg = "[WASAPI] Failed to create main event for main loop.", result = MAL_FAILED_TO_CREATE_EVENT;
goto done;
}
mal_IAudioClient_SetEventHandle((mal_IAudioClient*)pDevice->wasapi.pAudioClient, pDevice->wasapi.hEvent);
// When the device is playing the worker thread will be waiting on a bunch of notification events. To return from
// this wait state we need to signal a special event.
pDevice->wasapi.hBreakEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
if (pDevice->wasapi.hBreakEvent == NULL) {
errorMsg = "[WASAPI] Failed to create break event for main loop break notification.", result = MAL_FAILED_TO_CREATE_EVENT;
goto done;
}
#endif
result = MAL_SUCCESS;
done:
......@@ -6976,7 +6937,7 @@ mal_result mal_device_start__wasapi(mal_device* pDevice)
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal device.", MAL_FAILED_TO_START_BACKEND_DEVICE);
}
pDevice->wasapi.isStarted = MAL_TRUE;
mal_atomic_exchange_32(&pDevice->wasapi.isStarted, MAL_TRUE);
return MAL_SUCCESS;
}
......@@ -6993,7 +6954,7 @@ mal_result mal_device_stop__wasapi(mal_device* pDevice)
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal device.", MAL_FAILED_TO_STOP_BACKEND_DEVICE);
}
pDevice->wasapi.isStarted = MAL_FALSE;
mal_atomic_exchange_32(&pDevice->wasapi.isStarted, MAL_FALSE);
return MAL_SUCCESS;
}
......@@ -7056,8 +7017,6 @@ mal_result mal_device_write__wasapi(mal_device* pDevice, mal_uint32 pcmFrameCoun
mal_uint32 totalPCMFramesWritten;
HRESULT hr;
DWORD waitResult;
HANDLE hEvents[1];
hEvents[0] = pDevice->wasapi.hEventPlayback;
*pPCMFramesWritten = 0;
wasStartedOnEntry = pDevice->wasapi.isStarted;
......@@ -7119,7 +7078,7 @@ mal_result mal_device_write__wasapi(mal_device* pDevice, mal_uint32 pcmFrameCoun
/* Wait for data. */
waitResult = WaitForMultipleObjects(mal_countof(hEvents), hEvents, FALSE, INFINITE);
waitResult = WaitForSingleObject(pDevice->wasapi.hEventPlayback, INFINITE);
if (waitResult == WAIT_FAILED) {
result = MAL_ERROR;
break; /* An error occurred while waiting for the event. */
......@@ -7165,8 +7124,6 @@ mal_result mal_device_read__wasapi(mal_device* pDevice, mal_uint32 pcmFrameCount
HRESULT hr;
DWORD waitResult;
DWORD flags; /* Passed to IAudioCaptureClient_GetBuffer(). */
HANDLE hEvents[1];
hEvents[0] = pDevice->wasapi.hEventCapture;
/*
This is mostly the same as mal_device_write__wasapi() with only a few exceptions:
......@@ -7218,7 +7175,7 @@ mal_result mal_device_read__wasapi(mal_device* pDevice, mal_uint32 pcmFrameCount
}
/* Wait for data. */
waitResult = WaitForMultipleObjects(mal_countof(hEvents), hEvents, FALSE, INFINITE);
waitResult = WaitForSingleObject(pDevice->wasapi.hEventCapture, INFINITE);
if (waitResult == WAIT_FAILED) {
result = MAL_ERROR;
break; /* An error occurred while waiting for the event. */
......@@ -7257,172 +7214,6 @@ mal_result mal_device_read__wasapi(mal_device* pDevice, mal_uint32 pcmFrameCount
return result;
}
#if 0
mal_result mal_device_break_main_loop__wasapi(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
// The main loop will be waiting on a bunch of events via the WaitForMultipleObjects() API. One of those events
// is a special event we use for forcing that function to return.
pDevice->wasapi.breakFromMainLoop = MAL_TRUE;
SetEvent(pDevice->wasapi.hBreakEvent);
return MAL_SUCCESS;
}
mal_result mal_device__wait_for_frames__wasapi(mal_device* pDevice, mal_uint32* pFrameCount)
{
mal_assert(pDevice != NULL);
mal_result result;
while (!pDevice->wasapi.breakFromMainLoop) {
// Wait for a buffer to become available or for the stop event to be signalled.
HANDLE hEvents[2];
hEvents[0] = (HANDLE)pDevice->wasapi.hEvent;
hEvents[1] = (HANDLE)pDevice->wasapi.hBreakEvent;
if (WaitForMultipleObjects(mal_countof(hEvents), hEvents, FALSE, INFINITE) == WAIT_FAILED) {
break;
}
// Break from the main loop if the device isn't started anymore. Likely what's happened is the application
// has requested that the device be stopped.
if (!mal_device_is_started(pDevice)) {
break;
}
// Make sure we break from the main loop if requested from an external factor.
if (pDevice->wasapi.breakFromMainLoop) {
break;
}
// We may want to reinitialize the device. Only do this if this device is the default.
mal_bool32 needDeviceReinit = MAL_FALSE;
mal_bool32 hasDefaultDeviceChanged = pDevice->wasapi.hasDefaultDeviceChanged;
if (hasDefaultDeviceChanged && pDevice->isDefaultDevice) {
needDeviceReinit = MAL_TRUE;
}
if (!needDeviceReinit) {
result = mal_device__get_available_frames__wasapi(pDevice, pFrameCount);
if (result != MAL_SUCCESS) {
if (pDevice->initConfig.shareMode != mal_share_mode_exclusive) {
needDeviceReinit = MAL_TRUE;
} else {
return result;
}
}
}
mal_atomic_exchange_32(&pDevice->wasapi.hasDefaultDeviceChanged, MAL_FALSE);
// Here is where the device is re-initialized if required.
if (needDeviceReinit) {
#ifdef MAL_DEBUG_OUTPUT
printf("=== CHANGING DEVICE ===\n");
#endif
if (pDevice->pContext->onDeviceReinit) {
mal_result reinitResult = pDevice->pContext->onDeviceReinit(pDevice);
if (reinitResult != MAL_SUCCESS) {
return reinitResult;
}
mal_device__post_init_setup(pDevice);
// Start playing the device again, and then continue the loop from the top.
if (mal_device__get_state(pDevice) == MAL_STATE_STARTED) {
if (pDevice->pContext->onDeviceStart) {
pDevice->pContext->onDeviceStart(pDevice);
}
continue;
}
}
}
if (*pFrameCount > 0) {
return MAL_SUCCESS;
}
}
// We'll get here if the loop was terminated. Just return whatever's available.
return mal_device__get_available_frames__wasapi(pDevice, pFrameCount);
}
mal_result mal_device_main_loop__wasapi(mal_device* pDevice)
{
mal_assert(pDevice != NULL);
// Make sure the break event is not signaled to ensure we don't end up immediately returning from WaitForMultipleObjects().
ResetEvent(pDevice->wasapi.hBreakEvent);
pDevice->wasapi.breakFromMainLoop = MAL_FALSE;
while (!pDevice->wasapi.breakFromMainLoop) {
mal_uint32 framesAvailable;
mal_result result = mal_device__wait_for_frames__wasapi(pDevice, &framesAvailable);
if (result != MAL_SUCCESS) {
return result;
}
if (framesAvailable == 0) {
continue;
}
// If it's a playback device, don't bother grabbing more data if the device is being stopped.
if (pDevice->wasapi.breakFromMainLoop && pDevice->type == mal_device_type_playback) {
return MAL_SUCCESS;
}
if (pDevice->type == mal_device_type_playback) {
BYTE* pData;
HRESULT hr = mal_IAudioRenderClient_GetBuffer((mal_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailable, &pData);
if (FAILED(hr)) {
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to retrieve internal buffer from playback device in preparation for sending new data to the device.", MAL_FAILED_TO_MAP_DEVICE_BUFFER);
}
mal_device__read_frames_from_client(pDevice, framesAvailable, pData);
hr = mal_IAudioRenderClient_ReleaseBuffer((mal_IAudioRenderClient*)pDevice->wasapi.pRenderClient, framesAvailable, 0);
if (FAILED(hr)) {
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WASAPI] Failed to release internal buffer from playback device in preparation for sending new data to the device.", MAL_FAILED_TO_UNMAP_DEVICE_BUFFER);
}
} else {
mal_uint32 framesRemaining = framesAvailable;
while (framesRemaining > 0) {
BYTE* pData;
mal_uint32 framesToSend;
DWORD flags;
HRESULT hr = mal_IAudioCaptureClient_GetBuffer((mal_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, &pData, &framesToSend, &flags, NULL, NULL);
if (FAILED(hr)) {
mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WASAPI] WARNING: Failed to retrieve internal buffer from capture device in preparation for sending new data to the client.", MAL_FAILED_TO_MAP_DEVICE_BUFFER);
break;
}
if (hr != MAL_AUDCLNT_S_BUFFER_EMPTY) {
mal_device__send_frames_to_client(pDevice, framesToSend, pData);
hr = mal_IAudioCaptureClient_ReleaseBuffer((mal_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, framesToSend);
if (FAILED(hr)) {
mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WASAPI] WARNING: Failed to release internal buffer from capture device in preparation for sending new data to the client.", MAL_FAILED_TO_UNMAP_DEVICE_BUFFER);
break;
}
if (framesRemaining >= framesToSend) {
framesRemaining -= framesToSend;
} else {
framesRemaining = 0;
}
}
}
}
}
return MAL_SUCCESS;
}
#endif
mal_result mal_context_uninit__wasapi(mal_context* pContext)
{
mal_assert(pContext != NULL);
......@@ -7471,11 +7262,6 @@ mal_result mal_context_init__wasapi(mal_context* pContext)
pContext->onDeviceWrite = mal_device_write__wasapi;
pContext->onDeviceRead = mal_device_read__wasapi;
#if 0
pContext->onDeviceBreakMainLoop = mal_device_break_main_loop__wasapi;
pContext->onDeviceMainLoop = mal_device_main_loop__wasapi;
#endif
return result;
}
#endif
......@@ -9737,7 +9523,7 @@ mal_result mal_device_read__winmm(mal_device* pDevice, mal_uint32 pcmFrameCount,
return mal_post_error(pDevice, MAL_LOG_LEVEL_ERROR, "[WinMM] Failed to start backend device.", mal_result_from_MMRESULT(resultMM));
}
pDevice->winmm.isStarted = MAL_TRUE;
mal_atomic_exchange_32(&pDevice->winmm.isStarted, MAL_TRUE);
}
/* Keep processing as much data as possible. */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment