Stream Opus/derived read path: serve from seekable disk FileStream, never a whole-file byte[]; HasOpusAsync is index-only

This commit is contained in:
daniel-c-harvey
2026-06-26 14:58:11 -04:00
parent 1e17ffc380
commit d72263aea1
5 changed files with 241 additions and 61 deletions
@@ -13,11 +13,17 @@ namespace DeepDrftContent.Processors.Opus;
/// Downstream waves call this — 18.3 wires it behind the <c>?format=</c> stream param and serves the
/// sidecar over HTTP; this wave delivers only the seam, not the HTTP surface.
/// <para>
/// Additive and non-breaking (C2): the lossless branch reads the source exactly as the existing stream
/// path does (via <see cref="TrackContentService.GetAudioBinaryAsync"/>), and an Opus request for a track
/// with no Opus artifact falls back to lossless rather than failing. Mirrors the
/// <see cref="WaveformProfileService"/> derived-artifact lookup precedent: read from the dedicated vault,
/// swallow misses to null (FileDatabase convention), let the caller decide.
/// Additive and non-breaking (C2): the lossless branch streams the source exactly as the existing read
/// path does (via <see cref="TrackContentService.OpenAudioMediaStreamAsync"/>, a non-buffering disk
/// stream), and an Opus request for a track with no Opus artifact falls back to lossless rather than
/// failing. Mirrors the <see cref="WaveformProfileService"/> derived-artifact lookup precedent: read from
/// the dedicated vault, swallow misses to null (FileDatabase convention), let the caller decide.
/// </para>
/// <para>
/// Read-path streaming: artifacts are resolved as open, seekable, disk-backed <see cref="ResolvedAudio"/>
/// handles — never whole-file <c>byte[]</c> loads — so the delivery layer streams them straight to the
/// response (Range/206 honoured by the seekable <c>FileStream</c>) without buffering a ~220 MB Opus file
/// or a ~970 MB lossless source per request.
/// </para>
/// </summary>
public sealed class TrackFormatResolver
@@ -48,10 +54,16 @@ public sealed class TrackFormatResolver
{
if (requestedFormat == AudioFormat.Opus)
{
var opus = await _fileDatabase.LoadResourceAsync<AudioBinary>(
VaultConstants.TrackOpus, OpusTranscodeService.OpusAudioKey(entryKey));
if (opus is not null)
return new ResolvedAudio(opus, MimeTypeExtensions.GetMimeType(opus.Extension), AudioFormat.Opus);
var opusVault = _fileDatabase.GetVault(VaultConstants.TrackOpus);
if (opusVault is not null)
{
// Disk-backed, seekable stream over the Opus artifact — no whole-file buffer. The caller
// owns the stream (hands it to File(...) on success, disposes on a pre-handoff throw).
var opus = await opusVault.GetEntryStreamAsync(OpusTranscodeService.OpusAudioKey(entryKey));
if (opus is not null)
return new ResolvedAudio(
opus.Stream, MimeTypeExtensions.GetMimeType(opus.Extension), AudioFormat.Opus);
}
// C2 fallback: no Opus artifact yet (legacy row, not backfilled, or transcode failed). Degrade
// to lossless rather than 404 — Opus is strictly additive; its absence never means "no audio".
@@ -63,16 +75,18 @@ public sealed class TrackFormatResolver
}
/// <summary>
/// Resolves the lossless source artifact and its real MIME — the existing read path, unchanged. Shared
/// by the explicit-lossless branch and the Opus fallback so both produce identical bytes + content-type.
/// Resolves the lossless source artifact and its real MIME as a non-buffering disk stream — the existing
/// read path. Shared by the explicit-lossless branch and the Opus fallback so both produce identical
/// bytes + content-type. The returned stream is seekable, so the delivery layer's Range→206 still works.
/// </summary>
private async Task<ResolvedAudio?> ResolveLosslessAsync(string entryKey)
{
var source = await _trackContentService.GetAudioBinaryAsync(entryKey);
var source = await _trackContentService.OpenAudioMediaStreamAsync(entryKey);
if (source is null)
return null;
return new ResolvedAudio(source, MimeTypeExtensions.GetMimeType(source.Extension), AudioFormat.Lossless);
return new ResolvedAudio(
source.Stream, MimeTypeExtensions.GetMimeType(source.Extension), AudioFormat.Lossless);
}
/// <summary>
@@ -98,13 +112,18 @@ public sealed class TrackFormatResolver
/// </summary>
public async Task<bool> HasOpusAsync(string entryKey)
{
var audio = await _fileDatabase.LoadResourceAsync<AudioBinary>(
VaultConstants.TrackOpus, OpusTranscodeService.OpusAudioKey(entryKey));
if (audio is null)
// Index-only existence — never read a file body. The opus-status admin endpoint calls this in a loop
// over the entire catalogue, so a body load here would stream the whole library's audio sequentially.
// HasIndexEntry is a pure in-memory index lookup (no disk read, no allocation per track).
var opusVault = _fileDatabase.GetVault(VaultConstants.TrackOpus);
if (opusVault is null)
return false;
var sidecar = await _fileDatabase.LoadResourceAsync<MediaBinary>(
VaultConstants.TrackOpus, OpusTranscodeService.OpusSidecarKey(entryKey));
return sidecar is not null;
if (!await opusVault.HasIndexEntry(OpusTranscodeService.OpusAudioKey(entryKey)))
return false;
// Both halves required: audio without the seek/setup sidecar is unseekable, so a half-derived track
// counts as not-having-Opus (the same completeness rule the Backfill-Opus pass enqueues against).
return await opusVault.HasIndexEntry(OpusTranscodeService.OpusSidecarKey(entryKey));
}
}