Playing Audio
AudioResource wraps an audio source and handles transcoding via ffmpeg. It accepts a file path or a Readable stream.
import { AudioResource } from "stoatx";
import { join } from "node:path";
// From a file path (relative to your process CWD, or use import.meta.dirname to anchor to the source file)
const resource = AudioResource.from(join(import.meta.dirname, "./sounds/beep.mp3"));
// From a readable stream
import { createReadStream } from "node:fs";
const resource = AudioResource.from(createReadStream("./sounds/beep.ogg"));
Pass the resource to player.play():
player.play(resource);
Options
AudioResource.from(source, {
volume: 0.5, // Adjust volume, 1.0 = original (default)
inputType: "webm", // Override ffmpeg input format if autodetection fails
});
Full example
import { type CommandContext, SimpleCommand, Stoat, AudioPlayer, AudioResource } from "stoatx";
import { join } from "node:path";
@Stoat()
export class VoiceCommands {
private readonly players = new Map<string, AudioPlayer>();
@SimpleCommand({ name: "join", description: "Join the voice channel." })
async joinVoiceChannel(ctx: CommandContext) {
if (!ctx.message.channel?.isVoice()) {
await ctx.reply("This command can only be used in a voice channel!");
return;
}
const channel = ctx.message.channel;
const conn = await channel.join();
const player = new AudioPlayer();
conn.subscribe(player);
this.players.set(channel.id, player);
player.on("error", (err) => {
console.error(err);
this.players.delete(channel.id);
});
await ctx.reply("Joined!");
}
@SimpleCommand({ name: "play", description: "Play a sound." })
async play(ctx: CommandContext) {
const player = ctx.message.channel && this.players.get(ctx.message.channel.id);
if (!player) {
await ctx.reply("Not in a voice channel!");
return;
}
player.play(AudioResource.from(join(import.meta.dirname, "./sounds/beep.mp3")));
await ctx.reply("Playing!");
}
@SimpleCommand({ name: "leave", description: "Leave the voice channel." })
async leave(ctx: CommandContext) {
if (!ctx.message.channel?.isVoice()) return;
this.players.delete(ctx.message.channel.id);
await ctx.message.channel.leave();
await ctx.reply("Left!");
}
}