Files
oh-my-pi/packages/coding-agent/test/stt-recorder.test.ts
T
roboomp 26e75b251c fix(stt): selected supported linux ffmpeg input
- Probed Linux ffmpeg demuxers and fell back to ALSA when PulseAudio input is unavailable.
- Preserved recorder stderr so immediate capture failures report their real cause.
- Added regressions for ALSA selection and stderr diagnostics.

Fixes #5907
2026-07-17 20:25:21 +00:00

69 lines
2.4 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "bun:test";
import * as fs from "node:fs/promises";
import * as os from "node:os";
import * as path from "node:path";
import { startRecording } from "@oh-my-pi/pi-coding-agent/stt/recorder";
import * as toolsManager from "@oh-my-pi/pi-coding-agent/utils/tools-manager";
import * as piUtils from "@oh-my-pi/pi-utils";
let tmp = "";
async function installFakeFFmpeg(options: { demuxers: string; capture: string }): Promise<string> {
const bin = path.join(tmp, "ffmpeg");
const argsPath = path.join(tmp, "args.json");
await Bun.write(
bin,
`#!/usr/bin/env bun
const args = Bun.argv.slice(2);
if (args.includes("-demuxers")) {
await Bun.write(Bun.stdout, ${JSON.stringify(options.demuxers)});
} else {
await Bun.write(${JSON.stringify(argsPath)}, JSON.stringify(args));
${options.capture}
}
`,
);
await fs.chmod(bin, 0o755);
return bin;
}
beforeEach(async () => {
tmp = await fs.mkdtemp(path.join(os.tmpdir(), "omp-stt-recorder-"));
});
afterEach(async () => {
vi.restoreAllMocks();
await fs.rm(tmp, { recursive: true, force: true });
});
describe.skipIf(process.platform !== "linux")("Linux ffmpeg recording", () => {
it("uses ALSA when ffmpeg has no PulseAudio demuxer", async () => {
const bin = await installFakeFFmpeg({
demuxers: " D d alsa ALSA audio input\n",
capture: "await Bun.stdin.text();",
});
vi.spyOn(piUtils, "$which").mockImplementation(command => (command === "ffmpeg" ? bin : null));
vi.spyOn(toolsManager, "getToolPath").mockReturnValue(bin);
const recording = await startRecording(path.join(tmp, "recording.wav"));
await recording.stop();
const args = await Bun.file(path.join(tmp, "args.json")).text();
expect(args).toContain('"-f","alsa","-i","default"');
expect(args).not.toContain('"pulse"');
});
it("reports ffmpeg stderr when capture exits immediately", async () => {
const bin = await installFakeFFmpeg({
demuxers: " D d pulse Pulse audio input\n D d alsa ALSA audio input\n",
capture: 'await Bun.write(Bun.stderr, "Unknown input format: pulse\\n"); process.exit(234);',
});
vi.spyOn(piUtils, "$which").mockImplementation(command => (command === "ffmpeg" ? bin : null));
vi.spyOn(toolsManager, "getToolPath").mockReturnValue(bin);
await expect(startRecording(path.join(tmp, "recording.wav"))).rejects.toThrow(
"ffmpeg exited immediately (code 234): Unknown input format: pulse",
);
});
});