
Low-latency audio node written in Rust. It exposes a HTTP API to create/manage audio players and a WebSocket that streams raw PCM for clients (e.g., Discord bots). An example Discord.js client is included in examples/discord-js-bot.
Features
- HTTP API for creating/controlling players
- WebSocket PCM stream (48 kHz, stereo, 16-bit, 20 ms frames)
- Optional resolving/downloading for YouTube/Spotify/SoundCloud links via yt-dlp
- Allow/block URL patterns via regex
- Lightweight EQ and volume filters
- Minimal authentication via static password header
- First-run auto-download of
yt-dlp
andffmpeg
into a user cache (~/.resonix/bin
) keeping the executable slim - Automatic cleanup of downloaded/transcoded temp audio files when not looping; best‑effort cleanup on shutdown
Early preview. APIs may evolve. See License (BSD-3-Clause).
- Build
- Install Rust (stable). Then build:
- Windows PowerShell
cargo build --release
- Windows PowerShell
- Configure (optional)
- Copy
Resonix.toml
to your working directory and tweak values (lowercaseresonix.toml
is also supported). See Configuration below.
- Run
- Start the server binary from the repository root. Default bind:
0.0.0.0:2333
.
- Try it
- Create a player for a URL, then connect a WS client to stream PCM.
Base URL: http://<host>:<port>
(default http://127.0.0.1:2333
). If a password is set in config, include header: Authorization: <password>
.
Endpoints
-
POST
/players
→ Create player- Request JSON:
{ "id": string, "uri": string }
- Behavior: Validates against allow/block patterns. If resolver is enabled, attempts to resolve page URLs (YouTube/Spotify/SoundCloud) to a direct audio file before playback.
- Responses:
201 { "id": string }
,403
(blocked),409
(exists),400
(bad input)
- Request JSON:
-
POST
/players/{id}/play
→ Resume playback- Response:
204
or404
- Response:
-
POST
/players/{id}/pause
→ Pause playback- Response:
204
or404
- Response:
-
PATCH
/players/{id}/filters
→ Update filters- Request JSON:
{ "volume"?: number(0.0..5.0), "eq"?: [{ "band": 0..4, "gain_db": number }] }
- Response:
204
or404
- Request JSON:
-
DELETE
/players/{id}
→ Stop and remove player- Response:
204
or404
- Response:
-
GET
/resolve?url=<encoded>
→ Resolve to a direct audio file (if resolver enabled)- Responses:
200 <path-or-url>
,400
on errors,400
if resolver disabled
- Responses:
WebSocket stream
- URL:
ws://<host>:<port>/players/{id}/ws
- Frames: binary, interleaved little-endian i16 PCM
- Sample rate: 48,000 Hz
- Channels: 2 (stereo)
- Frame size: 960 samples/channel (20 ms), 3,840 bytes per packet
- A single silent priming frame is sent first
The server loads configuration from resonix.toml
(lowercase) or Resonix.toml
in the current working directory. Environment variables can override some resolver options.
TOML sections and keys
-
[server]
host
(string) → default"0.0.0.0"
port
(u16) → default2333
password
(string, optional) → if set, all requests must include headerAuthorization: <password>
-
[logging]
clean_log_on_start
(bool) → truncate.logs/latest.log
on startup; defaulttrue
-
[resolver]
enabled
(bool) → defaultfalse
ytdlp_path
(string) → default"yt-dlp"
(can be overridden byYTDLP_PATH
env)ffmpeg_path
(string, optional) → default"ffmpeg"
(can be overridden byFFMPEG_PATH
env)timeout_ms
(u64) → default20000
preferred_format
(string) → default"140"
(m4a)allow_spotify_title_search
(bool) → defaulttrue
(resolves Spotify URLs via title search)
-
[spotify]
client_id
(string, optional) → Either the literal client id OR the NAME of an env var containing it.client_secret
(string, optional) → Either the literal client secret OR the NAME of an env var containing it.- Behavior: If set to a string that matches an existing environment variable, that env var’s value is used. Otherwise the string is treated as the literal credential. If not provided, defaults to reading
SPOTIFY_CLIENT_ID
andSPOTIFY_CLIENT_SECRET
from the environment.
-
[sources]
allowed
(array of regex strings) → if empty, all allowed unless blockedblocked
(array of regex strings) → takes priority over allowed
Environment overrides
RESONIX_RESOLVE=1|true
→ enable resolverYTDLP_PATH=...
→ explicit path toyt-dlp
FFMPEG_PATH=...
→ explicit path toffmpeg
RESOLVE_TIMEOUT_MS=...
→ override timeoutSPOTIFY_CLIENT_ID
/SPOTIFY_CLIENT_SECRET
→ fallback env vars if[spotify]
section is omitted.- You can also set custom env var names and reference them from the config, e.g.:
client_id = "MY_APP_SPOTIFY_ID"
and then setMY_APP_SPOTIFY_ID
in your.env
or environment.
- You can also set custom env var names and reference them from the config, e.g.:
- (legacy)
RESONIX_EMBED_EXTRACT_DIR
is ignored now; tools are stored in~/.resonix/bin
(runtime exportRESONIX_TOOLS_DIR
shows the resolved directory)
Runtime export (informational)
- On startup the resolved paths are placed into
RESONIX_YTDLP_BIN
/RESONIX_FFMPEG_BIN
env vars for child processes spawned by the node. Normally you do not need to set these manually.
On startup Resonix checks for yt-dlp
and ffmpeg
.
Resolution order (per tool):
- Explicit env (
YTDLP_PATH
/FFMPEG_PATH
) - Config (
resolver.ytdlp_path
/resolver.ffmpeg_path
) - Auto-managed download to
~/.resonix/bin
(created if missing)
If only one tool is missing, only that one is downloaded. Existing executables are left untouched. Delete a file to force re-download of the latest release.
macOS: ffmpeg
is not auto-downloaded (install via Homebrew: brew install ffmpeg
).
Notes
- The resolver downloads temporary audio files using
yt-dlp
. Ensure sufficient disk space and legal use in your jurisdiction. - For sources needing remux/extraction,
ffmpeg
is required. - Cleanup: If loop mode is not enabled (neither
track
norqueue
), Resonix deletes any temporary audio file it created for the finished track. On process shutdown, Resonix also best‑effort removes leftover temp files with theresonix_
prefix from the OS temp directory.
See examples/discord-js-bot for a minimal Discord.js bot that connects to the node over WebSocket and plays a URL.
Prereqs
- Rust toolchain,
cargo
- Optional:
yt-dlp
in PATH for resolver;ffmpeg
recommended (used by yt-dlp to extract consistent audio formats)
Common tasks
- Format:
cargo fmt
(configured viarustfmt.toml
) - Build debug:
cargo build
- Build release:
cargo build --release
Project layout
src/
→ application codesrc/api/handlers.rs
→ HTTP/WS handlerssrc/middleware/auth.rs
→ simple auth middleware (Authorization header equals password)src/config/
→ config loading and effective configsrc/audio/
→ decoding, DSP, playerResonix.toml
→ example configuration
Basic flags:
--version
,-V
,-version
→ print version and exit--init-config
→ createResonix.toml
in the current directory (fails if it already exists) and exit
If no flag is passed, the server starts normally.
Report vulnerabilities via GitHub Security Advisories (see SECURITY.md). Do not open public issues for sensitive reports.
BSD 3-Clause. See LICENSE.