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) {
			return

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Require client offers to include a sendrecv/recvonly audio m-line offering Opus
  2. If data-channel-only sessions must be supported, skip track creation rather than failing the session
  3. 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

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


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/4cbe68e950713b8b. Report an issue: GitHub.