๐ Limoni Voice
Terminal-Native โข End-to-End Encrypted โข P2P Voice Chat & Screen Sharing
A pure-Go (no cgo), single-binary, real-time P2P voice chat application running entirely inside your terminal.
Built in Go with the Limoni TUI Framework.
English โข Tรผrkรงe
โจ Features
๐๏ธ Voice Communication
- Opus 48 kHz: CBR with in-band FEC; FEC redundancy follows the receivers' packet loss, and the bitrate steps between 12 and 32 kbps with the worst link in the room (drops quickly on loss or high latency, climbs back after 10 s of clean reports)
- Adaptive Jitter Buffer: RFC 3550 jitter estimation, packet-loss concealment and FEC recovery
- Echo Cancellation (AEC): Pure-Go Speex MDF port โ use speakers without headphones
- Noise & Click Suppression: Multi-band filter or pure-Go RNNoise (OFF / Standard / High / AI) plus a look-ahead transient suppressor for keyboard clicks and claps
- Voice Smoothing: De-harsh EQ, soft compressor and limiter for even, non-fatiguing loudness
- VAD: Real-time speaking detection with pre-roll lookback buffer and onset protection
- Global Push-to-Talk: Works while the terminal is unfocused (X11, XDG portal on Wayland, Win32, macOS)
- Native Audio I/O: PulseAudio/PipeWire protocol, CoreAudio, winmm โ no external tools needed
|
๐ฅ๏ธ Screen Sharing
- 60 FPS Hardware-Accelerated screen capture (1080p, ultra-low-latency)
- Native Platform API Support:
- ๐ช Windows: โ
Fully Tested & Working (Win32 GDI & DWM window capture / FFmpeg gdigrab display capture with monitor and window selector)
- ๐ macOS: โ
Fully Tested & Working (Native ScreenCaptureKit capture of any display or window, VideoToolbox hardware encoding with an x264 fallback, and a clear message when a macOS permission is missing)
- ๐ง Linux (GNOME): โ
Fully Tested & Working (Direct Mutter PipeWire zero-popup monitor capture & Portal window selector)
- ๐ง Linux (KDE Plasma): โ
Fully Tested & Working (XDG Desktop Portal PipeWire capture)
- ๐ง Other Linux DEs (Hyprland, Sway, XFCE, etc.): โ ๏ธ Untested / Experimental (Fallback to GPU Screen Recorder / FFmpeg)
- Watcher-Only Delivery: Video is uploaded only to members who actually watch (no bandwidth used otherwise)
- Quality Presets & Adaptive Bitrate: 720p30 (default, 2.5 Mbps) up to 1080p120; the stream steps down automatically when viewers lose packets
- Loss Recovery: NACK retransmission, time-based reorder buffer and paced sending; new viewers start instantly from the last keyframe
- System Audio: Share what your computer plays (PipeWire/PulseAudio monitor, WASAPI loopback, ScreenCaptureKit) with your own voice chat removed
- MPV / FFplay: Ultra-low-latency viewer experience (stream fed through a private pipe)
|
๐ Network Architecture
- LAN Auto-Discovery: Zero-configuration local network discovery via broadcast packets
- Path Ladder: LAN โ direct P2P (IPv6 / IPv4 hole-punch) โ UDP relay โ WebSocket relay
- NAT Classification: STUN-based cone/symmetric detection with port spraying & multi-socket punching
- UDP Relay: Low-latency encrypted media relay when direct paths fail (symmetric NAT, CGNAT)
- Redundant Audio: Audio is sent over both relay and direct paths, receiver deduplicates
- Live Diagnostics: Per-peer path, RTT, loss and jitter in the debug panel (
F12) and /net
- Relay Server: Lightweight Go relay with Prometheus
/metrics (including idle-room and kick/ban counters), structured logs and auth tokens that rotate without a restart
|
๐จ UI & Aesthetics
- 3D Studio Microphone: 60 FPS spinning 3D model on Braille Canvas
- Mouse 3D Rotation: Interactive control via drag & scroll
- Animated Modals: Smooth scaling dialog windows
- Neon & Cyberpunk Palettes: Multiple themes (Neon, Cyberpunk, Synthwave, Monokai, Dracula)
- Live VU-Meter: Real-time audio waveform and volume visualization
- Toast Notifications: Instant status updates
- English & Tรผrkรงe: Switch the interface language with
L in the lobby, I in the audio settings, --lang tr or LIMONI_LANG=tr
|
๐ E2EE File & Code Sharing
- Direct P2P Transfer: Chunked end-to-end encrypted file & code snippet sharing
- Safety Quarantine: Executable file warnings and strict filename sanitization
- Auto-Save: Accepted files saved to
Downloads/LimoniTransfers
- Integrity Verified: Automatic SHA-256 checksum verification
|
๐ฌ Chat & Room Security
- Terminal Chat: Multi-line messaging, clickable links & slash commands (
/help, /clear)
- Desktop Notifications: Chat messages, joins and file offers raise a system notification while the terminal is in the background (toggle with
B in settings)
- Invite Links:
/invite copies an https://limoni-voice-website.vercel.app/join#<key> link, clickable in any chat app. The page opens limoni://join/<key>, so on Linux, Windows and macOS (Limoni Voice.app) installs Limoni Voice starts and asks before joining the room (Enter joins, Esc cancels). The key sits after the #, which browsers never send to the server, and the page wipes it from the address bar once read. Pasting the link into the lobby works too, and limoni-voice --join <key or link> joins directly
- Knock to Join:
/knock makes everyone who has the room key wait until the host lets them in (Y) or turns them away (N)
- Room Lock & PIN: 4-digit PIN protection (
/lock <pin>) and host access control
- Kick & Ban: The host removes a member with
/kick <user> or keeps them out with /ban <user> (for as long as the room is open). The removal is proven with the host's key, so no member can fake one, and the group key is rotated at once so the removed member cannot follow the room
- Push-to-Talk (PTT): Configurable push-to-talk key, also with Ctrl / Alt / Shift / Cmd (e.g.
Alt+F), and voice activity detection
- Per-User Volume: Independent volume leveling and boost per participant
|
๐๏ธ Architecture
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Relay server (Docker / VPS / Cloudflare Tunnel) โ
โ WSS: signaling, PAKE handshake, fallback media โ
โ UDP: low-latency encrypted media relay โ
โโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโ
โ โ โ
โผ โผ โผ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
โ Peer A (Host)โ โ Peer B โ โ Peer C โ
โโโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโโค
โ Opus + FEC โ โ Opus + FEC โ โ Opus + FEC โ
โ AEC ยท RNNoiseโ โ AEC ยท RNNoiseโ โ AEC ยท RNNoiseโ
โ Limoni TUI โ โ Limoni TUI โ โ Limoni TUI โ
โโโโโโโโโฌโโโโโโโ โโโโโโโโโฌโโโโโโโ โโโโโโโโโฌโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโ
direct UDP / IPv6 hole-punch (full mesh)
(group key AES-256-GCM, rotated on join/leave)
Project Structure
limoni-voice/
โโโ main.go # Bootstrap: flags, language, log file, backend, node start
โโโ app*.go # App state, key/mouse routing, render loop, settings, kick/knock UI
โโโ ui_*.go # Lobby and room screens: cards, HUD, chat, controls
โโโ dialogs.go # Modals: audio settings, relay, debug/diagnostics, share, file offers
โโโ i18n.go # T / Tf / tr helpers over internal/i18n
โโโ internal/
โ โโโ p2p/ # P2P node: relay, handshake, NAT, media, files, screen share, kick/ban, stats
โ โโโ engine/ # Audio engine: 48 kHz capture/playback, VAD, AEC, denoise, mixing, SFX
โ โโโ i18n/ # Interface translations (English source, Turkish catalog)
โ โโโ applog/ # Rotating diagnostic log in the per-user state directory
โ โโโ protocol/ # Binary packet format + relay signaling types
โ โโโ e2ee/ # Room codes, CPace PAKE handshake, epoch keyring, member proofs
โ โโโ relay/ # Relay server (WebSocket + UDP), kick/ban, token rotation, metrics
โ โโโ nat/ # STUN NAT classification, punch strategies, IPv6
โ โโโ voice/ # Opus codec wrapper, adaptive bitrate controller, jitter buffer
โ โโโ dsp/ # Speex MDF echo canceller, RNNoise, FFT
โ โโโ audioio/ # PulseAudio / CoreAudio / winmm / tool fallback
โ โโโ sysaudio/ # System audio capture for screen share
โ โโโ video/ # Screen share video transport (reorder, pacing, NACK)
โ โโโ notify/ # Desktop notifications
โ โโโ ptt/ # System-wide push-to-talk (X11, portal, Win32, macOS)
โโโ screenshare/ # Screen sharing module (GPU Rec, FFmpeg, MPV)
โโโ relay-server/ # Relay binary (thin wrapper over internal/relay)
โโโ cmd/limoni-sign/ # ed25519 signing tool for release checksums
โโโ scripts/ # Build & packaging scripts
๐ Installation
๐ง Linux & ๐ macOS 1-Line Install (Recommended)
Install Limoni Voice with a single command in your terminal:
curl -fsSL https://raw.githubusercontent.com/thebanri/limoni-voice/main/install.sh | bash
Or with Homebrew (macOS and Linux, updates with brew upgrade):
brew install thebanri/tap/limoni-voice # the command
brew install --cask thebanri/tap/limoni-voice-app # macOS: Limoni Voice.app, opens invite links
Use one or the other: the cask includes the command.
๐ช Windows 1-Line Install (PowerShell)
irm https://raw.githubusercontent.com/thebanri/limoni-voice/main/scripts/install-windows.ps1 | iex
Or with Scoop (updates with scoop update limoni-voice):
scoop install https://github.com/thebanri/limoni-voice/releases/latest/download/limoni-voice.json
Prerequisites (Audio & Screen Sharing)
[!IMPORTANT]
- ๐ช Windows: Voice chat works out of the box with zero dependencies (using native Win32
winmm audio APIs). For Screen Sharing, FFmpeg and MPV are required.
- ๐ง Linux: Voice chat works out of the box on distributions with standard PulseAudio, PipeWire, or ALSA. For Screen Sharing, FFmpeg and MPV are required.
- ๐ macOS: Requires macOS 12 Monterey or later. Voice chat uses native CoreAudio (no dependencies). For screen sharing, install FFmpeg and MPV via Homebrew:
brew install ffmpeg mpv
- ๐ช Windows (winget / choco / scoop):
# via winget
winget install -e --id Gyan.FFmpeg
winget install -e --id shinchiro.mpv
# or via Chocolatey
choco install ffmpeg mpv
# or via Scoop
scoop install ffmpeg mpv
(Note: The Limoni-Voice-Setup.exe installer can also configure these automatically).
- ๐ง Linux (Debian / Ubuntu / Arch / Fedora):
# Debian / Ubuntu
sudo apt install ffmpeg mpv gstreamer1.0-tools gstreamer1.0-pipewire \
gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly
# Arch Linux
sudo pacman -S --needed ffmpeg mpv gstreamer gst-plugin-pipewire \
gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly
# Fedora
sudo dnf install ffmpeg mpv gstreamer1 pipewire-gstreamer \
gstreamer1-plugins-base gstreamer1-plugins-good gstreamer1-plugins-bad-free gstreamer1-plugins-ugly
Pre-built Binaries (Manual Download)
Download the latest release package from the Releases page:
| Platform |
Architecture |
File |
| ๐ง Linux |
amd64 |
limoni-voice_v1.4.0_linux_amd64.tar.gz / .deb |
| ๐ง Linux |
arm64 |
limoni-voice_v1.4.0_linux_arm64.tar.gz / .deb |
| ๐ macOS |
Apple Silicon |
Limoni-Voice_v1.4.0_macOS_arm64.app.zip |
| ๐ macOS |
Intel |
Limoni-Voice_v1.4.0_macOS_amd64.app.zip |
| ๐ช Windows |
amd64 |
Limoni-Voice-Setup.exe |
| ๐ช Windows |
arm64 |
Limoni-Voice-Setup_windows_arm64.exe |
# Linux / macOS
tar xzf limoni-voice_v1.4.0_linux_amd64.tar.gz
./limoni-voice
Building From Source
# Requirements: Go 1.26+
git clone https://github.com/thebanri/limoni-voice.git
cd limoni-voice
go build -o limoni-voice .
./limoni-voice
Self-Hosted Relay Server (Docker)
The relay server defaults to port 27850 (avoiding collision with common ports like 8080 and deterring port scanners). You can customize PORT in .env to any port you prefer.
To protect your relay server from unauthorized access and bandwidth abuse, you can set an optional Authentication Secret / Token (RELAY_AUTH_TOKEN):
# Option 1: Using Docker Compose (Recommended)
cp .env.example .env
# Set PORT and RELAY_AUTH_TOKEN in .env
docker compose up -d
# Option 2: Using Standard Docker CLI
docker build -t limoni-relay .
# Token-protected secure mode (Default Port 27850):
docker run -d --name limoni-relay -p 27850:27850 -e RELAY_AUTH_TOKEN="your_secret_key_123" limoni-relay
Connecting Clients to Protected Relay:
1. Via In-App Graphical Modal (Recommended - Friendly for Everyone):
To configure without messing with command-line arguments:
- In the lobby, press
[R] or click the [ R : Relay & Security Settings ] footer button.
- From any screen, press the
F5 shortcut.
- In room chat, type
/relay or /server.
In the animated dialog, configure the WebSocket URL and optional Server Password / Token, then click [ Save & Connect ]. Settings are persisted across sessions (settings.json).
2. Via Command-Line Flags or Environment Variables:
# Via command-line argument:
./limoni-voice --relay ws://192.168.1.100:27850/ws --relay-token your_secret_key_123
# OR directly in the URL query string:
./limoni-voice --relay "ws://192.168.1.100:27850/ws?token=your_secret_key_123"
# Alternatively, set via environment variables:
export LIMONI_RELAY_URL="ws://192.168.1.100:27850/ws"
export LIMONI_RELAY_TOKEN="your_secret_key_123"
./limoni-voice
๐ Exposing to the Internet with Cloudflare Tunnel (Zero Port Forwarding)
If you are hosting the relay on your home machine or behind CGNAT, you can expose it securely to your friends over the internet using Cloudflare Tunnel without opening any ports on your router:
๐ Option 1: Instant Quick Tunnel (NO Token or Cloudflare Account Needed)
Get a free, instant HTTPS/WSS URL without registering or configuring anything:
# 1. Start relay server and quick tunnel with a single command:
docker compose --profile quick-tunnel up -d
# 2. View your temporary public trycloudflare URL:
docker logs limoni-quick-tunnel
# Look for the generated URL in the logs:
# https://funny-animal-1234.trycloudflare.com
# 3. Connect yourself and friends via WSS:
./limoni-voice --relay wss://funny-animal-1234.trycloudflare.com/ws --relay-token your_secret_key_123
๐ Option 2: Using a Named Tunnel with Custom Domain (Token)
Add your tunnel token from Cloudflare Zero Trust to .env as CLOUDFLARE_TUNNEL_TOKEN=eyJh... and run:
docker compose --profile tunnel up -d
๐ป Option 3: Using the cloudflared CLI Directly
cloudflared tunnel --url http://localhost:27850
๐ Stopping Relay and Tunnels
Since tunnel services are defined under Docker Compose profiles, running a simple docker compose down will only stop the relay service. To stop everything (including all active tunnels):
# Stop all services and all tunnels across all profiles:
docker compose --profile "*" down
# Or stop a specific active profile:
docker compose --profile quick-tunnel down
# Remove any orphaned/leftover background containers:
docker compose down --remove-orphans
[!TIP]
Network / UDP QUIC Issues: docker-compose.yml is pre-configured with --protocol http2 and public DNS to route tunnel traffic over standard HTTPS (TCP 443) instead of UDP port 7844 (QUIC), preventing "sendmsg: network is unreachable" errors caused by ISP UDP drops.
๐ Backup Relays
Give several relays separated by commas, in the relay dialog (R), in --relay or in LIMONI_RELAY_URL:
./limoni-voice --relay "my.relay.com, backup.relay.com:27850"
The first one is the primary. A host whose primary is unreachable opens the room on the next one; a joiner that cannot reach a relay, or does not find the room there, asks the next one. Once a room is open it stays on its relay. Everyone in a room should list the same relays in the same order. A relay with its own password takes it in the URL: wss://backup.relay.com/ws?token=secret.
โก Low Latency: UDP Relay (Important for Cloudflare Tunnel users)
Cloudflare Tunnel only carries TCP/WebSocket. When two peers cannot connect directly (e.g. symmetric NAT or CGNAT), audio falls back to the WebSocket relay inside the tunnel, which typically adds ~100+ ms. For the lowest latency:
- Run the relay on a VPS, or port-forward UDP 27850 on your router.
- Tell clients where the UDP relay is reachable:
RELAY_UDP_PUBLIC_ADDR=203.0.113.10:27850 docker compose --profile tunnel up -d
- Check the debug panel (
F12) or type /net in chat: the peer path should show P2P, P2P-v6 or Relay-UDP instead of Relay.
| Env Variable |
Default |
Description |
PORT |
27850 |
TCP port for HTTP/WebSocket |
UDP_PORT |
same as PORT |
UDP relay port (0 / off disables it) |
RELAY_UDP_PUBLIC_ADDR |
โ |
host:port advertised for UDP (required behind a tunnel) |
RELAY_AUTH_TOKEN |
โ |
Optional shared secret for clients; several can be given separated by commas (e.g. the old and the new one while rotating) |
RELAY_AUTH_TOKEN_FILE |
โ |
File with one accepted secret per line (# comments). Re-read on SIGHUP (docker kill -s HUP limoni-relay) and whenever it changes, so secrets rotate without a restart; open connections stay up |
TRUST_PROXY |
false |
Always trust CF-Connecting-IP / X-Forwarded-For (private-network proxies are trusted automatically) |
LOG_FORMAT / LOG_LEVEL |
json / info |
Structured logging options |
LAN-Only / Offline Mode
To use Limoni Voice on an isolated local network (no internet connection required):
# Force LAN-only direct peer-to-peer mode
./limoni-voice --lan
# Or via environment variable:
export LIMONI_LAN_ONLY=1
./limoni-voice
โ๏ธ CLI Flags & Configuration
| Flag |
Env Variable |
Default |
Description |
--relay <url> |
LIMONI_RELAY_URL |
wss://relay.thebanri.dpdns.org/ws |
Custom WebSocket relay URL for self-hosted servers; backups after commas (see below) |
--relay-token <token> |
LIMONI_RELAY_TOKEN |
"" |
Authentication token for password-protected relay servers |
--token <token> |
LIMONI_RELAY_TOKEN |
"" |
Alias for --relay-token |
--lan, --lan-only |
LIMONI_LAN_ONLY |
false |
Force LAN-only offline mode (disables internet relay) |
--offline |
LIMONI_OFFLINE |
false |
Alias for --lan |
--peer <ip:port> |
LIMONI_PEER |
"" |
Direct target peer IP/host for cross-subnet or VPN LAN P2P |
--connect <ip:port> |
LIMONI_PEER |
"" |
Alias for --peer |
--sysaudio-test |
- |
- |
Capture system audio for 5 s, print the level and exit (screen share audio diagnosis) |
--version |
- |
- |
Print version information and exit |
--lang <en|tr> |
LIMONI_LANG |
saved setting, else en |
Interface language (English / Tรผrkรงe) |
--log-file <path> |
LIMONI_LOG_FILE |
see below |
Diagnostic log file |
--help, -h |
- |
- |
Show help message and usage instructions |
๐ Interface Language
The interface is written in English and ships with a Turkish translation. Press L in the lobby or I in the audio settings (T) to switch; the choice is saved in settings.json, like the audio settings, microphone and speakers, theme, mini HUD and chat height. --lang and LIMONI_LANG override it for one run. Log files stay in English so they can be shared in bug reports.
๐ Diagnostic Log
The log is written to the per-user state directory instead of the folder the app was started from, and rotates at 5 MB (one .1 backup is kept):
| Platform |
Location |
| Linux |
$XDG_STATE_HOME/limoni-voice/limoni-voice.log (~/.local/state/limoni-voice/) |
| macOS |
~/Library/Logs/limoni-voice/limoni-voice.log |
| Windows |
%LOCALAPPDATA%\limoni-voice\logs\limoni-voice.log |
๐ฅ๏ธ Screen Sharing Tips
- Press
V in a room, pick a quality preset (1โ5, or Q to cycle) and toggle system audio with A. Missing tools and the install command are shown in the dialog.
- Nothing is uploaded until someone watches (
W or click the stream). The sharer's bitrate then adapts to the viewers' connection (a short picture hiccup when it changes).
- The debug panel (
F12) shows preset, current bitrate, viewers, uplink queue and retransmissions.
- Relay operators: update the relay server to get per-viewer delivery through the relay; older relays still work but forward relayed video to the whole room.
- System audio not shared? Run
limoni-voice --sysaudio-test: it prints the capture backend and a level meter while you play something. On Windows the default playback device is captured (Sound settings โ Output), and an idle device delivers nothing.
- macOS: release builds embed the capture helper; self-built binaries compile it on first use (
xcode-select --install). System audio needs macOS 13+. Every display is offered separately, and a shared window is captured from the display it is on. Video is encoded by the VideoToolbox hardware encoder when your FFmpeg has it (Homebrew's does), otherwise by x264.
๐ macOS Notes
- Install: the one-line installer puts
Limoni Voice.app in /Applications (or ~/Applications) and links the limoni-voice command to it, so there is one copy to update. The app opens Limoni Voice in Terminal and handles limoni:// invite links.
- First launch: release apps are signed ad-hoc unless the release was built with a Developer ID. If macOS says it cannot verify the developer, Control-click the app โ Open (on macOS 15: System Settings โ Privacy & Security โ Open Anyway) once.
- Permissions belong to your terminal (Terminal, iTerm2, โฆ), because Limoni Voice runs inside it. Allow it under System Settings โ Privacy & Security, then restart the terminal:
| Feature |
Permission |
What happens without it |
| Talking |
Microphone |
Limoni Voice warns at start: others would hear silence |
| Screen sharing, system audio |
Screen & System Audio Recording |
The share dialog and the room log say what to enable |
| Global push-to-talk |
Input Monitoring |
The audio settings show the permission to enable |
| Opening from the app |
Automation โ Terminal |
Asked once, the first time the app opens Terminal |
- Updates: a copy running from
Limoni Voice.app updates the whole app bundle (checksum-verified), so its signature stays intact.
๐ฎ Usage
Quick Start
# 1. Launch the application
./limoni-voice
# 2. Your generated room key will appear (e.g. 9421-azure-wave-lemon)
# 3. Press [Enter] to host the room
# 4. Share the room key with your friends!
Lobby Screen Shortcuts
| Key |
Action |
Tab / Shift+Tab |
Navigate between input fields |
Enter |
Host or join room |
C / F2 |
Copy room key to clipboard |
G / F3 |
Generate a new room key |
T / F4 |
Open microphone sound test panel |
L |
Switch interface language (English / Tรผrkรงe) |
Esc |
Exit confirmation |
Ctrl+V / ๐ฑ๏ธ Right click |
Paste into the selected field (username or room key) |
๐ฑ๏ธ Drag |
Rotate 3D microphone model |
๐ฑ๏ธ Scroll |
Zoom in / out |
Room Screen Shortcuts
| Key |
Action |
M |
๐๏ธ Mute / Unmute Microphone |
D |
๐ Deafen / Undeafen audio |
N |
๐ Cycle Noise Suppression mode |
V |
๐ฅ๏ธ Start / Stop Screen Sharing |
W |
๐๏ธ Watch Live Stream |
, / . |
๐ Turn the watched stream's sound down / up (also [-]/[+] on the stream stage); each sharer keeps its own level |
C / F2 |
๐ Copy Room Code |
+ / - |
๐ Adjust Microphone Volume |
T |
๐งช Microphone Test Dialog |
P |
๐๏ธ Toggle Voice Activity / Push-to-Talk |
E |
๐ Toggle echo cancellation |
S |
๐ชถ Toggle voice smoothing (soft highs, even loudness, peak limiter) |
Ctrl+V / ๐ฑ๏ธ Right click |
๐ Paste into the chat (multi-line code keeps its lines) |
๐ฑ๏ธ Drag chat top border / [โฒ][โผ] |
โ๏ธ Make the chat panel taller or shorter (its left border drags it wider) |
/send <path> |
๐ Send a file (quoted paths from Explorer's "Copy as path" work) |
F12 |
๐ฉบ Debug & network diagnostics |
/net, /stats |
๐ถ Print per-peer path, RTT, loss & jitter to chat |
/kick <user> |
๐ข Remove a member (host only; they may knock again) |
/ban <user> |
โ Remove a member and keep their ID and address out while the room is open (host only) |
Esc |
Leave Room |
๐ Security
| Layer |
Technology |
Details |
| Room Code |
NNNN-word-word-word |
The 4 digits are the public room ID the relay sees; the 3 words are the secret and never leave your machine |
| Authentication |
CPace PAKE (ristretto255) |
Joiners prove they know the code without revealing it; offline guessing from captured traffic is impossible |
| Group Key |
Random AES-256 epoch key |
Generated by the host and delivered over the PAKE channel; rotated when a member joins or leaves, the host changes or ports hop |
| Rekeys |
X25519 member keys |
Every member has a session key vouched for by the host inside the PAKE channel. Each new group key is sealed separately per member, so a departed member cannot read it and no member can forge one; a newly elected host rekeys the same way |
| Encryption |
AES-256-GCM |
Voice, chat, control, video and file packets are encrypted end-to-end with random nonces |
| Anti-Replay |
Sequence + timestamp window |
Freshness window and sliding deduplication cache |
| Host Approval |
Room lock & PIN |
The host can lock the room and require a 4-digit PIN checked on the host side |
| Removal |
Host-proven kick / ban |
A removal carries pairwise tags only the host can compute; the group key rotates immediately without the removed member, and a missed rotation is recovered by asking the host for the key |
| Updates |
SHA-256 + ed25519 |
Self-update refuses assets without a matching checksums.txt; signed checksums are verified when a public key is embedded |
| Transport |
WSS (TLS) / UDP |
Signaling over WebSocket, media over direct or relayed encrypted UDP |
The relay cannot decrypt anything. It only sees the numeric room ID, opaque PAKE messages and encrypted media frames. When a direct path is not possible, encrypted audio is forwarded through the relay (UDP when available, otherwise WebSocket).
๐ ๏ธ Dependencies
Runtime (Optional)
For screen sharing capabilities:
| Tool |
Platform |
Purpose |
| FFmpeg |
All |
Video capture & transcoding |
| GPU Screen Recorder |
Linux |
Hardware-accelerated screen capture |
| MPV |
All |
Ultra-low-latency video playback |
Go Modules
๐งช Testing
# Run all tests (including the relay server and integration tests)
go test -race ./...
# End-to-end relay handshake, wrong-code rejection, key rotation, kick/ban
go test -run 'TestRelay|TestLAN|TestGroupKey|TestHostKicks' -v ./internal/p2p
# Every UI message has a Turkish translation and fixed-width labels still fit
go test -run 'TestEveryUIMessage|TestFixedColumn' .
# DSP ports (AEC, RNNoise), codec and jitter buffer
go test ./internal/...
๐ค Contributing
Contributions are always welcome! To get started:
- Fork this repository
- Create a feature branch (
git checkout -b feature/awesome-feature)
- Commit your changes (
git commit -m 'feat: add awesome feature')
- Push to your branch (
git push origin feature/awesome-feature)
- Open a Pull Request
๐ License
Copyright ยฉ 2026 TheBanri. Limoni Voice is licensed under the
GNU Affero General Public License v3.0.
You may use, study, change and share it. If you distribute it โ changed or not โ or let
people use a changed version over a network (a relay server, for example), you must give
them its complete source code under the same license. It cannot be turned into a closed
product.
Versions up to v1.7.0 were released under the MIT License, and stay under it.
The programs and libraries it works with are listed in
THIRD_PARTY_NOTICES.md.
Limoni Voice ๐ developed by the open source community.
Built with โค๏ธ using the Limoni TUI Framework.