Help us shape the future of Go! Take the 2026 Go Developer Survey

limoni-voice

command module
v1.17.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 23, 2026 License: AGPL-3.0 Imports: 69 Imported by: 0

README ยถ

Limoni Voice Logo

๐Ÿ‹ Limoni Voice

Terminal-Native โ€ข End-to-End Encrypted โ€ข P2P Voice Chat & Screen Sharing

Platform License Go Encryption

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

Limoni Voice Demo Preview


โœจ 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

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:

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:

  1. Run the relay on a VPS, or port-forward UDP 27850 on your router.
  2. Tell clients where the UDP relay is reachable:
    RELAY_UDP_PUBLIC_ADDR=203.0.113.10:27850 docker compose --profile tunnel up -d
    
  3. 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

Module Purpose
github.com/thebanri/limoni TUI framework (terminal, widgets, graphics, animations)
github.com/gorilla/websocket WebSocket relay transport
github.com/thesyncim/gopus Pure-Go Opus codec
filippo.io/cpace CPace password-authenticated key exchange
github.com/jfreymuth/pulse Native PulseAudio/PipeWire client
github.com/ebitengine/purego CoreAudio / macOS APIs without cgo
github.com/jezek/xgb, github.com/godbus/dbus Global push-to-talk on X11 / Wayland portal
golang.org/x/sys Platform-native system calls

๐Ÿงช 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:

  1. Fork this repository
  2. Create a feature branch (git checkout -b feature/awesome-feature)
  3. Commit your changes (git commit -m 'feat: add awesome feature')
  4. Push to your branch (git push origin feature/awesome-feature)
  5. 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.

Documentation ยถ

The Go Gopher

There is no documentation for this package.

Directories ยถ

Path Synopsis
Package assets holds the files embedded into the Limoni Voice binaries.
Package assets holds the files embedded into the Limoni Voice binaries.
cmd
installer command
limoni-sign command
Command limoni-sign generates the ed25519 key pair used to sign release checksums and signs checksums.txt so the in-app updater can verify releases.
Command limoni-sign generates the ed25519 key pair used to sign release checksums and signs checksums.txt so the in-app updater can verify releases.
internal
applog
Package applog writes the application's diagnostic log.
Package applog writes the application's diagnostic log.
audioio
Package audioio provides cross-platform, cgo-free audio capture and playback at the voice pipeline format (48 kHz, mono, 16-bit, 20 ms frames).
Package audioio provides cross-platform, cgo-free audio capture and playback at the voice pipeline format (48 kHz, mono, 16-bit, 20 ms frames).
clipboard
Package clipboard reads and owns the desktop clipboard natively, speaking the Wayland data-control protocol and X11 selections directly, so no wl-clipboard, xclip or xsel has to be installed.
Package clipboard reads and owns the desktop clipboard natively, speaking the Wayland data-control protocol and X11 selections directly, so no wl-clipboard, xclip or xsel has to be installed.
dsp
Package dsp holds the signal processing primitives of the voice pipeline: an arbitrary size FFT (kiss_fft algorithm), the Speex MDF acoustic echo canceller port and small filter helpers.
Package dsp holds the signal processing primitives of the voice pipeline: an arbitrary size FFT (kiss_fft algorithm), the Speex MDF acoustic echo canceller port and small filter helpers.
dsp/rnnoise
Package rnnoise is a pure Go port of RNNoise v0.1 (recurrent neural network noise suppression for 48 kHz speech, 10 ms frames), including its trained model.
Package rnnoise is a pure Go port of RNNoise v0.1 (recurrent neural network noise suppression for 48 kHz speech, 10 ms frames), including its trained model.
e2ee
Package e2ee implements Limoni Voice room cryptography: room codes, the CPace-based join handshake that lets a joiner obtain the room group key from the host without revealing the room secret to the relay, and the epoch keyring used to seal packets.
Package e2ee implements Limoni Voice room cryptography: room codes, the CPace-based join handshake that lets a joiner obtain the room group key from the host without revealing the room secret to the relay, and the epoch keyring used to seal packets.
i18n
Package i18n translates the user interface.
Package i18n translates the user interface.
nat
Package nat provides the NAT traversal building blocks used by Limoni Voice: a minimal STUN (RFC 5389) binding client codec, NAT mapping classification and hole punching candidate helpers.
Package nat provides the NAT traversal building blocks used by Limoni Voice: a minimal STUN (RFC 5389) binding client codec, NAT mapping classification and hole punching candidate helpers.
notify
Package notify shows desktop notifications: the freedesktop notification service over D-Bus on Linux, Notification Center through osascript on macOS and a toast through PowerShell on Windows.
Package notify shows desktop notifications: the freedesktop notification service over D-Bus on Linux, Notification Center through osascript on macOS and a toast through PowerShell on Windows.
p2p
protocol
Package protocol defines the Limoni Voice wire formats shared by the client and the relay: the compact binary P2P packet codec (carried inside the AEAD envelope) and the JSON signalling messages exchanged with the relay server.
Package protocol defines the Limoni Voice wire formats shared by the client and the relay: the compact binary P2P packet codec (carried inside the AEAD envelope) and the JSON signalling messages exchanged with the relay server.
ptt
Package ptt watches a push-to-talk key system wide, so talking works while another window (a game, an editor) has focus.
Package ptt watches a push-to-talk key system wide, so talking works while another window (a game, an editor) has focus.
relay
Package relay implements the Limoni Voice relay: WebSocket signalling with host-approved admission (the relay forwards opaque PAKE frames and never learns room secrets), a low-latency UDP datagram relay, WebSocket fallback forwarding, per-IP abuse limits and Prometheus metrics.
Package relay implements the Limoni Voice relay: WebSocket signalling with host-approved admission (the relay forwards opaque PAKE frames and never learns room secrets), a low-latency UDP datagram relay, WebSocket fallback forwarding, per-IP abuse limits and Prometheus metrics.
sysaudio
Package sysaudio captures what the computer is playing (system / desktop audio) for screen sharing: the PulseAudio / PipeWire monitor of the default output on Linux and WASAPI loopback on Windows.
Package sysaudio captures what the computer is playing (system / desktop audio) for screen sharing: the PulseAudio / PipeWire monitor of the default output on Linux and WASAPI loopback on Windows.
toolpath
Package toolpath finds the external programs Limoni Voice runs (FFmpeg, mpv, capture tools).
Package toolpath finds the external programs Limoni Voice runs (FFmpeg, mpv, capture tools).
video
Package video contains the screen share transport building blocks: MPEG-TS chunking with keyframe detection, the receiver's time-based reorder buffer with NACK scheduling, the sender's retransmission history, a token bucket pacer and the adaptive bitrate controller.
Package video contains the screen share transport building blocks: MPEG-TS chunking with keyframe detection, the receiver's time-based reorder buffer with NACK scheduling, the sender's retransmission history, a token bucket pacer and the adaptive bitrate controller.
voice
Package voice contains the real-time voice pipeline building blocks: the Opus codec wrapper and the adaptive jitter buffer with packet loss concealment and in-band FEC.
Package voice contains the real-time voice pipeline building blocks: the Opus codec wrapper and the adaptive jitter buffer with packet loss concealment and in-band FEC.
Command relay-server runs the Limoni Voice relay: WebSocket signalling on /ws plus an optional low-latency UDP datagram relay on the same port number.
Command relay-server runs the Limoni Voice relay: WebSocket signalling on /ws plus an optional low-latency UDP datagram relay on the same port number.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL