Phase 21.3: seek-back-past-window refill + clean refill-failure recovery

Seek-back past the retained tail reuses the existing seek-beyond-buffer
Range path (per-path resolver). A failed refill now halts the scheduler
into a paused-but-loaded state (AC6) instead of a silent false end.
This commit is contained in:
daniel-c-harvey
2026-06-23 23:43:17 -04:00
parent 121983b19d
commit af4cb186f3
5 changed files with 370 additions and 13 deletions
@@ -183,6 +183,18 @@ public class AudioInteropService : IAsyncDisposable
return await InvokeJsAsync<AudioOperationResult>("DeepDrftAudio.reinitializeFromOffset", playerId, totalStreamLength, seekPosition);
}
/// <summary>
/// Phase 21.3 / AC6 clean-failure recovery: after a window-miss refill (seek-back past the
/// retained tail) fails its Range fetch or reinit, halt the starved scheduler and leave the
/// player paused-but-loaded at <paramref name="seekPosition"/> so no silent false end fires and a
/// retry is possible. Routes through <see cref="InvokeJsAsync{T}"/> so an interop failure during
/// recovery still yields a failure result rather than throwing into the seek path.
/// </summary>
public async Task<AudioOperationResult> RecoverFromFailedRefill(string playerId, double seekPosition)
{
return await InvokeJsAsync<AudioOperationResult>("DeepDrftAudio.recoverFromFailedRefill", playerId, seekPosition);
}
public async Task<AudioOperationResult> SetVolumeAsync(string playerId, double volume)
{
return await InvokeJsAsync<AudioOperationResult>("DeepDrftAudio.setVolume", playerId, volume);