Files
skills/docs/media/audio/audio-codec-ffmpeg-wasm/src/decode/decode-pipeline.md
2026-05-29 08:20:56 +01:00

2.8 KiB

decode-pipeline.ts

(no submodules)

Purpose

This module owns the pure logic of the decode pipeline: format sniffing from magic bytes, the ffmpeg argument list that emits f32le interleaved samples to a MEMFS scratch file, and the deinterleave step that produces per-channel Float32Arrays for the DecodeResult shape. The pipeline runs entirely through the supplied WorkerHost so cancellation, timeouts, and OOM detection are inherited from a single source of truth.

Features

  • sniffFormat(bytes) recognises WAV, MP3 (ID3v2 + frame-sync), Ogg (Vorbis vs Opus by inspecting the bos packet), FLAC, AAC ADTS, and WebM/EBML headers.
  • deinterleave(samples, channels) returns channels equal-length Float32Arrays.
  • runDecode(opts) orchestrates writeFile → run → readFile via WorkerHost.submitFfmpeg and returns a normalised DecodeResult.
  • Default sample rate (48 000) and channel count (2) for callers that do not pre-probe their input.

Usage: Basic

import { runDecode } from "@suaveplan/audio-codec-ffmpeg-wasm/decode/decode-pipeline";

const result = await runDecode({ host, bytes, format: "wav" });
console.log(result.channelData.length);  // channel count
console.log(result.channelData[0].length); // frame count
console.log(result.sampleRate);

Usage: Advanced

import {
    runDecode,
    sniffFormat,
    deinterleave,
} from "@suaveplan/audio-codec-ffmpeg-wasm/decode/decode-pipeline";

const fmt = sniffFormat(bytes);
if (!fmt) throw new Error("unsupported");
const result = await runDecode({
    host,
    bytes,
    format: fmt as "wav" | "mp3" | "ogg" | "opus" | "flac" | "aac" | "webm",
    sampleRate: 44_100,
    channels: 1,
    timeoutMs: 30_000,
    signal: controller.signal,
});
// Drop a deinterleaved view for downstream processing
const ch = deinterleave(new Float32Array([0, 1, 2, 3]), 2);

API Reference

  • DEFAULT_SAMPLE_RATE: 48_000.
  • DEFAULT_CHANNELS: 2.
  • sniffFormat(bytes: Uint8Array): string | undefined.
  • deinterleave(interleaved: Float32Array, channels: number): Float32Array[].
  • runDecode(opts: DecodePipelineOptions): Promise<DecodeResult>.

Implementation Notes

The deinterleave step copies the raw Uint8Array through a Float32Array view to honour the f32le wire layout and then takes a .slice() so the returned arrays own their own backing buffer — callers can transfer or mutate them without aliasing the worker output. The pipeline never silently catches MEMFS cleanup failures here; the host's submitFfmpeg handles try/finally cleanup and logs any delete failures via the injected logger. A non-zero ffmpeg exit is mapped to AUDIO_CODEC_FFMPEG_WASM.DECODE_FAILED inside the worker host so this module never sees it directly.