VLX_AudioBridge (formerly Ermete) is a bi-directional audio gateway designed for Linux servers. It bridges the gap between Discord voice channels, web-based overlays, and streaming protocols (SRT). It allows you to inject audio from web sources (overlays) into Discord and simultaneously extract, mix, and stream Discord voice chat to an external media server via SRT.
The idea, the logics, the architecture, reviews, validation are made in VirusLox, but the code is 95% generated by Gemini.
The bridge operates in two concurrent directions:
-
Ingress (Overlay -> Discord):
- Spawns headless Chromium instances for configured overlay URLs.
- Routes browser audio to a dedicated Pipewire Virtual Sink.
- Captures audio via PortAudio, encodes it to Opus, and streams it to the Discord voice channel.
-
Egress (Discord -> SRT Stream):
- Captures incoming Opus packets from Discord users.
- Mixes audio streams in real-time.
- Filters out specific users (e.g., the bot itself or admin accounts) based on configuration.
- Pipes the mixed PCM audio to FFmpeg for encoding and SRT transmission.
VLX_AudioBridge/
├── main.go # Entry point: config load, bot init, system checks
├── AudioBridge.yaml # Centralized configuration
├── internal/
│ ├── config/
│ │ └── config.go # YAML Config Parser
│ ├── bot/
│ │ └── bot.go # Discord session, commands (join/leave/shutdown)
│ ├── stream/ # [Discord -> SRT]
│ │ ├── packet_handler.go # Opus packet receiver and SSRC handling
│ │ ├── mixer.go # PCM Soft-Clipping Mixer
│ │ └── ffmpeg_srt.go # FFmpeg process wrapper (stdin pipe)
│ ├── overlay/ # [Overlay -> Discord]
│ │ ├── browser_manager.go # Headless Chromium manager
│ │ └── audio_capture.go # PortAudio capture from Pipewire Monitor
│ └── system/
│ └── pipewire.go # Virtual Sink automation (pactl/pw-cli)
├── scripts/
│ └── vlx_audiobridge.service # Systemd User Unit file
├── go.mod # Go Dependencies
├── go.sum # Dependencies Checksum
└── README.md- OS: Linux (Tested on Debian).
- Audio System: Pipewire (with
pipewire-pulse). - Dependencies: Go 1.20+, FFmpeg, Chromium Browser, PortAudio & Opus dev libraries.
sudo apt update
sudo apt install git golang ffmpeg chromium-browser portaudio19-dev libopus-dev libopusfile-dev pulseaudio-utilsmkdir -p ~/go/src/ && cd ~/go/src/
git clone https://github.com/viruslox/VLX_AudioBridge.git
cd VLX_AudioBridgego mod init
go mod edit -replace github.com/bwmarrin/discordgo=github.com/ozraru/discordgo@master
go mod tidygo buildI hate "sudo", but let's make it easy:
sudo mkdir -p /opt/VLX_AudioBridge
# Ensure your user owns the directory
sudo chown -R $USER:$USER /opt/VLX_AudioBridge
cp ~/go/src/VLX_AudioBridge/VLX_AudioBridge /opt/VLX_AudioBridge/
# Copy config the example, but remember to edit it
cp ~/go/src/VLX_AudioBridge/AudioBridge.yaml /opt/VLX_AudioBridge/The application uses a YAML configuration file. Edit /opt/VLX_AudioBridge/AudioBridge.yaml. Example:
discord:
token: "YOUR_DISCORD_BOT_TOKEN"
prefix: "vlx." # Discord commands prefix
guild_id: "" # Optional: Restrict to specific Guild ID
streaming:
# SRT Destination (e.g., MediaMTX) # mode=caller to enable "us" as media sender
destination_url: "srt://127.0.0.1:8890?streamid=publish:vlx_audio&mode=caller&pkt_size=1316"
bitrate: "128k" # Audio output Bitrate for FFmpeg
# List of Discord User IDs to exclude from the SRT stream (Max 2)
excluded_users:
- "123456789012345678"
overlays:
# List of Web Overlay URLs to load and inject into Discord (Max 3)
urls:
- "https://stream-elements.com/overlay/"
- "https://another-overlay.com/"
# - "https://tuo-overlay-3.com"NOTE: Ensure your Pipewire session is active.
/opt/VLX_AudioBridge/
export XDG_RUNTIME_DIR=/run/user/$(id -u)
./VLX_AudioBridgevlx.join : Joins the user's voice channel, starts the SRT stream, and launches overlay browsers.
vlx.leave: Stops streaming, closes browsers, and disconnects from the voice channel.
vlx.shutdown: Gracefully shuts down the entire bridge process.
mkdir -p ~/.config/systemd/user/
cp ~/go/src/VLX_AudioBridge/scripts/vlx_audiobridge.service ~/.config/systemd/user/Edit ~/.config/systemd/user/vlx_audiobridge.service - at least configure "your user".
[Unit]
Description=VLX AudioBridge Service
After=network.target sound.target pipewire.service
Requires=pipewire.service
[Service]
Type=simple
ExecStart=/opt/VLX_AudioBridge/VLX_AudioBridge
WorkingDirectory=/opt/VLX_AudioBridge/
Restart=always
RestartSec=5
# Ensure XDG_RUNTIME_DIR is set for Pipewire access
Environment=XDG_RUNTIME_DIR=/run/user/%U
[Install]
WantedBy=default.targetsystemctl --user daemon-reload
systemctl --user enable vlx_audiobridge.service
systemctl --user start vlx_audiobridge.servicejournalctl --user -u vlx_audiobridge.service -f"Virtual Sink not found": Ensure pipewire-pulse is running. The application attempts to create VLX_VirtualSink automatically using pactl. Chromium Audio Issues: Check if the PULSE_SINK environment variable is correctly respected by your Chromium version. FFmpeg Errors: Ensure FFmpeg is installed and accessible in the system $PATH. Opus/CGO Errors: Ensure libopus-dev and portaudio19-dev are installed.
This project is licensed under the GNU General Public License v3.0. See the LICENSE file for details.