Files
OmniRoute/tests/unit/guardrails/videoBridgeAudioExtraction.test.ts
Diego Rodrigues de Sa e Souza 5fcd39bd6f feat(video): orchestrate Audio Bridge STT with one-download budgets (FU-06, #11654) (#12012)
FU-06 (Audio Bridge STT orchestration): one download, two extractions — takes already-downloaded video bytes and extracts bounded mono 16kHz PCM WAV via the loopback broker's new mode=audio operation, sharing the exact same queue/deadline/byte budgets as the frame path. Dual opt-in (operator setting default false + per-request), only reaches the STT call when both are on.

Rebased onto the tip after sibling #12011 (subtitle mode) landed first, both touching the same broker route/client — combined additively so frames/audio/subtitles all share the one extractionQueue singleton. Re-validated: 59/59 focused tests pass.
2026-08-29 19:34:57 -03:00

141 lines
4.4 KiB
TypeScript

import assert from "node:assert/strict";
import { writeFile } from "node:fs/promises";
import test from "node:test";
import {
VIDEO_AUDIO_CHANNELS,
VIDEO_AUDIO_SAMPLE_RATE_HZ,
extractVideoAudioFromBytes,
} from "../../../src/lib/guardrails/videoBridgeAudioExtraction.ts";
import type { VideoCommandRunner } from "../../../src/lib/guardrails/videoBridgeRuntime.ts";
test("extracts bounded mono 16kHz WAV bytes and reuses the probed duration", async () => {
const calls: Array<{ executable: string; args: string[] }> = [];
const runner: VideoCommandRunner = async (executable, args) => {
calls.push({ executable, args: [...args] });
if (executable === "ffprobe") {
return {
stdout: JSON.stringify({
format: { duration: "4.5", format_name: "mp4" },
streams: [{ index: 0, codec_type: "video", width: 640, height: 360 }],
}),
stderr: "",
};
}
await writeFile(args.at(-1) ?? "", Buffer.from("RIFF....WAVEfmt "));
return { stdout: "", stderr: "" };
};
const result = await extractVideoAudioFromBytes(Buffer.from("fake video bytes"), {
maxDurationSeconds: 600,
runner,
timeoutMs: 5_000,
});
assert.equal(result.durationSeconds, 4.5);
assert.equal(result.channels, VIDEO_AUDIO_CHANNELS);
assert.equal(result.sampleRateHz, VIDEO_AUDIO_SAMPLE_RATE_HZ);
assert.match(result.dataUri, /^data:audio\/wav;base64,/);
assert.deepEqual(
Buffer.from(result.dataUri.split(",", 2)[1], "base64"),
Buffer.from("RIFF....WAVEfmt ")
);
const ffmpegCall = calls.find((call) => call.executable === "ffmpeg");
assert.ok(ffmpegCall, "ffmpeg must be invoked");
assert.deepEqual(ffmpegCall!.args.slice(ffmpegCall!.args.indexOf("-map"), ffmpegCall!.args.indexOf("-map") + 2), [
"-map",
"0:a:0",
]);
assert.deepEqual(ffmpegCall!.args.slice(ffmpegCall!.args.indexOf("-ac"), ffmpegCall!.args.indexOf("-ac") + 2), [
"-ac",
"1",
]);
assert.deepEqual(ffmpegCall!.args.slice(ffmpegCall!.args.indexOf("-ar"), ffmpegCall!.args.indexOf("-ar") + 2), [
"-ar",
"16000",
]);
// No shell string ever built — every arg is a discrete array element (Hard Rule #13).
assert.equal(
ffmpegCall!.args.some((arg) => arg.includes(";") || arg.includes("&&")),
false
);
});
test("propagates the shared probe's duration cap instead of re-validating it", async () => {
const runner: VideoCommandRunner = async (executable) => {
if (executable === "ffprobe") {
return {
stdout: JSON.stringify({
format: { duration: "700", format_name: "mp4" },
streams: [{ index: 0, codec_type: "video", width: 640, height: 360 }],
}),
stderr: "",
};
}
throw new Error("ffmpeg must not run once the shared duration cap already rejected the file");
};
await assert.rejects(
() =>
extractVideoAudioFromBytes(Buffer.from("fake video bytes"), {
maxDurationSeconds: 600,
runner,
timeoutMs: 5_000,
}),
/maximum duration/
);
});
test("rejects a WAV output that exceeds the configured byte cap", async () => {
const runner: VideoCommandRunner = async (executable, args) => {
if (executable === "ffprobe") {
return {
stdout: JSON.stringify({
format: { duration: "4", format_name: "mp4" },
streams: [{ index: 0, codec_type: "video", width: 640, height: 360 }],
}),
stderr: "",
};
}
await writeFile(args.at(-1) ?? "", Buffer.alloc(16));
return { stdout: "", stderr: "" };
};
await assert.rejects(
() =>
extractVideoAudioFromBytes(Buffer.from("fake video bytes"), {
maxDurationSeconds: 600,
maxOutputBytes: 8,
runner,
timeoutMs: 5_000,
}),
/byte limit exceeded/
);
});
test("propagates ffmpeg's own failure when the container has no audio stream", async () => {
const runner: VideoCommandRunner = async (executable) => {
if (executable === "ffprobe") {
return {
stdout: JSON.stringify({
format: { duration: "4", format_name: "mp4" },
streams: [{ index: 0, codec_type: "video", width: 640, height: 360 }],
}),
stderr: "",
};
}
throw new Error("Stream map '0:a:0' matches no streams");
};
await assert.rejects(
() =>
extractVideoAudioFromBytes(Buffer.from("fake video bytes"), {
maxDurationSeconds: 600,
runner,
timeoutMs: 5_000,
}),
/matches no streams/
);
});