docs: update Mumble docs for pymumble transport
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
6
TASKS.md
6
TASKS.md
@@ -4,10 +4,10 @@
|
|||||||
|
|
||||||
| Pri | Status | Task |
|
| Pri | Status | Task |
|
||||||
|-----|--------|------|
|
|-----|--------|------|
|
||||||
| P0 | [x] | `src/derp/opus.py` -- ctypes libopus encoder (zero Python deps) |
|
| P0 | [x] | `src/derp/mumble.py` -- rewrite to pymumble transport (voice + text) |
|
||||||
| P0 | [x] | `src/derp/mumble.py` -- voice varint, voice packet, PCM scaling, stream_audio |
|
|
||||||
| P0 | [x] | `plugins/music.py` -- play/stop/skip/queue/np/volume commands |
|
| P0 | [x] | `plugins/music.py` -- play/stop/skip/queue/np/volume commands |
|
||||||
| P1 | [x] | Tests: `test_opus.py`, `test_mumble.py` voice additions, `test_music.py` |
|
| P0 | [x] | Container patches for pymumble ssl + opuslib musl |
|
||||||
|
| P1 | [x] | Tests: `test_mumble.py` (62 cases), `test_music.py` (28 cases) |
|
||||||
| P2 | [x] | Documentation update (USAGE.md, CHEATSHEET.md) |
|
| P2 | [x] | Documentation update (USAGE.md, CHEATSHEET.md) |
|
||||||
|
|
||||||
## Previous Sprint -- v2.2.0 Configurable Proxy (2026-02-21)
|
## Previous Sprint -- v2.2.0 Configurable Proxy (2026-02-21)
|
||||||
|
|||||||
@@ -529,20 +529,19 @@ split at 4096 chars. IRC-only commands are no-ops. ~90% of plugins work.
|
|||||||
# config/derp.toml
|
# config/derp.toml
|
||||||
[mumble]
|
[mumble]
|
||||||
enabled = true
|
enabled = true
|
||||||
proxy = true # SOCKS5 proxy for TCP
|
proxy = false # pymumble connects directly
|
||||||
host = "mumble.example.com"
|
host = "mumble.example.com"
|
||||||
port = 64738
|
port = 64738
|
||||||
username = "derp"
|
username = "derp"
|
||||||
password = ""
|
password = ""
|
||||||
tls_verify = false # self-signed certs common
|
|
||||||
admins = ["admin_user"] # Mumble usernames
|
admins = ["admin_user"] # Mumble usernames
|
||||||
operators = []
|
operators = []
|
||||||
trusted = []
|
trusted = []
|
||||||
```
|
```
|
||||||
|
|
||||||
TCP/TLS via SOCKS5 proxy by default (`proxy = true`). Minimal protobuf
|
Uses pymumble for protocol handling (connection, voice, Opus encoding).
|
||||||
codec (no external dep). HTML stripped on receive, escaped on send.
|
HTML stripped on receive, escaped on send. IRC-only commands are no-ops.
|
||||||
IRC-only commands are no-ops. ~90% of plugins work.
|
~90% of plugins work.
|
||||||
|
|
||||||
## Music (Mumble only)
|
## Music (Mumble only)
|
||||||
|
|
||||||
|
|||||||
@@ -1480,30 +1480,30 @@ proxy at `127.0.0.1:1080` via `derp.http.urlopen` when `proxy = true`
|
|||||||
|
|
||||||
## Mumble Integration
|
## Mumble Integration
|
||||||
|
|
||||||
Connect derp to a Mumble server via TCP/TLS protobuf control channel.
|
Connect derp to a Mumble server with text chat and voice playback.
|
||||||
Text chat only (no voice). TCP is routed through the SOCKS5 proxy when
|
Uses [pymumble](https://github.com/azlux/pymumble) for the Mumble
|
||||||
`proxy = true` (default). No protobuf library dependency -- uses a
|
protocol (connection, SSL, voice encoding). Text commands are bridged
|
||||||
minimal built-in varint/field encoder/decoder for the ~7 message types
|
from pymumble's thread callbacks to asyncio for plugin dispatch.
|
||||||
needed.
|
|
||||||
|
|
||||||
### How It Works
|
### How It Works
|
||||||
|
|
||||||
The bot connects to the Mumble server over TLS, sends
|
pymumble handles the Mumble protocol: TLS connection, ping keepalives,
|
||||||
Version and Authenticate messages, then enters a read loop. It tracks
|
channel/user tracking, and Opus voice encoding. The bot registers
|
||||||
channels (ChannelState), users (UserState), and dispatches commands
|
callbacks for text messages and connection events, then bridges them
|
||||||
from TextMessage messages through the shared plugin registry.
|
to asyncio via `run_coroutine_threadsafe()`. Voice playback feeds raw
|
||||||
|
PCM to `sound_output.add_sound()` -- pymumble handles Opus encoding,
|
||||||
|
packetization, and timing.
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[mumble]
|
[mumble]
|
||||||
enabled = true
|
enabled = true
|
||||||
proxy = true # Route TCP through SOCKS5
|
proxy = false # SOCKS5 proxy (pymumble connects directly)
|
||||||
host = "mumble.example.com" # Mumble server hostname
|
host = "mumble.example.com" # Mumble server hostname
|
||||||
port = 64738 # Default Mumble port
|
port = 64738 # Default Mumble port
|
||||||
username = "derp" # Bot username
|
username = "derp" # Bot username
|
||||||
password = "" # Server password (optional)
|
password = "" # Server password (optional)
|
||||||
tls_verify = false # Mumble commonly uses self-signed certs
|
|
||||||
admins = ["admin_user"] # Mumble usernames
|
admins = ["admin_user"] # Mumble usernames
|
||||||
operators = [] # Mumble usernames
|
operators = [] # Mumble usernames
|
||||||
trusted = [] # Mumble usernames
|
trusted = [] # Mumble usernames
|
||||||
@@ -1511,8 +1511,7 @@ trusted = [] # Mumble usernames
|
|||||||
|
|
||||||
### Mumble Setup
|
### Mumble Setup
|
||||||
|
|
||||||
1. **Ensure a Mumble server** (Murmur/Mumble-server) is running and
|
1. **Ensure a Mumble server** (Murmur/Mumble-server) is running
|
||||||
accessible through the SOCKS5 proxy
|
|
||||||
|
|
||||||
2. **Configure the bot** with the server hostname, port, and credentials
|
2. **Configure the bot** with the server hostname, port, and credentials
|
||||||
|
|
||||||
@@ -1556,13 +1555,14 @@ unescapes entities. On send, text is HTML-escaped. Action messages use
|
|||||||
### Music Playback
|
### Music Playback
|
||||||
|
|
||||||
Stream audio from YouTube, SoundCloud, and other yt-dlp-supported sites
|
Stream audio from YouTube, SoundCloud, and other yt-dlp-supported sites
|
||||||
into the Mumble voice channel. Audio is decoded to PCM, encoded to Opus
|
into the Mumble voice channel. Audio is decoded to PCM via a
|
||||||
via system libopus, and transmitted as voice packets over the TCP tunnel.
|
`yt-dlp | ffmpeg` subprocess pipeline; pymumble handles Opus encoding
|
||||||
|
and voice transmission.
|
||||||
|
|
||||||
**System dependencies** (must be installed on the host):
|
**System dependencies** (container image includes these):
|
||||||
- `yt-dlp` -- audio stream extraction
|
- `yt-dlp` -- audio stream extraction
|
||||||
- `ffmpeg` -- decode to 48kHz mono s16le PCM
|
- `ffmpeg` -- decode to 48kHz mono s16le PCM
|
||||||
- `libopus.so.0` -- Opus codec (ctypes, no Python binding)
|
- `libopus` -- Opus codec (used by pymumble/opuslib)
|
||||||
|
|
||||||
```
|
```
|
||||||
!play <url> Play audio or add to queue
|
!play <url> Play audio or add to queue
|
||||||
@@ -1572,21 +1572,14 @@ via system libopus, and transmitted as voice packets over the TCP tunnel.
|
|||||||
!queue <url> Add to queue (alias for !play)
|
!queue <url> Add to queue (alias for !play)
|
||||||
!np Now playing
|
!np Now playing
|
||||||
!volume [0-100] Get/set volume
|
!volume [0-100] Get/set volume
|
||||||
|
!testtone Play 3-second 440Hz test tone
|
||||||
```
|
```
|
||||||
|
|
||||||
- Queue holds up to 50 tracks
|
- Queue holds up to 50 tracks
|
||||||
- Volume applies from the next track (default: 50%)
|
- Volume applies from the next track (default: 50%)
|
||||||
- Title resolved via `yt-dlp --get-title` before playback
|
- Title resolved via `yt-dlp --get-title` before playback
|
||||||
- Audio pipeline: `yt-dlp | ffmpeg` subprocess, 20ms Opus frames
|
- Audio pipeline: `yt-dlp | ffmpeg` subprocess, PCM fed to pymumble
|
||||||
- Commands are Mumble-only; `!play` on other adapters replies with an error,
|
- Commands are Mumble-only; `!play` on other adapters replies with an error,
|
||||||
other music commands silently no-op
|
other music commands silently no-op
|
||||||
- Playback runs as an asyncio background task; the bot remains responsive
|
- Playback runs as an asyncio background task; the bot remains responsive
|
||||||
to text commands during streaming
|
to text commands during streaming
|
||||||
|
|
||||||
### Transport
|
|
||||||
|
|
||||||
TCP connections route through the SOCKS5 proxy at `127.0.0.1:1080`
|
|
||||||
via `derp.http.create_connection` when `proxy = true` (default). Set
|
|
||||||
`proxy = false` to connect directly. TLS is applied on top of the
|
|
||||||
socket. Mumble commonly uses self-signed certificates, so `tls_verify`
|
|
||||||
defaults to `false`.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user