The auto-bitrate formula 'bandwidth/840 - 42' produces negative values
for servers with bandwidth below ~35 kbps. A negative AudioDataBytes
would cause the Opus encoder to be configured with zero or negative
bitrate, producing invalid output.
Add a floor of 10 bytes per frame (8 kbps), the minimum usable Opus
bitrate for intelligible voice.
Lower maxGain from 8x to 4x (12dB) and target level from 18% to 12%.
The previous 8x gain would amplify quiet noise floors by 18dB,
transforming room tone and electrical hum into audible static. The
compression threshold is raised from 70% to 85% with a gentler 2:1
ratio instead of 3:1, reducing pumping distortion. The soft limiter
threshold is relaxed from 0.90 to 0.95 with a 0.2 knee instead of
0.1, providing more headroom before limiting engages.
These changes reduce the distortion and unnatural 'processed' sound
that other users would hear from barnard clients.
Replace SetBitrateToMax() with dynamic bitrate configuration based on
the per-frame byte budget (AudioDataBytes). Previously, the encoder
always targeted maximum bitrate (~510 kbps) and relied on output
truncation when frames exceeded the available bandwidth. This could
produce truncated/invalid Opus frames when the server's max bandwidth
is lower than the encoder's target.
The bitrate is now recalculated on every Encode() call as:
maxDataBytes * 8 * 100 (bits per second for 10ms frames)
This ensures the encoder produces frames that fit within the byte
budget without truncation.
Remove automatic stereo encoder selection based on buffer size. Voice
transmission in the Mumble protocol uses mono Opus with the AppVoIP
profile. The stereo encoder (AppAudio profile) is only appropriate for
file playback, which is controlled by the explicit EnableStereoEncoder
flag.
Additionally, downmix stereo microphone input to mono before sending
when no file playback is active. Previously, a stereo mic would cause
the stereo encoder to be selected via the buffer-size heuristic,
sending non-standard stereo Opus that could confuse other clients'
decoders and cause distorted audio.
This fixes 'user c has issues hearing audio from user a with distorted
audio' when user a has a stereo-input USB headset or similar device.
Track per-user audio sequence numbers to detect UDP packet loss gaps.
When a sequence discontinuity is detected (loss, reorder, or burst gap),
reset the Opus decoder state to prevent permanent audio corruption.
Also reset the decoder when Decode() returns an error, instead of
leaving the decoder in a corrupted state that produces static/popping
for the remainder of the session.
This fixes the 'random static/popping from user b but no other clients
hear it' symptom, which occurs when one client experiences packet loss
affecting only its own per-user decoder instance.
Make the F11 action menu close through a shared close action so Escape and the explicit Close actions menu item follow the same path. Treat Escape-prefixed Up and Down events as close inputs while the action menu is active, which handles termbox InputAlt behavior after pressing Escape. Preserve and restore the user/channel tree selection across action menu open and close, and preserve selection across live tree rebuilds.
Tested with: GOCACHE=/tmp/barnard-go-cache go test ./...
Implements 7 voice effects that can be cycled through with F12:
- None (default)
- Echo: Single repeating delay with feedback (250ms)
- Reverb: Multiple short delays without feedback
- High Pitch: Chipmunk voice using cubic interpolation
- Low Pitch: Deep voice effect
- Robot: Ring modulation for robotic sound
- Chorus: Layered voices with pitch variations
The effects are applied after noise suppression and AGC in the audio
pipeline. Selected effect is persisted to config file. Includes
comprehensive documentation in README.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This addresses low microphone volume issues by automatically normalizing
outgoing audio levels with dynamic range compression and soft limiting.
The AGC is always enabled and applies voice-optimized parameters to
ensure consistent audio levels are sent to other users while preserving
manual volume control for incoming audio.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed handle_error to accept *Barnard pointer instead of copying struct by value, eliminating race condition warnings from mutex copying.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>