Merge branch 'seek-hardening' into dev

This commit is contained in:
daniel-c-harvey
2026-06-10 13:25:17 -04:00
@@ -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)
catch (OperationCanceledException) when (seekCts.IsCancellationRequested)
{
// 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)
{