From 2bee71a7e032c0972418e324bb1d7e6b02330b18 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Wed, 19 Feb 2025 13:40:38 -0500 Subject: Server resource unload, many tweaks and fixes - Initial liana client preferences. - Hook up libplacebo dx11 backend. - Make usage of FFmpeg hardware decoding api make some sense. Signed-off-by: Andrew Opalach --- .../miniaudio/miniaudio_pulse_flush.diff | 25 +--- .../miniaudio/miniaudio_wasapi_clock_service.diff | 151 +++++++++++++++++++++ .../miniaudio/miniaudio_wasapi_drain.diff | 44 ++++++ .../miniaudio_wasapi_exclusive_testing.diff | 83 +++++++++++ .../miniaudio/miniaudio_wasapi_release.diff | 70 ++++++++++ 5 files changed, 349 insertions(+), 24 deletions(-) create mode 100644 subprojects/packagefiles/miniaudio/miniaudio_wasapi_clock_service.diff create mode 100644 subprojects/packagefiles/miniaudio/miniaudio_wasapi_drain.diff create mode 100644 subprojects/packagefiles/miniaudio/miniaudio_wasapi_exclusive_testing.diff create mode 100644 subprojects/packagefiles/miniaudio/miniaudio_wasapi_release.diff (limited to 'subprojects/packagefiles/miniaudio') diff --git a/subprojects/packagefiles/miniaudio/miniaudio_pulse_flush.diff b/subprojects/packagefiles/miniaudio/miniaudio_pulse_flush.diff index 41ea436..293ba94 100644 --- a/subprojects/packagefiles/miniaudio/miniaudio_pulse_flush.diff +++ b/subprojects/packagefiles/miniaudio/miniaudio_pulse_flush.diff @@ -1,26 +1,3 @@ -diff --git a/extras/miniaudio_split/miniaudio.c b/extras/miniaudio_split/miniaudio.c -index bb97e1f..43bf4f1 100644 ---- a/extras/miniaudio_split/miniaudio.c -+++ b/extras/miniaudio_split/miniaudio.c -@@ -4763,7 +4763,7 @@ static void ma_thread_wait__posix(ma_thread* pThread) - static ma_result ma_mutex_init__posix(ma_mutex* pMutex) - { - int result; -- -+ - if (pMutex == NULL) { - return MA_INVALID_ARGS; - } -@@ -19374,7 +19374,8 @@ static ma_result ma_device_stop__pulse(ma_device* pDevice) - happens, draining never completes and we get stuck here. For now I'm disabling draining of - the device so we don't just freeze the application. - */ -- #if 0 -+ #if 1 -+ ma_bool32 wasSuccessful = MA_FALSE; - ma_pa_operation* pOP = ((ma_pa_stream_drain_proc)pDevice->pContext->pulse.pa_stream_drain)((ma_pa_stream*)pDevice->pulse.pStreamPlayback, ma_pulse_operation_complete_callback, &wasSuccessful); - ma_wait_for_operation_and_unref__pulse(pDevice->pContext, pDevice->pulse.pMainLoop, pOP); - #endif diff --git a/miniaudio.h b/miniaudio.h index a5673ac..cf73a54 100644 --- a/miniaudio.h @@ -29,7 +6,7 @@ index a5673ac..cf73a54 100644 static ma_result ma_mutex_init__posix(ma_mutex* pMutex) { int result; -- +- + if (pMutex == NULL) { return MA_INVALID_ARGS; diff --git a/subprojects/packagefiles/miniaudio/miniaudio_wasapi_clock_service.diff b/subprojects/packagefiles/miniaudio/miniaudio_wasapi_clock_service.diff new file mode 100644 index 0000000..4398e31 --- /dev/null +++ b/subprojects/packagefiles/miniaudio/miniaudio_wasapi_clock_service.diff @@ -0,0 +1,151 @@ +diff --git a/miniaudio.h b/miniaudio.h +index 3879cd3..58a16a6 100644 +--- a/miniaudio.h ++++ b/miniaudio.h +@@ -7312,6 +7312,7 @@ typedef struct + ma_device_type deviceType; + void* pAudioClient; + void** ppAudioClientService; ++ void** ppAudioClock; + ma_result* pResult; /* The result from creating the audio client service. */ + } createAudioClient; + struct +@@ -7821,6 +7822,7 @@ struct ma_device + /*IAudioClient**/ ma_ptr pAudioClientCapture; + /*IAudioRenderClient**/ ma_ptr pRenderClient; + /*IAudioCaptureClient**/ ma_ptr pCaptureClient; ++ /*IAudioClock**/ ma_ptr pAudioClock; + /*IMMDeviceEnumerator**/ ma_ptr pDeviceEnumerator; /* Used for IMMNotificationClient notifications. Required for detecting default device changes. */ + ma_IMMNotificationClient notificationClient; + /*HANDLE*/ ma_handle hEventPlayback; /* Auto reset. Initialized to signaled. */ +@@ -20305,6 +20307,8 @@ static const IID MA_IID_IAudioClient2 = {0x726778CD, + static const IID MA_IID_IAudioClient3 = {0x7ED4EE07, 0x8E67, 0x4CD4, {0x8C, 0x1A, 0x2B, 0x7A, 0x59, 0x87, 0xAD, 0x42}}; /* 7ED4EE07-8E67-4CD4-8C1A-2B7A5987AD42 = __uuidof(IAudioClient3) */ + static const IID MA_IID_IAudioRenderClient = {0xF294ACFC, 0x3146, 0x4483, {0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2}}; /* F294ACFC-3146-4483-A7BF-ADDCA7C260E2 = __uuidof(IAudioRenderClient) */ + static const IID MA_IID_IAudioCaptureClient = {0xC8ADBD64, 0xE71E, 0x48A0, {0xA4, 0xDE, 0x18, 0x5C, 0x39, 0x5C, 0xD3, 0x17}}; /* C8ADBD64-E71E-48A0-A4DE-185C395CD317 = __uuidof(IAudioCaptureClient) */ ++static const IID MA_IID_IAudioClock = {0xCD63314F, 0x3FBA, 0x4a1b, {0x81, 0x2C, 0xEF, 0x96, 0x35, 0x87, 0x28, 0xE7}}; /* CD63314F-3FBA-4a1b-812C-EF96358728E7 = _uuidof(IAudioClock) */ ++static const IID MA_IID_IAudioClock2 = {0x6f49ff73, 0x6727, 0x49ac, {0xa0, 0x08, 0xd9, 0x8c, 0xf5, 0xe7, 0x00, 0x48}}; /* 6f49ff73-6727-49ac-a008-d98cf5e70048 = __uuidof(IAudioClock2) */ + static const IID MA_IID_IMMNotificationClient = {0x7991EEC9, 0x7E89, 0x4D85, {0x83, 0x90, 0x6C, 0x70, 0x3C, 0xEC, 0x60, 0xC0}}; /* 7991EEC9-7E89-4D85-8390-6C703CEC60C0 = __uuidof(IMMNotificationClient) */ + #if !defined(MA_WIN32_DESKTOP) && !defined(MA_WIN32_GDK) + static const IID MA_IID_DEVINTERFACE_AUDIO_RENDER = {0xE6327CAD, 0xDCEC, 0x4949, {0xAE, 0x8A, 0x99, 0x1E, 0x97, 0x6A, 0x79, 0xD2}}; /* E6327CAD-DCEC-4949-AE8A-991E976A79D2 */ +@@ -20334,6 +20338,7 @@ typedef struct ma_IAudioClient2 ma_IAudioClient2; + typedef struct ma_IAudioClient3 ma_IAudioClient3; + typedef struct ma_IAudioRenderClient ma_IAudioRenderClient; + typedef struct ma_IAudioCaptureClient ma_IAudioCaptureClient; ++typedef struct ma_IAudioClock ma_IAudioClock; + + typedef ma_int64 MA_REFERENCE_TIME; + +@@ -20745,6 +20750,28 @@ static MA_INLINE HRESULT ma_IAudioCaptureClient_GetBuffer(ma_IAudioCaptureClient + static MA_INLINE HRESULT ma_IAudioCaptureClient_ReleaseBuffer(ma_IAudioCaptureClient* pThis, ma_uint32 numFramesRead) { return pThis->lpVtbl->ReleaseBuffer(pThis, numFramesRead); } + static MA_INLINE HRESULT ma_IAudioCaptureClient_GetNextPacketSize(ma_IAudioCaptureClient* pThis, ma_uint32* pNumFramesInNextPacket) { return pThis->lpVtbl->GetNextPacketSize(pThis, pNumFramesInNextPacket); } + ++ ++/* IAudioClock */ ++typedef struct ++{ ++ /* IUnknown */ ++ HRESULT (STDMETHODCALLTYPE * QueryInterface)(ma_IAudioCaptureClient* pThis, const IID* const riid, void** ppObject); ++ ULONG (STDMETHODCALLTYPE * AddRef) (ma_IAudioCaptureClient* pThis); ++ ULONG (STDMETHODCALLTYPE * Release) (ma_IAudioCaptureClient* pThis); ++ ++ /* IAudioClock */ ++ HRESULT (STDMETHODCALLTYPE * GetFrequency)(ma_IAudioClock* pThis, ma_uint64* pu64Frequency); ++ HRESULT (STDMETHODCALLTYPE * GetPosition)(ma_IAudioClock* pThis, ma_uint64* pu64Position, ma_uint64* pu64QPCPosition); ++ HRESULT (STDMETHODCALLTYPE * GetCharacteristics)(ma_IAudioClock* pThis, DWORD* pdwCharacteristics); ++} ma_IAudioClockVtbl; ++struct ma_IAudioClock ++{ ++ ma_IAudioClockVtbl* lpVtbl; ++}; ++static MA_INLINE HRESULT ma_IAudioClock_GetFrequency(ma_IAudioClock* pThis, ma_uint64* pu64Frequency) { return pThis->lpVtbl->GetFrequency(pThis, pu64Frequency); } ++static MA_INLINE HRESULT ma_IAudioClock_GetPosition(ma_IAudioClock* pThis, ma_uint64* pu64Position, ma_uint64* pu64QPCPosition) { return pThis->lpVtbl->GetPosition(pThis, pu64Position, pu64QPCPosition); } ++static MA_INLINE HRESULT ma_IAudioClock_GetCharacteristics(ma_IAudioClock* pThis, DWORD* pdwCharacteristics) { return pThis->lpVtbl->GetCharacteristics(pThis, pdwCharacteristics); } ++ + #if defined(MA_WIN32_UWP) + /* mmdevapi Functions */ + typedef HRESULT (WINAPI * MA_PFN_ActivateAudioInterfaceAsync)(const wchar_t* deviceInterfacePath, const IID* riid, MA_PROPVARIANT* activationParams, ma_IActivateAudioInterfaceCompletionHandler* completionHandler, ma_IActivateAudioInterfaceAsyncOperation** activationOperation); +@@ -21248,6 +21275,7 @@ static ma_thread_result MA_THREADCALL ma_context_command_thread__wasapi(void* pU + } else { + *cmd.data.createAudioClient.pResult = ma_result_from_HRESULT(ma_IAudioClient_GetService((ma_IAudioClient*)cmd.data.createAudioClient.pAudioClient, &MA_IID_IAudioCaptureClient, cmd.data.createAudioClient.ppAudioClientService)); + } ++ ma_IAudioClient_GetService((ma_IAudioClient*)cmd.data.createAudioClient.pAudioClient, &MA_IID_IAudioClock, cmd.data.createAudioClient.ppAudioClock); + } break; + + case MA_CONTEXT_COMMAND_RELEASE_IAUDIOCLIENT__WASAPI: +@@ -21286,7 +21314,7 @@ static ma_thread_result MA_THREADCALL ma_context_command_thread__wasapi(void* pU + 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) ++static ma_result ma_device_create_IAudioClient_service__wasapi(ma_context* pContext, ma_device_type deviceType, ma_IAudioClient* pAudioClient, void** ppAudioClientService, void **ppAudioClock) + { + ma_result result; + ma_result cmdResult; +@@ -21294,6 +21322,7 @@ static ma_result ma_device_create_IAudioClient_service__wasapi(ma_context* pCont + cmd.data.createAudioClient.deviceType = deviceType; + cmd.data.createAudioClient.pAudioClient = (void*)pAudioClient; + cmd.data.createAudioClient.ppAudioClientService = ppAudioClientService; ++ cmd.data.createAudioClient.ppAudioClock = ppAudioClock; + 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. */ +@@ -22121,6 +22150,7 @@ typedef struct + ma_IAudioClient* pAudioClient; + ma_IAudioRenderClient* pRenderClient; + ma_IAudioCaptureClient* pCaptureClient; ++ ma_IAudioClock* pAudioClock; + ma_format formatOut; + ma_uint32 channelsOut; + ma_uint32 sampleRateOut; +@@ -22160,6 +22190,7 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device + pData->pAudioClient = NULL; + pData->pRenderClient = NULL; + pData->pCaptureClient = NULL; ++ pData->pAudioClock = NULL; + + streamFlags = MA_AUDCLNT_STREAMFLAGS_EVENTCALLBACK; + if (!pData->noAutoConvertSRC && pData->sampleRateIn != 0 && pData->shareMode != ma_share_mode_exclusive) { /* <-- Exclusive streams must use the native sample rate. */ +@@ -22530,9 +22561,9 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device + + + if (deviceType == ma_device_type_playback) { +- result = ma_device_create_IAudioClient_service__wasapi(pContext, deviceType, (ma_IAudioClient*)pData->pAudioClient, (void**)&pData->pRenderClient); ++ result = ma_device_create_IAudioClient_service__wasapi(pContext, deviceType, (ma_IAudioClient*)pData->pAudioClient, (void**)&pData->pRenderClient, (void**)&pData->pAudioClock); + } else { +- result = ma_device_create_IAudioClient_service__wasapi(pContext, deviceType, (ma_IAudioClient*)pData->pAudioClient, (void**)&pData->pCaptureClient); ++ result = ma_device_create_IAudioClient_service__wasapi(pContext, deviceType, (ma_IAudioClient*)pData->pAudioClient, (void**)&pData->pCaptureClient, (void**)&pData->pAudioClock); + } + + /*if (FAILED(hr)) {*/ +@@ -22693,6 +22724,7 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev + if (deviceType == ma_device_type_capture || deviceType == ma_device_type_loopback) { + pDevice->wasapi.pAudioClientCapture = data.pAudioClient; + pDevice->wasapi.pCaptureClient = data.pCaptureClient; ++ pDevice->wasapi.pAudioClock = data.pAudioClock; + + pDevice->capture.internalFormat = data.formatOut; + pDevice->capture.internalChannels = data.channelsOut; +@@ -22714,6 +22746,7 @@ static ma_result ma_device_reinit__wasapi(ma_device* pDevice, ma_device_type dev + if (deviceType == ma_device_type_playback) { + pDevice->wasapi.pAudioClientPlayback = data.pAudioClient; + pDevice->wasapi.pRenderClient = data.pRenderClient; ++ pDevice->wasapi.pAudioClock = data.pAudioClock; + + pDevice->playback.internalFormat = data.formatOut; + pDevice->playback.internalChannels = data.channelsOut; +@@ -22783,6 +22816,7 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf + + pDevice->wasapi.pAudioClientCapture = data.pAudioClient; + pDevice->wasapi.pCaptureClient = data.pCaptureClient; ++ pDevice->wasapi.pAudioClock = data.pAudioClock; + pDevice->wasapi.originalPeriodSizeInMilliseconds = pDescriptorCapture->periodSizeInMilliseconds; + pDevice->wasapi.originalPeriodSizeInFrames = pDescriptorCapture->periodSizeInFrames; + pDevice->wasapi.originalPeriods = pDescriptorCapture->periodCount; +@@ -22862,6 +22896,7 @@ static ma_result ma_device_init__wasapi(ma_device* pDevice, const ma_device_conf + + pDevice->wasapi.pAudioClientPlayback = data.pAudioClient; + pDevice->wasapi.pRenderClient = data.pRenderClient; ++ pDevice->wasapi.pAudioClock = data.pAudioClock; + pDevice->wasapi.originalPeriodSizeInMilliseconds = pDescriptorPlayback->periodSizeInMilliseconds; + pDevice->wasapi.originalPeriodSizeInFrames = pDescriptorPlayback->periodSizeInFrames; + pDevice->wasapi.originalPeriods = pDescriptorPlayback->periodCount; diff --git a/subprojects/packagefiles/miniaudio/miniaudio_wasapi_drain.diff b/subprojects/packagefiles/miniaudio/miniaudio_wasapi_drain.diff new file mode 100644 index 0000000..eb6bd24 --- /dev/null +++ b/subprojects/packagefiles/miniaudio/miniaudio_wasapi_drain.diff @@ -0,0 +1,44 @@ +commit 7ead713f6b67c0247e248de3709cc383da19bdea +Author: Andrew Opalach +Date: Sun Feb 2 15:24:33 2025 -0500 + + WASAPI: Fix drain on device stop + +diff --git a/miniaudio.h b/miniaudio.h +index fced0d2..22b0e4f 100644 +--- a/miniaudio.h ++++ b/miniaudio.h +@@ -23133,13 +23133,12 @@ static ma_result ma_device_stop__wasapi_nolock(ma_device* pDevice) + */ + if (ma_atomic_bool32_get(&pDevice->wasapi.isStartedPlayback)) { + /* We need to make sure we put a timeout here or else we'll risk getting stuck in a deadlock in some cases. */ +- DWORD waitTime = pDevice->wasapi.actualBufferSizeInFramesPlayback / pDevice->playback.internalSampleRate; ++ DWORD waitTime = pDevice->wasapi.actualBufferSizeInFramesPlayback / (pDevice->playback.internalSampleRate / 1000); + + if (pDevice->playback.shareMode == ma_share_mode_exclusive) { + WaitForSingleObject((HANDLE)pDevice->wasapi.hEventPlayback, waitTime); +- } +- else { +- ma_uint32 prevFramesAvaialablePlayback = (ma_uint32)-1; ++ } else { ++ ma_uint32 prevFramesAvailablePlayback = (ma_uint32)-1; + ma_uint32 framesAvailablePlayback; + for (;;) { + result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback); +@@ -23155,13 +23154,13 @@ static ma_result ma_device_stop__wasapi_nolock(ma_device* pDevice) + Just a safety check to avoid an infinite loop. If this iteration results in a situation where the number of available frames + has not changed, get out of the loop. I don't think this should ever happen, but I think it's nice to have just in case. + */ +- if (framesAvailablePlayback == prevFramesAvaialablePlayback) { ++ if (framesAvailablePlayback == prevFramesAvailablePlayback) { + break; + } +- prevFramesAvaialablePlayback = framesAvailablePlayback; ++ prevFramesAvailablePlayback = framesAvailablePlayback; + +- WaitForSingleObject((HANDLE)pDevice->wasapi.hEventPlayback, waitTime * 1000); + ResetEvent((HANDLE)pDevice->wasapi.hEventPlayback); /* Manual reset. */ ++ WaitForSingleObject((HANDLE)pDevice->wasapi.hEventPlayback, waitTime); + } + } + } diff --git a/subprojects/packagefiles/miniaudio/miniaudio_wasapi_exclusive_testing.diff b/subprojects/packagefiles/miniaudio/miniaudio_wasapi_exclusive_testing.diff new file mode 100644 index 0000000..994a750 --- /dev/null +++ b/subprojects/packagefiles/miniaudio/miniaudio_wasapi_exclusive_testing.diff @@ -0,0 +1,83 @@ +diff --git a/miniaudio.h b/miniaudio.h +index 22b0e4f..49ecd9a 100644 +--- a/miniaudio.h ++++ b/miniaudio.h +@@ -23061,6 +23061,26 @@ static ma_result ma_device_start__wasapi_nolock(ma_device* pDevice) + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ++ ma_uint32 bufferSizeInFrames; ++ if (pDevice->playback.shareMode == ma_share_mode_exclusive) { ++ bufferSizeInFrames = pDevice->wasapi.actualBufferSizeInFramesPlayback; ++ } else { ++ bufferSizeInFrames = pDevice->wasapi.periodSizeInFramesPlayback; ++ } ++ hr = ma_IAudioRenderClient_GetBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, bufferSizeInFrames, (BYTE**)&pDevice->wasapi.pMappedBufferPlayback); ++ if (FAILED(hr)) { ++ return ma_result_from_HRESULT(hr); ++ } ++ pDevice->wasapi.mappedBufferPlaybackCap = bufferSizeInFrames; ++ pDevice->wasapi.mappedBufferPlaybackLen = 0; ++ ++ ma_device__read_frames_from_client(pDevice, bufferSizeInFrames, pDevice->wasapi.pMappedBufferPlayback); ++ ++ ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, pDevice->wasapi.mappedBufferPlaybackCap, 0); ++ pDevice->wasapi.pMappedBufferPlayback = NULL; ++ pDevice->wasapi.mappedBufferPlaybackCap = 0; ++ pDevice->wasapi.mappedBufferPlaybackLen = 0; ++ + hr = ma_IAudioClient_Start((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); + if (FAILED(hr)) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to start internal playback device. HRESULT = %d.", (int)hr); +@@ -23136,6 +23156,7 @@ static ma_result ma_device_stop__wasapi_nolock(ma_device* pDevice) + DWORD waitTime = pDevice->wasapi.actualBufferSizeInFramesPlayback / (pDevice->playback.internalSampleRate / 1000); + + if (pDevice->playback.shareMode == ma_share_mode_exclusive) { ++ ResetEvent((HANDLE)pDevice->wasapi.hEventPlayback); + WaitForSingleObject((HANDLE)pDevice->wasapi.hEventPlayback, waitTime); + } else { + ma_uint32 prevFramesAvailablePlayback = (ma_uint32)-1; +@@ -23415,7 +23436,23 @@ static ma_result ma_device_write__wasapi(ma_device* pDevice, const void* pFrames + ma_uint32 totalFramesProcessed = 0; + + /* Keep writing to the device until it's stopped or we've consumed all of our input. */ +- while (ma_device_get_state(pDevice) == ma_device_state_started && totalFramesProcessed < frameCount) { ++ while (totalFramesProcessed < frameCount) { ++ if (pDevice->playback.shareMode == ma_share_mode_exclusive && pDevice->wasapi.pMappedBufferPlayback == NULL) { ++ /* ++ In exclusive mode we need to wait here. Exclusive mode is weird because GetBuffer() never ++ seems to return AUDCLNT_E_BUFFER_TOO_LARGE, which is what we normally use to determine ++ whether or not we need to wait for more data. ++ */ ++ if (WaitForSingleObject((HANDLE)pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { ++ result = MA_ERROR; ++ break; /* Wait failed. Probably timed out. */ ++ } ++ } ++ ++ if (ma_device_get_state(pDevice) != ma_device_state_started) { ++ break; ++ } ++ + ma_uint32 framesRemaining = frameCount - totalFramesProcessed; + + /* +@@ -23448,18 +23485,6 @@ static ma_result ma_device_write__wasapi(ma_device* pDevice, const void* pFrames + pDevice->wasapi.pMappedBufferPlayback = NULL; + pDevice->wasapi.mappedBufferPlaybackCap = 0; + pDevice->wasapi.mappedBufferPlaybackLen = 0; +- +- /* +- In exclusive mode we need to wait here. Exclusive mode is weird because GetBuffer() never +- seems to return AUDCLNT_E_BUFFER_TOO_LARGE, which is what we normally use to determine +- whether or not we need to wait for more data. +- */ +- if (pDevice->playback.shareMode == ma_share_mode_exclusive) { +- if (WaitForSingleObject((HANDLE)pDevice->wasapi.hEventPlayback, MA_WASAPI_WAIT_TIMEOUT_MILLISECONDS) != WAIT_OBJECT_0) { +- result = MA_ERROR; +- break; /* Wait failed. Probably timed out. */ +- } +- } + } + } else { + /* We don't have a mapped data buffer so we'll need to get one. */ diff --git a/subprojects/packagefiles/miniaudio/miniaudio_wasapi_release.diff b/subprojects/packagefiles/miniaudio/miniaudio_wasapi_release.diff new file mode 100644 index 0000000..15bc2e0 --- /dev/null +++ b/subprojects/packagefiles/miniaudio/miniaudio_wasapi_release.diff @@ -0,0 +1,70 @@ +commit 90f8315432c85b3efdde3a808c3fd890fe4a0064 +Author: Andrew Opalach +Date: Mon Feb 3 13:58:49 2025 -0500 + + WASAPI: Release mapped buffer before stopping device + +diff --git a/miniaudio.h b/miniaudio.h +index 22b0e4f..2d94253 100644 +--- a/miniaudio.h ++++ b/miniaudio.h +@@ -23102,6 +23102,14 @@ static ma_result ma_device_stop__wasapi_nolock(ma_device* pDevice) + } + + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { ++ /* If we have a mapped buffer we need to release it. */ ++ if (pDevice->wasapi.pMappedBufferCapture != NULL) { ++ ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); ++ pDevice->wasapi.pMappedBufferCapture = NULL; ++ pDevice->wasapi.mappedBufferCaptureCap = 0; ++ pDevice->wasapi.mappedBufferCaptureLen = 0; ++ } ++ + hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); + if (FAILED(hr)) { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal capture device."); +@@ -23115,18 +23123,22 @@ static ma_result ma_device_stop__wasapi_nolock(ma_device* pDevice) + return ma_result_from_HRESULT(hr); + } + +- /* If we have a mapped buffer we need to release it. */ +- if (pDevice->wasapi.pMappedBufferCapture != NULL) { +- ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); +- pDevice->wasapi.pMappedBufferCapture = NULL; +- pDevice->wasapi.mappedBufferCaptureCap = 0; +- pDevice->wasapi.mappedBufferCaptureLen = 0; +- } +- + ma_atomic_bool32_set(&pDevice->wasapi.isStartedCapture, MA_FALSE); + } + + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ++ if (pDevice->wasapi.pMappedBufferPlayback != NULL) { ++ ma_silence_pcm_frames( ++ ma_offset_pcm_frames_ptr(pDevice->wasapi.pMappedBufferPlayback, pDevice->wasapi.mappedBufferPlaybackLen, pDevice->playback.internalFormat, pDevice->playback.internalChannels), ++ pDevice->wasapi.mappedBufferPlaybackCap - pDevice->wasapi.mappedBufferPlaybackLen, ++ pDevice->playback.internalFormat, pDevice->playback.internalChannels ++ ); ++ ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, pDevice->wasapi.mappedBufferPlaybackCap, 0); ++ pDevice->wasapi.pMappedBufferPlayback = NULL; ++ pDevice->wasapi.mappedBufferPlaybackCap = 0; ++ pDevice->wasapi.mappedBufferPlaybackLen = 0; ++ } ++ + /* + The buffer needs to be drained before stopping the device. Not doing this will result in the last few frames not getting output to + the speakers. This is a problem for very short sounds because it'll result in a significant portion of it not getting played. +@@ -23178,13 +23190,6 @@ static ma_result ma_device_stop__wasapi_nolock(ma_device* pDevice) + return ma_result_from_HRESULT(hr); + } + +- if (pDevice->wasapi.pMappedBufferPlayback != NULL) { +- ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, pDevice->wasapi.mappedBufferPlaybackCap, 0); +- pDevice->wasapi.pMappedBufferPlayback = NULL; +- pDevice->wasapi.mappedBufferPlaybackCap = 0; +- pDevice->wasapi.mappedBufferPlaybackLen = 0; +- } +- + ma_atomic_bool32_set(&pDevice->wasapi.isStartedPlayback, MA_FALSE); + } + -- cgit v1.2.3-101-g0448