router-for-me/CLIProxyAPI · error
add downstream audio track: %w
Error message
add downstream audio track: %w
What it means
Thrown when downstream.AddTrack(toDesktop) fails while attaching the client-facing audio track. Pion AddTrack errors when the track's codec is not negotiated in the remote offer (the client offer lacks an audio m-line compatible with Opus 111) or when SDP negotiation state makes the direction invalid. The session is closed on failure.
Source
Thrown at internal/client/codex/live/media.go:337
log.WithFields(session.logFields("session")).Info("codex live WebRTC media session created")
if errRemote := downstream.SetRemoteDescription(webrtc.SessionDescription{
Type: webrtc.SDPTypeOffer,
SDP: clientOffer,
}); errRemote != nil {
_ = session.Close()
return nil, "", fmt.Errorf("set downstream WebRTC offer: %w", errRemote)
}
toDesktop, errTrack := webrtc.NewTrackLocalStaticRTP(opusCodec, "audio", "codex-live")
if errTrack != nil {
_ = session.Close()
return nil, "", fmt.Errorf("create downstream audio track: %w", errTrack)
}
downstreamSender, errTrack := downstream.AddTrack(toDesktop)
if errTrack != nil {
_ = session.Close()
return nil, "", fmt.Errorf("add downstream audio track: %w", errTrack)
}
go drainRTCP("downstream", downstreamSender, session.done)
toOpenAI, errTrack := webrtc.NewTrackLocalStaticRTP(opusCodec, "audio", "codex-live")
if errTrack != nil {
_ = session.Close()
return nil, "", fmt.Errorf("create upstream audio track: %w", errTrack)
}
upstreamSender, errTrack := upstream.AddTrack(toOpenAI)
if errTrack != nil {
_ = session.Close()
return nil, "", fmt.Errorf("add upstream audio track: %w", errTrack)
}
go drainRTCP("upstream", upstreamSender, session.done)
downstream.OnTrack(func(track *webrtc.TrackRemote, _ *webrtc.RTPReceiver) {
if !strings.EqualFold(track.Codec().MimeType, webrtc.MimeTypeOpus) {
returnView on GitHub (pinned to 78f0c4079e)
Solutions
- Require client offers to include a sendrecv/recvonly audio m-line offering Opus
- If data-channel-only sessions must be supported, skip track creation rather than failing the session
- Inspect the client offer SDP for 'm=audio' and 'opus' before session setup
Defensive patterns
Strategy: validation
Validate before calling
func offerSupportsOpusAudio(offer string) bool {
for _, line := range strings.Split(offer, "\n") {
if strings.HasPrefix(strings.TrimSpace(line), "m=audio") {
return true
}
}
return false
} Try / catch
if _, _, err := relay.NewSession(ctx, offer, route); err != nil {
if strings.Contains(err.Error(), "add downstream audio track") {
respondUnsupportedMedia(w) // 415: offer lacks negotiable Opus audio
return
}
} Prevention
- Document that clients must offer Opus audio
- Reject audio-less offers early with 415 instead of failing mid-setup
- Cover this path with a unit test using a video-only offer
When it happens
Trigger: Client offer contains no audio section, an audio section with an incompatible codec (e.g. PCMU-only), or recvonly audio incompatible with the sender direction AddTrack implies.
Common situations: Clients that connect in listen-only or data-channel-only mode, or offer a non-Opus audio codec, so AddTrack cannot bind the Opus sender.
Related errors
- create downstream audio track: %w
- create upstream audio track: %w
- add upstream audio track: %w
- set downstream WebRTC offer: %w
- set upstream WebRTC answer: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/4cbe68e950713b8b.
Report an issue: GitHub.