From eb9ccb347022263004d8f0d79bd623c247bc87ae Mon Sep 17 00:00:00 2001 From: BlackSpirits Date: Tue, 15 Sep 2026 19:44:56 +0200 Subject: [PATCH] Retain WinMM buffers when teardown cannot reclaim them --- .../Ffmpeg/Audio/WaveOutAudioSink.cs | 46 ++++++++++++++++--- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/src/ui/Logic/VideoPlayers/Ffmpeg/Audio/WaveOutAudioSink.cs b/src/ui/Logic/VideoPlayers/Ffmpeg/Audio/WaveOutAudioSink.cs index efcfdb70cd..2b87e49c1d 100644 --- a/src/ui/Logic/VideoPlayers/Ffmpeg/Audio/WaveOutAudioSink.cs +++ b/src/ui/Logic/VideoPlayers/Ffmpeg/Audio/WaveOutAudioSink.cs @@ -1,3 +1,4 @@ +using Nikse.SubtitleEdit.Logic.Config; using System; using System.Runtime.InteropServices; using System.Runtime.Versioning; @@ -161,7 +162,10 @@ public void Open(int sampleRate, int channels) { lock (_lock) { - CloseCore(); + if (!CloseCore()) + { + throw new InvalidOperationException("Previous waveOut device could not be closed safely"); + } var format = new WaveFormatEx { @@ -412,20 +416,43 @@ public void Resume() } } - private void CloseCore() + /// + /// Releases native resources only after WinMM confirms it no longer owns any waveform + /// buffers. A failure keeps the complete device/buffer/event boundary alive so Dispose can + /// be retried instead of freeing memory that the driver may still reference. + /// Called under . + /// + private bool CloseCore() { if (_device != IntPtr.Zero) { - waveOutReset(_device); + var resetResult = waveOutReset(_device); + if (resetResult != MmSysErrNoError) + { + Se.LogError($"ffmpeg player: waveOutReset failed during teardown with error {resetResult}; retaining WinMM resources"); + return false; + } + if (_headers != IntPtr.Zero) { for (var i = 0; i < BufferCount; i++) { - waveOutUnprepareHeader(_device, (IntPtr)((WaveHdr*)_headers + i), (uint)sizeof(WaveHdr)); + var unprepareResult = waveOutUnprepareHeader(_device, (IntPtr)((WaveHdr*)_headers + i), (uint)sizeof(WaveHdr)); + if (unprepareResult != MmSysErrNoError) + { + Se.LogError($"ffmpeg player: waveOutUnprepareHeader failed during teardown with error {unprepareResult}; retaining WinMM resources"); + return false; + } } } - waveOutClose(_device); + var closeResult = waveOutClose(_device); + if (closeResult != MmSysErrNoError) + { + Se.LogError($"ffmpeg player: waveOutClose failed during teardown with error {closeResult}; retaining WinMM resources"); + return false; + } + _device = IntPtr.Zero; } @@ -443,9 +470,16 @@ private void CloseCore() if (_doneEvent != IntPtr.Zero) { - CloseHandle(_doneEvent); + if (!CloseHandle(_doneEvent)) + { + Se.LogError($"ffmpeg player: CloseHandle failed during waveOut teardown with error {Marshal.GetLastWin32Error()}; retaining event handle"); + return false; + } + _doneEvent = IntPtr.Zero; } + + return true; } public void Dispose()