Embedded quickstart
Install FFmpeg 9 and @remedia/node, then play audio into a Discord voice channel from your Node.js bot.
Run the engine inside your bot's Node.js process. You need Node.js 22.18 or newer, a Discord bot token, and permission to join and speak in a test voice channel.
1. Install FFmpeg 9
The engine needs FFmpeg 9 shared libraries on this machine. The official installer is the quickest way and needs no environment variables afterwards:
curl -fsSL https://remedia.twlite.dev/install.sh | sh -s -- --ffmpeg-onlyOn Windows PowerShell, and for other options, see Install FFmpeg 9.
2. Install the package
npm install @remedia/node discord.js3. Check that the engine starts
node --input-type=module -e "import { Remedia } from '@remedia/node'; const engine = await Remedia.create(); await engine.close(); console.log('Remedia native runtime OK')"If this prints Remedia native runtime OK, FFmpeg was found and the addon loaded. Otherwise the error
lists every location that was tried. See native library troubleshooting.
4. Play into a voice channel
Your bot keeps its own Gateway connection. Give Remedia a function that sends a Gateway payload for a
guild, and forward every raw packet to remedia.receive(). This example uses discord.js:
import { Client, Events, GatewayIntentBits } from 'discord.js';
import { Remedia } from '@remedia/node';
const discord = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates],
});
const remedia = await Remedia.create({
send(guildId, payload) {
discord.guilds.cache.get(guildId)?.shard.send(payload);
},
});
discord.on(Events.Raw, (packet) => remedia.receive(packet));
discord.once(Events.ClientReady, async (ready) => {
const voice = remedia.createDiscordSession({
guildId: '123456789012345678',
channelId: '234567890123456789',
userId: ready.user.id,
});
try {
await voice.connect();
await voice.play({ url: 'https://example.com/audio.mp3' });
await voice.wait();
} finally {
await remedia.close();
discord.destroy();
}
});
await discord.login(process.env.DISCORD_TOKEN);Export DISCORD_TOKEN before running the example. It plays one source, then closes the engine and Gateway client. In a long-running bot, keep both clients open until application shutdown.
connect() resolves once the voice connection is ready. play() resolves once the audio stream is
open and playback has started, and wait() resolves when it ends.
Snowflake IDs are always strings. Replace the guild and channel IDs with real ones, and use a URL or file path your bot may read.
5. Control playback
await voice.pause();
await voice.resume();
await voice.seek(30_000); // milliseconds
await voice.setVolume(0.8); // 0 to 2, default 1
await voice.filters.set('bass=gain=6'); // FFmpeg audio filtergraph
await voice.stop(); // stops playback and stays in the channel
await voice.disconnect(); // leaves the channelAlways call await remedia.close() when your process shuts down. It stops playback and releases
native resources.
Playback without Discord is silent
remedia.createPlaybackSession() decodes audio into a null output. It is useful for tests and for
checking that a file decodes, but it does not play through speakers. Audio is only audible through
a Discord voice session.
Next steps
@remedia/nodereference: Buffer and Readable inputs, events, diagnostics, probing.- Using
@remedia/client: the same session API with remote nodes and node pools. - Events and hooks, Media sources and probing.