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; LoadProgress = 1.0;
await NotifyStateChanged(); await NotifyStateChanged();
} }
catch (OperationCanceledException) catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{ {
// Cancellation is expected during track switch or seek — propagate cleanly. // Cancellation is expected during track switch or seek — propagate cleanly.
throw; throw;
@@ -432,7 +432,8 @@ public class StreamingAudioPlayerService : AudioPlayerService, IStreamingPlayerS
_streamingCancellation?.Cancel(); _streamingCancellation?.Cancel();
await DrainActiveStreamingTaskAsync(); await DrainActiveStreamingTaskAsync();
_streamingCancellation?.Dispose(); _streamingCancellation?.Dispose();
_streamingCancellation = new CancellationTokenSource(); var seekCts = new CancellationTokenSource();
_streamingCancellation = seekCts;
try try
{ {
@@ -444,7 +445,7 @@ public class StreamingAudioPlayerService : AudioPlayerService, IStreamingPlayerS
var mediaResult = await _trackMediaClient.GetTrackMedia( var mediaResult = await _trackMediaClient.GetTrackMedia(
_currentTrackId, _currentTrackId,
byteOffset, byteOffset,
cancellationToken: _streamingCancellation.Token); cancellationToken: seekCts.Token);
if (!mediaResult.Success || mediaResult.Value == null) if (!mediaResult.Success || mediaResult.Value == null)
{ {
var technicalError = mediaResult.GetMessage() ?? "Failed to load audio from position"; var technicalError = mediaResult.GetMessage() ?? "Failed to load audio from position";
@@ -473,17 +474,22 @@ public class StreamingAudioPlayerService : AudioPlayerService, IStreamingPlayerS
BufferedChunks = 0; BufferedChunks = 0;
// Stream audio from offset // Stream audio from offset
_activeStreamingTask = StreamAudioWithEarlyPlayback(audio, _streamingCancellation.Token); _activeStreamingTask = StreamAudioWithEarlyPlayback(audio, seekCts.Token);
await _activeStreamingTask; await _activeStreamingTask;
IsSeekingBeyondBuffer = false; 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"); _logger.LogDebug("Seek beyond buffer cancelled");
if (ReferenceEquals(_streamingCancellation, seekCts))
{
IsSeekingBeyondBuffer = false; IsSeekingBeyondBuffer = false;
} }
}
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "Error during seek beyond buffer to position {Position}", seekPosition); _logger.LogError(ex, "Error during seek beyond buffer to position {Position}", seekPosition);