log the incoming audio path at packet level
Record decoder creation, sequence numbers, frame lengths, and decode results for each tunneled audio packet, and note when a slow listener has a packet dropped. Diagnosing a codec or ordering problem previously meant adding print statements and rebuilding. These sit at info and debug, so they cost nothing unless -logfile is given. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
872149c977
commit
d02177af71
@@ -118,28 +118,31 @@ func (c *Client) handleUDPTunnel(buffer []byte) error {
|
||||
buffer = buffer[1:]
|
||||
session, n := varint.Decode(buffer)
|
||||
if n <= 0 {
|
||||
log.Warn("handleUDPTunnel: session varint decode failed")
|
||||
return errInvalidProtobuf
|
||||
}
|
||||
buffer = buffer[n:]
|
||||
user := c.Users[uint32(session)]
|
||||
if user == nil {
|
||||
log.Warn("handleUDPTunnel: unknown user session=%d", session)
|
||||
return errInvalidProtobuf
|
||||
}
|
||||
decoder := user.decoder
|
||||
if decoder == nil {
|
||||
// TODO: decoder pool
|
||||
// TODO: de-reference after stream is done
|
||||
codec := c.audioCodec
|
||||
if codec == nil {
|
||||
log.Warn("handleUDPTunnel: no audio codec available")
|
||||
return errNoCodec
|
||||
}
|
||||
decoder = codec.NewDecoder()
|
||||
user.decoder = decoder
|
||||
log.Info("handleUDPTunnel: created new decoder for %s", user.Name)
|
||||
}
|
||||
|
||||
// Sequence
|
||||
seq, n := varint.Decode(buffer)
|
||||
if n <= 0 {
|
||||
log.Warn("handleUDPTunnel: seq varint decode failed")
|
||||
return errInvalidProtobuf
|
||||
}
|
||||
buffer = buffer[n:]
|
||||
@@ -170,13 +173,20 @@ func (c *Client) handleUDPTunnel(buffer []byte) error {
|
||||
// Length
|
||||
length, n := varint.Decode(buffer)
|
||||
if n <= 0 {
|
||||
log.Warn("handleUDPTunnel: length varint decode failed")
|
||||
return errInvalidProtobuf
|
||||
}
|
||||
buffer = buffer[n:]
|
||||
// Opus audio packets set the 13th bit in the size field as the terminator.
|
||||
audioLength := int(length) &^ 0x2000
|
||||
isFinal := (length & 0x2000) != 0
|
||||
|
||||
log.Info("handleUDPTunnel: %s session=%d seq=%d audio_len=%d final=%v buf_remain=%d",
|
||||
user.Name, session, seq, audioLength, isFinal, len(buffer))
|
||||
|
||||
if audioLength > len(buffer) {
|
||||
log.Warn("handleUDPTunnel: audio length %d > remaining buffer %d",
|
||||
audioLength, len(buffer))
|
||||
return errInvalidProtobuf
|
||||
}
|
||||
|
||||
@@ -189,6 +199,9 @@ func (c *Client) handleUDPTunnel(buffer []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("handleUDPTunnel: Opus decode OK for %s seq=%d pcm_samples=%d",
|
||||
user.Name, seq, len(pcm))
|
||||
|
||||
event := AudioPacket{
|
||||
Client: c,
|
||||
Sender: user,
|
||||
@@ -271,6 +284,7 @@ func (c *Client) dispatchAudio(user *User, packet *AudioPacket) {
|
||||
|
||||
for _, delivery := range deliveries {
|
||||
if delivery.new {
|
||||
log.Debug("new audio stream from %s (session=%d)", user.Name, user.Session)
|
||||
delivery.listener.OnAudioStream(&AudioStreamEvent{Client: c, User: user, C: delivery.ch})
|
||||
}
|
||||
// User removal can run on a different protocol goroutine. Keep the
|
||||
@@ -283,6 +297,7 @@ func (c *Client) dispatchAudio(user *User, packet *AudioPacket) {
|
||||
case delivery.ch <- packet:
|
||||
default:
|
||||
// Never allow a slow listener to block protocol processing.
|
||||
log.Debug("dropping buffered audio for slow listener (session=%d)", user.Session)
|
||||
}
|
||||
}
|
||||
listeners.mu.Unlock()
|
||||
|
||||
@@ -204,8 +204,8 @@ func main() {
|
||||
}
|
||||
b.Config.Buffers = *buffers
|
||||
b.Config.AudioInterval = selectedAudioInterval
|
||||
b.Config.DisableUDP = *tcpOnly
|
||||
b.Config.IncomingAudioBuffer = selectedJitterBuffer
|
||||
b.Config.DisableUDP = *tcpOnly
|
||||
|
||||
b.Hotkeys = b.UserConfig.GetHotkeys()
|
||||
if err := b.UserConfig.SaveConfig(); err != nil {
|
||||
@@ -275,8 +275,7 @@ func jitterBufferDuration(milliseconds int) (time.Duration, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// serverAddress appends Mumble's default port unless the address already has
|
||||
// one. A bracketed or bare IPv6 literal is not a host:port pair.
|
||||
// serverAddress adds Mumble's default port without corrupting an IPv6 literal.
|
||||
func serverAddress(address string) string {
|
||||
if _, port, err := net.SplitHostPort(address); err == nil && port != "" {
|
||||
return address
|
||||
|
||||
Reference in New Issue
Block a user