Stream the waveform compute so large uploads no longer buffer the whole file (Wave 2 OOM)
This commit is contained in:
@@ -112,10 +112,10 @@ public class ReleaseController : ControllerBase
|
||||
}
|
||||
|
||||
// POST api/release/{id}/mix/waveform ([ApiKeyAuthorize], no body)
|
||||
// Server-side trigger: fetch the Mix's track audio from the vault, compute a duration-derived high-res
|
||||
// waveform via ComputeAndStoreHighResAsync, store it in the track-waveforms vault, and set
|
||||
// MixMetadata.WaveformEntryKey. 404 when the release is missing or has no stored audio; 500 on
|
||||
// compute/storage failure. Declared before "{id:long}".
|
||||
// Server-side trigger: stream the Mix's track audio from the vault, compute a duration-derived
|
||||
// high-res waveform, store it in the track-waveforms vault, and set MixMetadata.WaveformEntryKey.
|
||||
// 404 when the release is missing or has no stored audio; 500 on compute/storage failure. Declared
|
||||
// before "{id:long}".
|
||||
[ApiKeyAuthorize]
|
||||
[HttpPost("{id:long}/mix/waveform")]
|
||||
public async Task<ActionResult> GenerateMixWaveform(long id, CancellationToken ct = default)
|
||||
|
||||
@@ -756,15 +756,18 @@ public class TrackController : ControllerBase
|
||||
[HttpPost("{trackId}/waveform")]
|
||||
public async Task<ActionResult> GenerateWaveform(string trackId)
|
||||
{
|
||||
var audio = await _trackContentService.GetAudioBinaryAsync(trackId);
|
||||
if (audio is null)
|
||||
// Streaming compute (Wave 2): the WAV is read from the vault in bounded chunks, never buffered
|
||||
// whole. Tri-state: null = no vault audio (404), false = present but uncomputable / write failed
|
||||
// (500), true = stored.
|
||||
var stored = await _waveformProfileService.ComputeAndStoreProfileStreamingAsync(
|
||||
_ => _trackContentService.OpenAudioStreamAsync(trackId), trackId, HttpContext.RequestAborted);
|
||||
if (stored is null)
|
||||
{
|
||||
_logger.LogWarning("GenerateWaveform: no audio in vault for {TrackId}", trackId);
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var stored = await _waveformProfileService.ComputeAndStoreAsync(audio.Buffer, trackId);
|
||||
if (!stored)
|
||||
if (stored is false)
|
||||
{
|
||||
_logger.LogError("GenerateWaveform: profile computation/storage failed for {TrackId}", trackId);
|
||||
return StatusCode(500, "Failed to generate waveform profile.");
|
||||
@@ -784,16 +787,27 @@ public class TrackController : ControllerBase
|
||||
[HttpPost("{trackId}/waveform/high-res")]
|
||||
public async Task<ActionResult> GenerateHighResWaveform(string trackId)
|
||||
{
|
||||
var audio = await _trackContentService.GetAudioBinaryAsync(trackId);
|
||||
if (audio is null)
|
||||
// The high-res bucket count is duration-derived. Read the duration from the vault index metadata
|
||||
// (no body load); its absence means the track has no vault audio → 404.
|
||||
var duration = await _trackContentService.GetAudioDurationAsync(trackId);
|
||||
if (duration is null)
|
||||
{
|
||||
_logger.LogWarning("GenerateHighResWaveform: no audio in vault for {TrackId}", trackId);
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var stored = await _waveformProfileService.ComputeAndStoreHighResAsync(
|
||||
audio.Buffer, trackId, audio.Duration);
|
||||
if (!stored)
|
||||
// Streaming compute (Wave 2): bounded read of the vault WAV. Tri-state mapping as in
|
||||
// GenerateWaveform — null (entry vanished between the metadata read and the compute) → 404.
|
||||
var stored = await _waveformProfileService.ComputeAndStoreHighResStreamingAsync(
|
||||
_ => _trackContentService.OpenAudioStreamAsync(trackId), trackId, duration.Value,
|
||||
HttpContext.RequestAborted);
|
||||
if (stored is null)
|
||||
{
|
||||
_logger.LogWarning("GenerateHighResWaveform: no audio in vault for {TrackId}", trackId);
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (stored is false)
|
||||
{
|
||||
_logger.LogError("GenerateHighResWaveform: computation/storage failed for {TrackId}", trackId);
|
||||
return StatusCode(500, "Failed to generate high-res waveform datum.");
|
||||
|
||||
Reference in New Issue
Block a user