Wire Opus end-to-end playback + Backfill-Opus action (Phase 18.5)
Player picks Opus when the browser can decode it and a sidecar exists (else lossless), injecting the sidecar before stream init; seek reuses the same format. Adds the Backfill-Opus bulk API endpoint + CMS action.
This commit is contained in:
@@ -70,6 +70,36 @@ public class AudioInteropService : IAsyncDisposable
|
||||
return await InvokeJsAsync<AudioOperationResult>("DeepDrftAudio.initializeStreaming", playerId, totalStreamLength, contentType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Probes whether this browser can decode Ogg Opus via <c>decodeAudioData</c> (Safari < 18.4 cannot).
|
||||
/// Phase 18 capability gate (OQ2): the player only requests Opus when this returns true, otherwise it
|
||||
/// stays on the universal lossless path (AC7 — no listener ever gets silence over a codec gap). Probe
|
||||
/// failures degrade to <c>false</c> (assume incapable) so an interop error can never silence playback.
|
||||
/// </summary>
|
||||
public async Task<bool> CanDecodeOggOpus(string playerId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _jsRuntime.InvokeAsync<bool>("DeepDrftAudio.canDecodeOggOpus");
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hands the raw Opus seek/setup sidecar bytes (setup header + granule→byte seek index) to the JS player
|
||||
/// so the next Opus stream's decoder has them BEFORE init (the 18.4 set-before-init contract). The player
|
||||
/// parses and stashes them; <see cref="InitializeStreaming"/> applies them when it builds the Opus decoder.
|
||||
/// Must be called before <see cref="InitializeStreaming"/> on an Opus stream. Returns the parse result —
|
||||
/// a failure means the bytes were not a valid sidecar, and the caller falls back to lossless.
|
||||
/// </summary>
|
||||
public async Task<AudioOperationResult> SetOpusSidecar(string playerId, byte[] sidecarBytes)
|
||||
{
|
||||
return await InvokeJsAsync<AudioOperationResult>("DeepDrftAudio.setOpusSidecar", playerId, sidecarBytes);
|
||||
}
|
||||
|
||||
public async Task<StreamingResult> ProcessStreamingChunk(string playerId, byte[] audioChunk)
|
||||
{
|
||||
return await InvokeJsAsync<StreamingResult>("DeepDrftAudio.processStreamingChunk", playerId, audioChunk);
|
||||
|
||||
Reference in New Issue
Block a user