refactor(audio): extract IFormatDecoder/WavFormatDecoder and wire Content-Type to JS format selection

StreamDecoder is now format-agnostic; WavFormatDecoder delegates to WavUtils; contentType flows C# to JS.
This commit is contained in:
daniel-c-harvey
2026-06-11 06:08:09 -04:00
parent f8186fb7c7
commit 0b0bcb3dee
9 changed files with 308 additions and 105 deletions
@@ -11,12 +11,20 @@ public class TrackMediaResponse : IDisposable
{
public Stream Stream { get; }
public long ContentLength { get; }
/// <summary>
/// The response media type (e.g. "audio/wav", "audio/mpeg"). Drives format-decoder
/// selection on the JS side. Falls back to "audio/wav" when the server omits the header.
/// </summary>
public string ContentType { get; }
private readonly HttpResponseMessage _response;
public TrackMediaResponse(Stream stream, long contentLength, HttpResponseMessage response)
public TrackMediaResponse(Stream stream, long contentLength, string contentType, HttpResponseMessage response)
{
Stream = stream;
ContentLength = contentLength;
ContentType = contentType;
_response = response;
}
@@ -61,11 +69,14 @@ public class TrackMediaClient
response.EnsureSuccessStatusCode();
var contentLength = response.Content.Headers.ContentLength ?? 0;
// Default to WAV when the server omits the header — the only format shipping
// today — so the JS factory always receives a usable media type.
var contentType = response.Content.Headers.ContentType?.MediaType ?? "audio/wav";
var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
// TrackMediaResponse takes ownership of both stream and response;
// do NOT dispose response here — the caller disposes via TrackMediaResponse.Dispose().
return ApiResult<TrackMediaResponse>.CreatePassResult(new TrackMediaResponse(stream, contentLength, response));
return ApiResult<TrackMediaResponse>.CreatePassResult(new TrackMediaResponse(stream, contentLength, contentType, response));
}
catch (Exception e)
{