2.0 KiB
commands/play — runPlay
Purpose
runPlay plays a file through an injected SpeakerAdapter. The CLI package
intentionally carries no platform audio binding — naming a specific speaker
binary (sox, mpv, ffplay) would couple the package to whichever the user has
installed. Instead, the function exercises argument validation, the input
load path, and the adapter dispatch, and consumers (or installer hooks) wire
the actual hardware adapter behind the SpeakerAdapter interface.
A noopSpeaker is exported so headless servers, CI, and tests can run the
play code path without audio output.
Features
- Zod-strict
PlayOptionsaccepting an injectedSpeakerAdapterand anAbortSignal. - Default
noopSpeakeradapter for headless environments. - Same input-error mapping (
AUDIO_CLI.INPUT_NOT_FOUND) as the other load-driven commands. - Adapter failures wrap as
AUDIO_CLI.PIPELINE_FAILEDwith the original cause attached.
Usage: Basic
import { AudioCLI } from "@suaveplan/audio-cli";
const cli = new AudioCLI();
await cli.play("input.wav"); // noop on a headless host
Usage: Advanced
import { runPlay } from "@suaveplan/audio-cli/commands/play";
import type { SpeakerAdapter } from "@suaveplan/audio-cli/commands/play";
const mySpeaker: SpeakerAdapter = {
async play(doc, { signal }) { /* ...write doc to a DAC... */ },
};
await runPlay(cli, "song.flac", { speaker: mySpeaker });
API Reference
runPlay(cli, input, opts?): Promise<void>PlayOptions—{ speaker?, signal? }SpeakerAdapter.play(doc, { signal? }): Promise<void>noopSpeaker: SpeakerAdapter
Implementation Notes
The function deliberately structures the failure modes so a missing speaker
falls through to the no-op rather than throwing — this matches audio play
on a headless box: argv parses, the file decodes, and the command returns
0. Real hardware bindings ship as separate adapters consumers add at
construction time via new AudioCLI({ ... }) or by passing opts.speaker
directly.