package xmppsig import ( "sync" "dev.narayana.im/narayana/telegabber/calls/signaling" "dev.narayana.im/narayana/telegabber/xmpp/jingle" "github.com/pion/webrtc/v4" ) // per-call state shared by Caller and Callee type xmppBase struct { a *Adapter remote string // full JID we act as on the wire; falls back to a.cfg.LocalJID localJID string // CallerSide/CalleeSide for Bind's MediaConnected wiring side signaling.Side mu sync.Mutex sid string session *jingle.Session bridge *signaling.Bridge pc *webrtc.PeerConnection remoteSDPSeen bool onRemoteSDP func(sdp string) // pion fires OnTrack during SetRemoteDescription, before any handler // the orchestrator might want to install - so hookTrack runs a permanent // forwarder at PC construction and buffers into pendingTracks until // SetTrackHandler arrives onTrackFn func(t *webrtc.TrackRemote) pendingTracks []*webrtc.TrackRemote } func (b *xmppBase) set(sid string, sess *jingle.Session) { b.mu.Lock() b.sid, b.session = sid, sess b.mu.Unlock() } // attaches the bridge and wires pion's connection-state callback func (b *xmppBase) Bind(br *signaling.Bridge) { b.mu.Lock() b.bridge = br pc := b.pc side := b.side b.mu.Unlock() hookPCState(pc, br, side) } func (b *xmppBase) bridgeRef() *signaling.Bridge { b.mu.Lock() defer b.mu.Unlock() return b.bridge } func (b *xmppBase) sessionRef() *jingle.Session { b.mu.Lock() defer b.mu.Unlock() return b.session } func (b *xmppBase) cleanup() { b.mu.Lock() sid := b.sid b.mu.Unlock() if sid == "" { return } b.a.cfg.Manager.Unregister(sid) } func (b *xmppBase) PeerConnection() *webrtc.PeerConnection { b.mu.Lock() defer b.mu.Unlock() return b.pc } func (b *xmppBase) SetOnRemoteSDP(fn func(sdp string)) { b.mu.Lock() b.onRemoteSDP = fn b.mu.Unlock() } // must run before the first SetRemoteDescription, or pion's first // OnTrack event is lost func (b *xmppBase) hookTrack(pc *webrtc.PeerConnection) { pc.OnTrack(func(t *webrtc.TrackRemote, _ *webrtc.RTPReceiver) { b.mu.Lock() fn := b.onTrackFn if fn == nil { b.pendingTracks = append(b.pendingTracks, t) b.mu.Unlock() return } b.mu.Unlock() fn(t) }) } // swaps in the real handler and drains buffered tracks func (b *xmppBase) SetTrackHandler(fn func(t *webrtc.TrackRemote)) { b.mu.Lock() b.onTrackFn = fn pending := b.pendingTracks b.pendingTracks = nil b.mu.Unlock() for _, t := range pending { fn(t) } } // fires the orchestrator hook exactly once per call func (b *xmppBase) onRemoteDescription(sdp string) { b.mu.Lock() if b.remoteSDPSeen { b.mu.Unlock() return } b.remoteSDPSeen = true hook := b.onRemoteSDP b.mu.Unlock() if hook != nil { hook(sdp) } }