From 6fe76636676ef6945e8c6c6a53203a197052b6fb Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Wed, 10 Jun 2026 10:55:49 -0400 Subject: [PATCH] =?UTF-8?q?fix:=20harden=20seek=20=E2=80=94=20timeout=20no?= =?UTF-8?q?=20longer=20swallowed=20as=20cancel,=20rapid=20seek-on-seek=20n?= =?UTF-8?q?o=20longer=20clears=20active=20seek=20flag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/StreamingAudioPlayerService.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/DeepDrftPublic.Client/Services/StreamingAudioPlayerService.cs b/DeepDrftPublic.Client/Services/StreamingAudioPlayerService.cs index d77b8da..cc15e25 100644 --- a/DeepDrftPublic.Client/Services/StreamingAudioPlayerService.cs +++ b/DeepDrftPublic.Client/Services/StreamingAudioPlayerService.cs @@ -327,7 +327,7 @@ public class StreamingAudioPlayerService : AudioPlayerService, IStreamingPlayerS LoadProgress = 1.0; await NotifyStateChanged(); } - catch (OperationCanceledException) + catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { // Cancellation is expected during track switch or seek — propagate cleanly. throw; @@ -432,7 +432,8 @@ public class StreamingAudioPlayerService : AudioPlayerService, IStreamingPlayerS _streamingCancellation?.Cancel(); await DrainActiveStreamingTaskAsync(); _streamingCancellation?.Dispose(); - _streamingCancellation = new CancellationTokenSource(); + var seekCts = new CancellationTokenSource(); + _streamingCancellation = seekCts; try { @@ -444,7 +445,7 @@ public class StreamingAudioPlayerService : AudioPlayerService, IStreamingPlayerS var mediaResult = await _trackMediaClient.GetTrackMedia( _currentTrackId, byteOffset, - cancellationToken: _streamingCancellation.Token); + cancellationToken: seekCts.Token); if (!mediaResult.Success || mediaResult.Value == null) { var technicalError = mediaResult.GetMessage() ?? "Failed to load audio from position"; @@ -473,16 +474,21 @@ public class StreamingAudioPlayerService : AudioPlayerService, IStreamingPlayerS BufferedChunks = 0; // Stream audio from offset - _activeStreamingTask = StreamAudioWithEarlyPlayback(audio, _streamingCancellation.Token); + _activeStreamingTask = StreamAudioWithEarlyPlayback(audio, seekCts.Token); await _activeStreamingTask; IsSeekingBeyondBuffer = false; } catch (OperationCanceledException) { - // Another seek or stop interrupted this one + // Another seek or stop interrupted this one. Only clear the flag if we are + // still the active seek — if _streamingCancellation has been replaced, a + // newer seek is in progress and owns the flag. _logger.LogDebug("Seek beyond buffer cancelled"); - IsSeekingBeyondBuffer = false; + if (ReferenceEquals(_streamingCancellation, seekCts)) + { + IsSeekingBeyondBuffer = false; + } } catch (Exception ex) {