summaryrefslogtreecommitdiff
path: root/subprojects/packagefiles
diff options
context:
space:
mode:
authorAndrew Opalach <andrew@akon.city> 2025-02-19 13:40:38 -0500
committerAndrew Opalach <andrew@akon.city> 2025-02-19 13:40:38 -0500
commit2bee71a7e032c0972418e324bb1d7e6b02330b18 (patch)
treefa5819e9d9efe75cbc6f50d462dd0eb6bd19b6a2 /subprojects/packagefiles
parentb36f022defd8d4ec5a8c29578bb583bea05dfbb6 (diff)
downloadcamu-2bee71a7e032c0972418e324bb1d7e6b02330b18.tar.gz
camu-2bee71a7e032c0972418e324bb1d7e6b02330b18.tar.bz2
camu-2bee71a7e032c0972418e324bb1d7e6b02330b18.zip
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 <andrew@akon.city>
Diffstat (limited to 'subprojects/packagefiles')
-rw-r--r--subprojects/packagefiles/ffmpeg/meson.build30
-rw-r--r--subprojects/packagefiles/miniaudio/miniaudio_pulse_flush.diff25
-rw-r--r--subprojects/packagefiles/miniaudio/miniaudio_wasapi_clock_service.diff151
-rw-r--r--subprojects/packagefiles/miniaudio/miniaudio_wasapi_drain.diff44
-rw-r--r--subprojects/packagefiles/miniaudio/miniaudio_wasapi_exclusive_testing.diff83
-rw-r--r--subprojects/packagefiles/miniaudio/miniaudio_wasapi_release.diff70
6 files changed, 371 insertions, 32 deletions
diff --git a/subprojects/packagefiles/ffmpeg/meson.build b/subprojects/packagefiles/ffmpeg/meson.build
index 33dbd30..05940c4 100644
--- a/subprojects/packagefiles/ffmpeg/meson.build
+++ b/subprojects/packagefiles/ffmpeg/meson.build
@@ -1,11 +1,14 @@
project('ffmpeg', 'c', version: '7.1', meson_version: '>=0.57.0')
+ffmpeg_version_string = meson.project_version()
+
compiler = meson.get_compiler('c')
cpu = target_machine.cpu_family()
is_64bit = (cpu == 'x86_64' or cpu == 'aarch64')
is_debug = get_option('buildtype').startswith('debug')
is_minsize = get_option('buildtype') == 'minsize'
+is_linux = host_machine.system() == 'linux'
is_windows = host_machine.system() == 'windows'
is_msvc = compiler.get_id() == 'msvc' or compiler.get_id() == 'clang-cl'
is_mingw = is_windows and not is_msvc
@@ -45,6 +48,7 @@ endif
decoders = 'flac,mp3,mp3float,aac,opus,vorbis,alac,mjpeg,jpeg2000,gif,h264,hevc,av1,vp9,vp8'
decoders += ',pcm_f32be,pcm_s32be,pcm_s32le,pcm_s32le_planar,pcm_f32le,pcm_s24be,pcm_s24le,pcm_s16be,pcm_s16be_planar,pcm_s16le,pcm_s16le_planar'
+decoders += ',dca'
#decoders += ',pcm_dvd,mpegvideo,mpeg2video'
#decoders += ',ass,srt'
@@ -53,6 +57,7 @@ demuxers = 'flac,mp3,aac,wav,image2,mjpeg,image2pipe,image_jpeg_pipe,gif,matrosk
#demuxers += ',ass,srt'
parsers = 'aac,opus,mjpeg,jpeg2000,gif,h264,hevc,av1,vp9,vp8'
+parsers += ',dca'
#parsers += ',mpegaudio,mpegvideo,dvd_nav'
extra_options += ['--enable-zlib']
@@ -63,16 +68,24 @@ parsers += ',png'
bsfs = 'extract_extradata,mp3_header_decompress'
hwaccels = ''
-if is_windows and get_option('sink-use-vulkan')
+if get_option('sink-use-vulkan')
extra_options += ['--enable-vulkan']
hwaccels += 'h264_vulkan,hevc_vulkan,av1_vulkan'
- #extra_options += ['--enable-d3d11va', '--enable-d3d12va', '--enable-dxva2']
- #hwaccels += 'h264_dxva2,'
+elif is_windows
+ extra_options += ['--enable-d3d11va']
+ #extra_options += ['--enable-d3d11va', '--enable-dxva2']
+ hwaccels += 'h264_d3d11va,hevc_d3d11va,av1_d3d11va,vp9_d3d11va'
+ hwaccels += ',h264_d3d11va2,hevc_d3d11va2,av1_d3d11va2,vp9_d3d11va2'
+ #hwaccels += ',h264_dxva2,hevc_dxva2,av1_dxva2,vp9_dxva2'
elif is_android
extra_options += ['--enable-jni', '--enable-mediacodec']
decoders += ',h264_mediacodec,hevc_mediacodec,av1_mediacodec'
-else
- extra_options += ['--disable-vulkan', '--disable-vdpau', '--disable-vaapi']
+elif is_linux
+ extra_options += ['--enable-vaapi']
+endif
+
+if hwaccels != ''
+ extra_options += ['--enable-hwaccel=' + hwaccels]
endif
protocols = 'file,cache'
@@ -121,6 +134,7 @@ proj = ext_proj.add_project('configure',
'--enable-avutil',
'--enable-avformat',
'--enable-avcodec',
+ '--enable-avdevice',
'--enable-swresample',
'--enable-swscale',
'--disable-indevs',
@@ -129,9 +143,8 @@ proj = ext_proj.add_project('configure',
'--enable-decoder=' + decoders,
'--enable-parser=' + parsers,
'--enable-bsf=' + bsfs,
- '--enable-hwaccel=' + hwaccels,
'--enable-protocol=' + protocols,
- extra_options,
+ extra_options
],
cross_configure_options: ['--enable-cross-compile'],
verbose: true)
@@ -139,6 +152,7 @@ proj = ext_proj.add_project('configure',
avutil = proj.dependency('avutil')
avformat = proj.dependency('avformat')
avcodec = proj.dependency('avcodec')
+avdevice = proj.dependency('avdevice')
swresample = proj.dependency('swresample')
swscale = proj.dependency('swscale')
-ffmpeg_inc_dep = declare_dependency(include_directories: include_directories('.', 'build/'))
+ffmpeg_include = declare_dependency(include_directories: include_directories('.', 'build/'))
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 <andrew@akon.city>
+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 <andrew@akon.city>
+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);
+ }
+