Documentation
¶
Index ¶
- Variables
- func DiscoverPublicIPs(stunURLs []string, log *slog.Logger) []string
- type Leg
- type LegState
- type LegType
- type LiveKitParticipantLeg
- func (l *LiveKitParticipantLeg) AcceptDTMF() bool
- func (l *LiveKitParticipantLeg) AcceptText() bool
- func (l *LiveKitParticipantLeg) Answer(_ context.Context) error
- func (l *LiveKitParticipantLeg) AnsweredAt() time.Time
- func (l *LiveKitParticipantLeg) AppID() string
- func (l *LiveKitParticipantLeg) AudioReader() io.Reader
- func (l *LiveKitParticipantLeg) AudioWriter() io.Writer
- func (l *LiveKitParticipantLeg) ClaimDisconnect() bool
- func (l *LiveKitParticipantLeg) ClearSpeakingTap()
- func (l *LiveKitParticipantLeg) Context() context.Context
- func (l *LiveKitParticipantLeg) CreatedAt() time.Time
- func (l *LiveKitParticipantLeg) Hangup(_ context.Context) error
- func (l *LiveKitParticipantLeg) Headers() map[string]string
- func (l *LiveKitParticipantLeg) ID() string
- func (l *LiveKitParticipantLeg) Identity() string
- func (l *LiveKitParticipantLeg) IsDeaf() bool
- func (l *LiveKitParticipantLeg) IsHeld() bool
- func (l *LiveKitParticipantLeg) IsMuted() bool
- func (l *LiveKitParticipantLeg) OnDTMF(_ func(rune))
- func (l *LiveKitParticipantLeg) OnTextReceived(_ func(text string, lossMarker bool))
- func (l *LiveKitParticipantLeg) RTPStats() RTPStats
- func (l *LiveKitParticipantLeg) RTTNegotiated() bool
- func (l *LiveKitParticipantLeg) Role() string
- func (l *LiveKitParticipantLeg) RoomID() string
- func (l *LiveKitParticipantLeg) SIPHeaders() map[string]string
- func (l *LiveKitParticipantLeg) SampleRate() int
- func (l *LiveKitParticipantLeg) SendDTMF(_ context.Context, _ string) error
- func (l *LiveKitParticipantLeg) SendText(_ context.Context, _ string) error
- func (l *LiveKitParticipantLeg) SetAcceptDTMF(a bool)
- func (l *LiveKitParticipantLeg) SetAcceptText(a bool)
- func (l *LiveKitParticipantLeg) SetAppID(id string)
- func (l *LiveKitParticipantLeg) SetDeaf(d bool)
- func (l *LiveKitParticipantLeg) SetMuted(m bool)
- func (l *LiveKitParticipantLeg) SetRole(r string)
- func (l *LiveKitParticipantLeg) SetRoomID(id string)
- func (l *LiveKitParticipantLeg) SetSpeakingTap(io.Writer)
- func (l *LiveKitParticipantLeg) State() LegState
- func (l *LiveKitParticipantLeg) TrackSID() string
- func (l *LiveKitParticipantLeg) Type() LegType
- type LiveKitPublishLeg
- func (l *LiveKitPublishLeg) AcceptDTMF() bool
- func (l *LiveKitPublishLeg) AcceptText() bool
- func (l *LiveKitPublishLeg) Answer(_ context.Context) error
- func (l *LiveKitPublishLeg) AnsweredAt() time.Time
- func (l *LiveKitPublishLeg) AppID() string
- func (l *LiveKitPublishLeg) AudioReader() io.Reader
- func (l *LiveKitPublishLeg) AudioWriter() io.Writer
- func (l *LiveKitPublishLeg) ClaimDisconnect() bool
- func (l *LiveKitPublishLeg) ClearSpeakingTap()
- func (l *LiveKitPublishLeg) Context() context.Context
- func (l *LiveKitPublishLeg) CreatedAt() time.Time
- func (l *LiveKitPublishLeg) Hangup(_ context.Context) error
- func (l *LiveKitPublishLeg) Headers() map[string]string
- func (l *LiveKitPublishLeg) ID() string
- func (l *LiveKitPublishLeg) IsDeaf() bool
- func (l *LiveKitPublishLeg) IsHeld() bool
- func (l *LiveKitPublishLeg) IsMuted() bool
- func (l *LiveKitPublishLeg) OnDTMF(_ func(rune))
- func (l *LiveKitPublishLeg) OnTextReceived(_ func(text string, lossMarker bool))
- func (l *LiveKitPublishLeg) RTPStats() RTPStats
- func (l *LiveKitPublishLeg) RTTNegotiated() bool
- func (l *LiveKitPublishLeg) Role() string
- func (l *LiveKitPublishLeg) RoomID() string
- func (l *LiveKitPublishLeg) SIPHeaders() map[string]string
- func (l *LiveKitPublishLeg) SampleRate() int
- func (l *LiveKitPublishLeg) SendDTMF(_ context.Context, _ string) error
- func (l *LiveKitPublishLeg) SendText(_ context.Context, _ string) error
- func (l *LiveKitPublishLeg) SetAcceptDTMF(a bool)
- func (l *LiveKitPublishLeg) SetAcceptText(a bool)
- func (l *LiveKitPublishLeg) SetAppID(id string)
- func (l *LiveKitPublishLeg) SetDeaf(d bool)
- func (l *LiveKitPublishLeg) SetMuted(m bool)
- func (l *LiveKitPublishLeg) SetRole(r string)
- func (l *LiveKitPublishLeg) SetRoomID(id string)
- func (l *LiveKitPublishLeg) SetSpeakingTap(io.Writer)
- func (l *LiveKitPublishLeg) State() LegState
- func (l *LiveKitPublishLeg) Transport() *lkmedia.Transport
- func (l *LiveKitPublishLeg) Type() LegType
- type Manager
- type MoQLeg
- func (l *MoQLeg) AcceptDTMF() bool
- func (l *MoQLeg) AcceptText() bool
- func (l *MoQLeg) Answer(_ context.Context) error
- func (l *MoQLeg) AnsweredAt() time.Time
- func (l *MoQLeg) AppID() string
- func (l *MoQLeg) AudioReader() io.Reader
- func (l *MoQLeg) AudioWriter() io.Writer
- func (l *MoQLeg) ClaimDisconnect() bool
- func (l *MoQLeg) ClearSpeakingTap()
- func (l *MoQLeg) Context() context.Context
- func (l *MoQLeg) CreatedAt() time.Time
- func (l *MoQLeg) Hangup(_ context.Context) error
- func (l *MoQLeg) Headers() map[string]string
- func (l *MoQLeg) ID() string
- func (l *MoQLeg) IsDeaf() bool
- func (l *MoQLeg) IsHeld() bool
- func (l *MoQLeg) IsMuted() bool
- func (l *MoQLeg) OnDTMF(_ func(rune))
- func (l *MoQLeg) OnTextReceived(_ func(text string, lossMarker bool))
- func (l *MoQLeg) RTPStats() RTPStats
- func (l *MoQLeg) RTTNegotiated() bool
- func (l *MoQLeg) Role() string
- func (l *MoQLeg) RoomID() string
- func (l *MoQLeg) SIPHeaders() map[string]string
- func (l *MoQLeg) SampleRate() int
- func (l *MoQLeg) SendDTMF(_ context.Context, _ string) error
- func (l *MoQLeg) SendText(_ context.Context, _ string) error
- func (l *MoQLeg) SetAcceptDTMF(a bool)
- func (l *MoQLeg) SetAcceptText(a bool)
- func (l *MoQLeg) SetAppID(id string)
- func (l *MoQLeg) SetDeaf(d bool)
- func (l *MoQLeg) SetMuted(m bool)
- func (l *MoQLeg) SetRole(r string)
- func (l *MoQLeg) SetRoomID(id string)
- func (l *MoQLeg) SetSpeakingTap(io.Writer)
- func (l *MoQLeg) State() LegState
- func (l *MoQLeg) Transport() *moqmedia.Transport
- func (l *MoQLeg) Type() LegType
- type PCMedia
- func (m *PCMedia) AddICECandidate(c webrtc.ICECandidateInit) error
- func (m *PCMedia) AudioReader() io.Reader
- func (m *PCMedia) AudioWriter() io.Writer
- func (m *PCMedia) ClearSpeakingTap()
- func (m *PCMedia) Close() error
- func (m *PCMedia) Codec() codec.CodecType
- func (m *PCMedia) Context() context.Context
- func (m *PCMedia) DrainLocalCandidates() ([]webrtc.ICECandidateInit, bool)
- func (m *PCMedia) PC() *webrtc.PeerConnection
- func (m *PCMedia) SampleRate() int
- func (m *PCMedia) SetOnDTMF(fn func(digit rune))
- func (m *PCMedia) SetSpeakingTap(w io.Writer)
- func (m *PCMedia) Start()
- type PCMediaConfig
- type RTPStats
- type SIPLeg
- func NewSIPInboundLeg(call *sipmod.InboundCall, engine *sipmod.Engine, log *slog.Logger) *SIPLeg
- func NewSIPOutboundLeg(call *sipmod.OutboundCall, engine *sipmod.Engine, log *slog.Logger) *SIPLeg
- func NewSIPOutboundPendingLeg(engine *sipmod.Engine, codecs []codec.CodecType, log *slog.Logger) *SIPLeg
- func (l *SIPLeg) AcceptDTMF() bool
- func (l *SIPLeg) AcceptText() bool
- func (l *SIPLeg) Answer(ctx context.Context) error
- func (l *SIPLeg) AnswerCh() <-chan struct{}
- func (l *SIPLeg) AnsweredAt() time.Time
- func (l *SIPLeg) AppID() string
- func (l *SIPLeg) AudioReader() io.Reader
- func (l *SIPLeg) AudioWriter() io.Writer
- func (l *SIPLeg) CallID() string
- func (l *SIPLeg) ClaimDisconnect() bool
- func (l *SIPLeg) ClearAMDTap()
- func (l *SIPLeg) ClearInTap()
- func (l *SIPLeg) ClearOutTap()
- func (l *SIPLeg) ClearSpeakingTap()
- func (l *SIPLeg) ConnectOutbound(call *sipmod.OutboundCall) error
- func (l *SIPLeg) Context() context.Context
- func (l *SIPLeg) CreatedAt() time.Time
- func (l *SIPLeg) DialogIdentity() (callID, localTag, remoteTag string, ok bool)
- func (l *SIPLeg) DisconnectReason() string
- func (l *SIPLeg) EnableEarlyMedia(ctx context.Context, preferred codec.CodecType) error
- func (l *SIPLeg) HandleRemoteHold(direction string)
- func (l *SIPLeg) Hangup(ctx context.Context) error
- func (l *SIPLeg) Headers() map[string]string
- func (l *SIPLeg) Hold(ctx context.Context) error
- func (l *SIPLeg) ID() string
- func (l *SIPLeg) IsDeaf() bool
- func (l *SIPLeg) IsHeld() bool
- func (l *SIPLeg) IsMuted() bool
- func (l *SIPLeg) JitterBufferMs() int
- func (l *SIPLeg) OnDTMF(f func(digit rune))
- func (l *SIPLeg) OnHold(f func())
- func (l *SIPLeg) OnRTPTimeout(f func())
- func (l *SIPLeg) OnSessionExpired(f func())
- func (l *SIPLeg) OnTextReceived(f func(text string, lossMarker bool))
- func (l *SIPLeg) OnUnhold(f func())
- func (l *SIPLeg) RTPStats() RTPStats
- func (l *SIPLeg) RTTNegotiated() bool
- func (l *SIPLeg) ReInviteAnswerSDP(remoteDirection string) []byte
- func (l *SIPLeg) Reject(ctx context.Context, statusCode int, reasonPhrase string) error
- func (l *SIPLeg) RemoteOfferCodecs() []codec.CodecType
- func (l *SIPLeg) ResetSessionTimer()
- func (l *SIPLeg) Role() string
- func (l *SIPLeg) RoomID() string
- func (l *SIPLeg) SIPHeaders() map[string]string
- func (l *SIPLeg) SampleRate() int
- func (l *SIPLeg) SendDTMF(ctx context.Context, digits string) error
- func (l *SIPLeg) SendNotifySipfrag(ctx context.Context, statusCode int, reason string, terminated bool) error
- func (l *SIPLeg) SendRinging(ctx context.Context) error
- func (l *SIPLeg) SendText(ctx context.Context, text string) error
- func (l *SIPLeg) SessionTimerParams() (interval uint32, refresher string)
- func (l *SIPLeg) SetAMDTap(w io.Writer)
- func (l *SIPLeg) SetAcceptDTMF(accept bool)
- func (l *SIPLeg) SetAcceptText(accept bool)
- func (l *SIPLeg) SetAppID(id string)
- func (l *SIPLeg) SetDeaf(d bool)
- func (l *SIPLeg) SetDisconnectReason(reason string)
- func (l *SIPLeg) SetHeld(held bool)
- func (l *SIPLeg) SetInTap(w io.Writer)
- func (l *SIPLeg) SetJitterBuffer(targetMs, maxMs int)
- func (l *SIPLeg) SetMuted(m bool)
- func (l *SIPLeg) SetOutTap(w io.Writer)
- func (l *SIPLeg) SetRole(r string)
- func (l *SIPLeg) SetRoomID(id string)
- func (l *SIPLeg) SetSpeakingTap(w io.Writer)
- func (l *SIPLeg) SetupEarlyMediaOutbound(remoteSDP *sipmod.SDPMedia, rtpSess *sipmod.RTPSession) error
- func (l *SIPLeg) SignalAnswer(preferred codec.CodecType)
- func (l *SIPLeg) State() LegState
- func (l *SIPLeg) SupportedCodecs() []codec.CodecType
- func (l *SIPLeg) Transfer(ctx context.Context, target string, replaces *sipmod.ReplacesParams) error
- func (l *SIPLeg) Type() LegType
- func (l *SIPLeg) Unhold(ctx context.Context) error
- func (l *SIPLeg) WaitConnected(ctx context.Context) error
- type SIPResponseLogger
- type WebRTCLeg
- func (l *WebRTCLeg) AcceptDTMF() bool
- func (l *WebRTCLeg) AcceptText() bool
- func (l *WebRTCLeg) AddICECandidate(c webrtc.ICECandidateInit) error
- func (l *WebRTCLeg) Answer(_ context.Context) error
- func (l *WebRTCLeg) AnsweredAt() time.Time
- func (l *WebRTCLeg) AppID() string
- func (l *WebRTCLeg) AudioReader() io.Reader
- func (l *WebRTCLeg) AudioWriter() io.Writer
- func (l *WebRTCLeg) ClaimDisconnect() bool
- func (l *WebRTCLeg) ClearSpeakingTap()
- func (l *WebRTCLeg) Context() context.Context
- func (l *WebRTCLeg) CreatedAt() time.Time
- func (l *WebRTCLeg) DrainCandidates() ([]webrtc.ICECandidateInit, bool)
- func (l *WebRTCLeg) Hangup(_ context.Context) error
- func (l *WebRTCLeg) Headers() map[string]string
- func (l *WebRTCLeg) ID() string
- func (l *WebRTCLeg) IsDeaf() bool
- func (l *WebRTCLeg) IsHeld() bool
- func (l *WebRTCLeg) IsMuted() bool
- func (l *WebRTCLeg) Media() *PCMedia
- func (l *WebRTCLeg) OnDTMF(f func(digit rune))
- func (l *WebRTCLeg) OnTextReceived(_ func(text string, lossMarker bool))
- func (l *WebRTCLeg) RTPStats() RTPStats
- func (l *WebRTCLeg) RTTNegotiated() bool
- func (l *WebRTCLeg) Role() string
- func (l *WebRTCLeg) RoomID() string
- func (l *WebRTCLeg) SIPHeaders() map[string]string
- func (l *WebRTCLeg) SampleRate() int
- func (l *WebRTCLeg) SendDTMF(_ context.Context, _ string) error
- func (l *WebRTCLeg) SendText(_ context.Context, _ string) error
- func (l *WebRTCLeg) SetAcceptDTMF(a bool)
- func (l *WebRTCLeg) SetAcceptText(_ bool)
- func (l *WebRTCLeg) SetAppID(id string)
- func (l *WebRTCLeg) SetDeaf(d bool)
- func (l *WebRTCLeg) SetMuted(m bool)
- func (l *WebRTCLeg) SetRole(r string)
- func (l *WebRTCLeg) SetRoomID(id string)
- func (l *WebRTCLeg) SetSpeakingTap(w io.Writer)
- func (l *WebRTCLeg) State() LegState
- func (l *WebRTCLeg) Type() LegType
- type WebSocketLeg
- func (l *WebSocketLeg) AcceptDTMF() bool
- func (l *WebSocketLeg) AcceptText() bool
- func (l *WebSocketLeg) Answer(_ context.Context) error
- func (l *WebSocketLeg) AnsweredAt() time.Time
- func (l *WebSocketLeg) AppID() string
- func (l *WebSocketLeg) AttachTransport(t *wsmedia.Transport, headers map[string]string)
- func (l *WebSocketLeg) AudioReader() io.Reader
- func (l *WebSocketLeg) AudioWriter() io.Writer
- func (l *WebSocketLeg) ClaimDisconnect() bool
- func (l *WebSocketLeg) ClearSpeakingTap()
- func (l *WebSocketLeg) Context() context.Context
- func (l *WebSocketLeg) CreatedAt() time.Time
- func (l *WebSocketLeg) Hangup(_ context.Context) error
- func (l *WebSocketLeg) Headers() map[string]string
- func (l *WebSocketLeg) ID() string
- func (l *WebSocketLeg) IsDeaf() bool
- func (l *WebSocketLeg) IsHeld() bool
- func (l *WebSocketLeg) IsMuted() bool
- func (l *WebSocketLeg) OnDTMF(_ func(rune))
- func (l *WebSocketLeg) OnTextReceived(fn func(text string, lossMarker bool))
- func (l *WebSocketLeg) RTPStats() RTPStats
- func (l *WebSocketLeg) RTTNegotiated() bool
- func (l *WebSocketLeg) Role() string
- func (l *WebSocketLeg) RoomID() string
- func (l *WebSocketLeg) SIPHeaders() map[string]string
- func (l *WebSocketLeg) SampleRate() int
- func (l *WebSocketLeg) SendDTMF(_ context.Context, _ string) error
- func (l *WebSocketLeg) SendText(ctx context.Context, text string) error
- func (l *WebSocketLeg) SetAcceptDTMF(a bool)
- func (l *WebSocketLeg) SetAcceptText(a bool)
- func (l *WebSocketLeg) SetAppID(id string)
- func (l *WebSocketLeg) SetDeaf(d bool)
- func (l *WebSocketLeg) SetMuted(m bool)
- func (l *WebSocketLeg) SetRole(r string)
- func (l *WebSocketLeg) SetRoomID(id string)
- func (l *WebSocketLeg) SetSpeakingTap(io.Writer)
- func (l *WebSocketLeg) State() LegState
- func (l *WebSocketLeg) Transport() *wsmedia.Transport
- func (l *WebSocketLeg) Type() LegType
- type WhatsAppLeg
- func (l *WhatsAppLeg) AcceptDTMF() bool
- func (l *WhatsAppLeg) AcceptText() bool
- func (l *WhatsAppLeg) Answer(_ context.Context) error
- func (l *WhatsAppLeg) AnswerCh() <-chan struct{}
- func (l *WhatsAppLeg) AnsweredAt() time.Time
- func (l *WhatsAppLeg) AppID() string
- func (l *WhatsAppLeg) AudioReader() io.Reader
- func (l *WhatsAppLeg) AudioWriter() io.Writer
- func (l *WhatsAppLeg) ClaimDisconnect() bool
- func (l *WhatsAppLeg) ClearSpeakingTap()
- func (l *WhatsAppLeg) ClientDialog() *sipgo.DialogClientSession
- func (l *WhatsAppLeg) ConnectOutbound(dialog *sipgo.DialogClientSession) error
- func (l *WhatsAppLeg) Context() context.Context
- func (l *WhatsAppLeg) CreatedAt() time.Time
- func (l *WhatsAppLeg) From() string
- func (l *WhatsAppLeg) Hangup(ctx context.Context) error
- func (l *WhatsAppLeg) Headers() map[string]string
- func (l *WhatsAppLeg) ID() string
- func (l *WhatsAppLeg) IsDeaf() bool
- func (l *WhatsAppLeg) IsHeld() bool
- func (l *WhatsAppLeg) IsMuted() bool
- func (l *WhatsAppLeg) Media() *PCMedia
- func (l *WhatsAppLeg) OnDTMF(f func(digit rune))
- func (l *WhatsAppLeg) OnTextReceived(_ func(text string, lossMarker bool))
- func (l *WhatsAppLeg) RTPStats() RTPStats
- func (l *WhatsAppLeg) RTTNegotiated() bool
- func (l *WhatsAppLeg) RequestAnswer() error
- func (l *WhatsAppLeg) Role() string
- func (l *WhatsAppLeg) RoomID() string
- func (l *WhatsAppLeg) SIPHeaders() map[string]string
- func (l *WhatsAppLeg) SampleRate() int
- func (l *WhatsAppLeg) SendDTMF(_ context.Context, _ string) error
- func (l *WhatsAppLeg) SendText(_ context.Context, _ string) error
- func (l *WhatsAppLeg) ServerDialog() *sipgo.DialogServerSession
- func (l *WhatsAppLeg) SetAcceptDTMF(a bool)
- func (l *WhatsAppLeg) SetAcceptText(_ bool)
- func (l *WhatsAppLeg) SetAppID(id string)
- func (l *WhatsAppLeg) SetDeaf(d bool)
- func (l *WhatsAppLeg) SetMuted(m bool)
- func (l *WhatsAppLeg) SetRole(r string)
- func (l *WhatsAppLeg) SetRoomID(id string)
- func (l *WhatsAppLeg) SetSIPController(c WhatsAppSIPController)
- func (l *WhatsAppLeg) SetSIPResponseLogger(c SIPResponseLogger)
- func (l *WhatsAppLeg) SetSpeakingTap(w io.Writer)
- func (l *WhatsAppLeg) State() LegState
- func (l *WhatsAppLeg) To() string
- func (l *WhatsAppLeg) Type() LegType
- type WhatsAppSIPController
Constants ¶
This section is empty.
Variables ¶
var ErrRTTNotNegotiated = errors.New("RTT not negotiated for this leg")
ErrRTTNotNegotiated is returned by SendText when RTT was not agreed in the SDP offer/answer exchange (or the leg type does not support RTT).
Functions ¶
func DiscoverPublicIPs ¶ added in v0.9.0
DiscoverPublicIPs queries each STUN server in turn and returns the first IPv4 and IPv6 reflexive addresses learned. The result is suitable for PCMediaConfig.ExternalIPs (and pion's SetNAT1To1IPs). Returns nil when no STUN URL is reachable.
Each lookup is bounded by stunDiscoverTimeout. Failures are logged at warn level and the next server is tried; if every server fails the caller should fall back to gathering host candidates as-is.
Types ¶
type Leg ¶
type Leg interface {
ID() string
Type() LegType
State() LegState
SampleRate() int
AudioReader() io.Reader
AudioWriter() io.Writer
OnDTMF(func(digit rune))
SendDTMF(ctx context.Context, digits string) error
AcceptDTMF() bool
SetAcceptDTMF(accept bool)
OnTextReceived(func(text string, lossMarker bool))
SendText(ctx context.Context, text string) error
AcceptText() bool
SetAcceptText(accept bool)
RTTNegotiated() bool
Hangup(ctx context.Context) error
Answer(ctx context.Context) error
Context() context.Context
RoomID() string
SetRoomID(id string)
AppID() string
SetAppID(id string)
IsMuted() bool
SetMuted(muted bool)
IsDeaf() bool
SetDeaf(deaf bool)
// Role returns the routing role used by the room's audio routing matrix.
// Empty string means unroled (full mesh).
Role() string
SetRole(role string)
SetSpeakingTap(w io.Writer)
ClearSpeakingTap()
IsHeld() bool
CreatedAt() time.Time
AnsweredAt() time.Time
SIPHeaders() map[string]string
// Headers returns custom protocol headers exposed by the leg's
// transport (X-/P- headers from a SIP INVITE or from a WebSocket HTTP
// upgrade, caller-supplied headers on an outbound WebSocket dial,
// etc.). Returns nil for leg types with no header concept.
Headers() map[string]string
RTPStats() RTPStats
// ClaimDisconnect returns true exactly once per leg. Termination paths
// (API hangup, remote BYE, RTP timeout, session expiry, etc.) call this
// before publishing leg.disconnected so concurrent paths cannot emit
// duplicate events.
ClaimDisconnect() bool
}
type LegType ¶
type LegType string
const ( TypeSIPInbound LegType = "sip_inbound" TypeSIPOutbound LegType = "sip_outbound" TypeWebRTC LegType = "webrtc" TypeWhatsAppInbound LegType = "whatsapp_in" TypeWhatsAppOutbound LegType = "whatsapp_out" TypeWebSocketInbound LegType = "websocket_in" TypeWebSocketOutbound LegType = "websocket_out" TypeMoQInbound LegType = "moq_in" TypeLiveKitPublish LegType = "livekit_publish" TypeLiveKitParticipant LegType = "livekit_participant" )
type LiveKitParticipantLeg ¶ added in v0.8.0
type LiveKitParticipantLeg struct {
// contains filtered or unexported fields
}
LiveKitParticipantLeg represents a single remote LiveKit participant — auto-created when the umbrella LiveKitPublishLeg's transport receives an inbound audio track for that participant. From VoiceBlender's room perspective the participant is a normal leg whose AudioReader is the decoded PCM of the LK participant's published audio. The AudioWriter is io.Discard — the LK side already mixes outbound audio for the participant, so we have nothing meaningful to send back to them at the leg level.
State machine: created in StateConnected. No ringing, no early-media. DTMF and RTT are not negotiated over LiveKit, so SendDTMF/SendText return errors. Hangup tears down the leg locally; the API layer is responsible for asking the LK server to unsubscribe via the umbrella transport (so we stop receiving the participant's RTP).
func NewLiveKitParticipantLeg ¶ added in v0.8.0
func NewLiveKitParticipantLeg(identity, trackSID string, pcmReader io.Reader, sampleRate int, log *slog.Logger) *LiveKitParticipantLeg
NewLiveKitParticipantLeg builds a participant leg already bound to its decoded-PCM source. The reader is owned by the caller (typically the umbrella transport's per-track decoder goroutine); the leg only reads from it.
`identity` is the LK participant identity from JoinResponse / ParticipantUpdate. `trackSID` is the LK track ID of the audio track. Both are surfaced via Headers().
The leg starts in StateConnected; the API layer is responsible for adding it to the LegMgr, emitting `leg.connected`, and adding it to the VoiceBlender room.
func (*LiveKitParticipantLeg) AcceptDTMF ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) AcceptDTMF() bool
func (*LiveKitParticipantLeg) AcceptText ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) AcceptText() bool
func (*LiveKitParticipantLeg) Answer ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) Answer(_ context.Context) error
Answer is a no-op for LK participant legs — connection completes when the leg is constructed.
func (*LiveKitParticipantLeg) AnsweredAt ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) AnsweredAt() time.Time
func (*LiveKitParticipantLeg) AppID ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) AppID() string
func (*LiveKitParticipantLeg) AudioReader ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) AudioReader() io.Reader
AudioReader yields the decoded PCM of the LK participant's audio track. Driven by the umbrella transport's per-track decoder goroutine.
func (*LiveKitParticipantLeg) AudioWriter ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) AudioWriter() io.Writer
AudioWriter is io.Discard: the LK side already mixes outbound audio for this participant, so anything VB tried to write would not reach them anyway. Reads from the VB room mixer's mixed-minus-self output land here and are dropped.
func (*LiveKitParticipantLeg) ClaimDisconnect ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) ClaimDisconnect() bool
func (*LiveKitParticipantLeg) ClearSpeakingTap ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) ClearSpeakingTap()
func (*LiveKitParticipantLeg) Context ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) Context() context.Context
func (*LiveKitParticipantLeg) CreatedAt ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) CreatedAt() time.Time
func (*LiveKitParticipantLeg) Hangup ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) Hangup(_ context.Context) error
Hangup transitions to StateHungUp and cancels the leg's context. The API layer is responsible for telling the umbrella transport to drop the LK subscription (so the server stops sending us this participant's RTP). Idempotent.
func (*LiveKitParticipantLeg) Headers ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) Headers() map[string]string
func (*LiveKitParticipantLeg) ID ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) ID() string
func (*LiveKitParticipantLeg) Identity ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) Identity() string
Identity returns the LK participant identity from JoinResponse.
func (*LiveKitParticipantLeg) IsDeaf ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) IsDeaf() bool
func (*LiveKitParticipantLeg) IsHeld ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) IsHeld() bool
func (*LiveKitParticipantLeg) IsMuted ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) IsMuted() bool
func (*LiveKitParticipantLeg) OnDTMF ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) OnDTMF(_ func(rune))
func (*LiveKitParticipantLeg) OnTextReceived ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) OnTextReceived(_ func(text string, lossMarker bool))
func (*LiveKitParticipantLeg) RTPStats ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) RTPStats() RTPStats
func (*LiveKitParticipantLeg) RTTNegotiated ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) RTTNegotiated() bool
func (*LiveKitParticipantLeg) Role ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) Role() string
func (*LiveKitParticipantLeg) RoomID ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) RoomID() string
func (*LiveKitParticipantLeg) SIPHeaders ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) SIPHeaders() map[string]string
func (*LiveKitParticipantLeg) SampleRate ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) SampleRate() int
func (*LiveKitParticipantLeg) SendDTMF ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) SendDTMF(_ context.Context, _ string) error
func (*LiveKitParticipantLeg) SendText ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) SendText(_ context.Context, _ string) error
func (*LiveKitParticipantLeg) SetAcceptDTMF ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) SetAcceptDTMF(a bool)
func (*LiveKitParticipantLeg) SetAcceptText ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) SetAcceptText(a bool)
func (*LiveKitParticipantLeg) SetAppID ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) SetAppID(id string)
func (*LiveKitParticipantLeg) SetDeaf ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) SetDeaf(d bool)
func (*LiveKitParticipantLeg) SetMuted ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) SetMuted(m bool)
func (*LiveKitParticipantLeg) SetRole ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) SetRole(r string)
func (*LiveKitParticipantLeg) SetRoomID ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) SetRoomID(id string)
func (*LiveKitParticipantLeg) SetSpeakingTap ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) SetSpeakingTap(io.Writer)
func (*LiveKitParticipantLeg) State ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) State() LegState
func (*LiveKitParticipantLeg) TrackSID ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) TrackSID() string
TrackSID returns the LK audio track ID this leg is bound to.
func (*LiveKitParticipantLeg) Type ¶ added in v0.8.0
func (l *LiveKitParticipantLeg) Type() LegType
type LiveKitPublishLeg ¶ added in v0.8.0
type LiveKitPublishLeg struct {
// contains filtered or unexported fields
}
LiveKitPublishLeg represents the outbound (publish) audio direction of a LiveKit-room connection. One per umbrella `POST /v1/legs type=livekit_room` call; it owns the lkmedia.Transport (signaling + publisher PC + subscriber PC).
Audio model: the publish leg's AudioWriter is fed by the VB room mixer with mixed-minus-self PCM; that PCM is Opus-encoded and pushed onto the local LiveKit track. The leg has no upstream audio of its own — AudioReader returns emptyReader{}. Remote LK participants surface as separate LiveKitParticipantLeg entries in the same VB room (auto-managed by the API layer).
State machine: created in StateConnected (LK signaling already completed during the transport's Connect). No ringing, no early-media. DTMF and RTT are not negotiated over LiveKit (browser SDKs don't carry them), so SendDTMF/SendText return errors.
func NewLiveKitPublishLeg ¶ added in v0.8.0
func NewLiveKitPublishLeg(t *lkmedia.Transport, headers map[string]string, sampleRate int, log *slog.Logger) *LiveKitPublishLeg
NewLiveKitPublishLeg constructs the umbrella publish leg already bound to a connected transport. The leg is StateConnected immediately — the LK signaling JOIN completed during Connect, so there is no ringing phase to wait on.
The headers map is expected to carry observability fields surfaced via Leg.Headers (livekit_identity, livekit_room). The leg merges these with the transport's identity/room values so callers can pass nil or partial maps.
func (*LiveKitPublishLeg) AcceptDTMF ¶ added in v0.8.0
func (l *LiveKitPublishLeg) AcceptDTMF() bool
func (*LiveKitPublishLeg) AcceptText ¶ added in v0.8.0
func (l *LiveKitPublishLeg) AcceptText() bool
func (*LiveKitPublishLeg) Answer ¶ added in v0.8.0
func (l *LiveKitPublishLeg) Answer(_ context.Context) error
Answer is a no-op for LK legs — connection completes during NewTransport.
func (*LiveKitPublishLeg) AnsweredAt ¶ added in v0.8.0
func (l *LiveKitPublishLeg) AnsweredAt() time.Time
func (*LiveKitPublishLeg) AppID ¶ added in v0.8.0
func (l *LiveKitPublishLeg) AppID() string
func (*LiveKitPublishLeg) AudioReader ¶ added in v0.8.0
func (l *LiveKitPublishLeg) AudioReader() io.Reader
AudioReader returns emptyReader{} — the publish leg has no upstream audio of its own. Remote LK participants' audio arrives via separate LiveKitParticipantLeg entries managed by the API layer.
func (*LiveKitPublishLeg) AudioWriter ¶ added in v0.8.0
func (l *LiveKitPublishLeg) AudioWriter() io.Writer
func (*LiveKitPublishLeg) ClaimDisconnect ¶ added in v0.8.0
func (l *LiveKitPublishLeg) ClaimDisconnect() bool
func (*LiveKitPublishLeg) ClearSpeakingTap ¶ added in v0.8.0
func (l *LiveKitPublishLeg) ClearSpeakingTap()
func (*LiveKitPublishLeg) Context ¶ added in v0.8.0
func (l *LiveKitPublishLeg) Context() context.Context
func (*LiveKitPublishLeg) CreatedAt ¶ added in v0.8.0
func (l *LiveKitPublishLeg) CreatedAt() time.Time
func (*LiveKitPublishLeg) Hangup ¶ added in v0.8.0
func (l *LiveKitPublishLeg) Hangup(_ context.Context) error
Hangup tears down the transport (sends Leave + closes peer connections). Idempotent.
func (*LiveKitPublishLeg) Headers ¶ added in v0.8.0
func (l *LiveKitPublishLeg) Headers() map[string]string
func (*LiveKitPublishLeg) ID ¶ added in v0.8.0
func (l *LiveKitPublishLeg) ID() string
func (*LiveKitPublishLeg) IsDeaf ¶ added in v0.8.0
func (l *LiveKitPublishLeg) IsDeaf() bool
func (*LiveKitPublishLeg) IsHeld ¶ added in v0.8.0
func (l *LiveKitPublishLeg) IsHeld() bool
func (*LiveKitPublishLeg) IsMuted ¶ added in v0.8.0
func (l *LiveKitPublishLeg) IsMuted() bool
func (*LiveKitPublishLeg) OnDTMF ¶ added in v0.8.0
func (l *LiveKitPublishLeg) OnDTMF(_ func(rune))
func (*LiveKitPublishLeg) OnTextReceived ¶ added in v0.8.0
func (l *LiveKitPublishLeg) OnTextReceived(_ func(text string, lossMarker bool))
func (*LiveKitPublishLeg) RTPStats ¶ added in v0.8.0
func (l *LiveKitPublishLeg) RTPStats() RTPStats
func (*LiveKitPublishLeg) RTTNegotiated ¶ added in v0.8.0
func (l *LiveKitPublishLeg) RTTNegotiated() bool
func (*LiveKitPublishLeg) Role ¶ added in v0.8.0
func (l *LiveKitPublishLeg) Role() string
func (*LiveKitPublishLeg) RoomID ¶ added in v0.8.0
func (l *LiveKitPublishLeg) RoomID() string
func (*LiveKitPublishLeg) SIPHeaders ¶ added in v0.8.0
func (l *LiveKitPublishLeg) SIPHeaders() map[string]string
func (*LiveKitPublishLeg) SampleRate ¶ added in v0.8.0
func (l *LiveKitPublishLeg) SampleRate() int
func (*LiveKitPublishLeg) SendDTMF ¶ added in v0.8.0
func (l *LiveKitPublishLeg) SendDTMF(_ context.Context, _ string) error
func (*LiveKitPublishLeg) SendText ¶ added in v0.8.0
func (l *LiveKitPublishLeg) SendText(_ context.Context, _ string) error
func (*LiveKitPublishLeg) SetAcceptDTMF ¶ added in v0.8.0
func (l *LiveKitPublishLeg) SetAcceptDTMF(a bool)
func (*LiveKitPublishLeg) SetAcceptText ¶ added in v0.8.0
func (l *LiveKitPublishLeg) SetAcceptText(a bool)
func (*LiveKitPublishLeg) SetAppID ¶ added in v0.8.0
func (l *LiveKitPublishLeg) SetAppID(id string)
func (*LiveKitPublishLeg) SetDeaf ¶ added in v0.8.0
func (l *LiveKitPublishLeg) SetDeaf(d bool)
func (*LiveKitPublishLeg) SetMuted ¶ added in v0.8.0
func (l *LiveKitPublishLeg) SetMuted(m bool)
func (*LiveKitPublishLeg) SetRole ¶ added in v0.8.0
func (l *LiveKitPublishLeg) SetRole(r string)
func (*LiveKitPublishLeg) SetRoomID ¶ added in v0.8.0
func (l *LiveKitPublishLeg) SetRoomID(id string)
func (*LiveKitPublishLeg) SetSpeakingTap ¶ added in v0.8.0
func (l *LiveKitPublishLeg) SetSpeakingTap(io.Writer)
func (*LiveKitPublishLeg) State ¶ added in v0.8.0
func (l *LiveKitPublishLeg) State() LegState
func (*LiveKitPublishLeg) Transport ¶ added in v0.8.0
func (l *LiveKitPublishLeg) Transport() *lkmedia.Transport
Transport returns the underlying lkmedia.Transport. Used by the API handler to wait on Done() and surface CloseReason on disconnect.
func (*LiveKitPublishLeg) Type ¶ added in v0.8.0
func (l *LiveKitPublishLeg) Type() LegType
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
func NewManager ¶
func NewManager() *Manager
func (*Manager) FindSIPByCallID ¶ added in v0.3.0
FindSIPByCallID returns the SIPLeg whose dialog Call-ID matches the given value, or nil if none. Used to route in-dialog requests (e.g. REFER, NOTIFY) back to the leg that owns the dialog.
func (*Manager) Remove ¶
Remove deletes the leg from the manager and returns it together with a boolean indicating whether this call performed the removal. The boolean is the single-flight signal: termination paths use it to ensure only one of several racing callers (API DELETE × N, remote BYE, RTP timeout, session expiry) actually drives leg shutdown. Callers that get false should treat the leg as already being torn down by someone else.
type MoQLeg ¶ added in v0.6.0
type MoQLeg struct {
// contains filtered or unexported fields
}
MoQLeg wraps a moqmedia.Transport as a Leg. PoC scope: inbound only, straight to StateConnected, no DTMF, no RTT/text, no mute parity beyond the atomic bit. Mute/deaf are honored by the room's mixer adapter because the leg exposes IsMuted/IsDeaf.
func NewMoQInboundLeg ¶ added in v0.6.0
func NewMoQInboundLeg(t *moqmedia.Transport, headers map[string]string, sampleRate int, log *slog.Logger) *MoQLeg
NewMoQInboundLeg constructs an inbound MoQ leg already bound to a transport and starts the transport's send loop reading from the egress pipe. The leg goes straight to StateConnected (no ringing flow).
func (*MoQLeg) AcceptDTMF ¶ added in v0.6.0
func (*MoQLeg) AcceptText ¶ added in v0.6.0
func (*MoQLeg) AnsweredAt ¶ added in v0.6.0
func (*MoQLeg) AudioReader ¶ added in v0.6.0
func (*MoQLeg) AudioWriter ¶ added in v0.6.0
func (*MoQLeg) ClaimDisconnect ¶ added in v0.6.0
func (*MoQLeg) ClearSpeakingTap ¶ added in v0.6.0
func (l *MoQLeg) ClearSpeakingTap()
func (*MoQLeg) OnTextReceived ¶ added in v0.6.0
func (*MoQLeg) RTTNegotiated ¶ added in v0.6.0
func (*MoQLeg) SIPHeaders ¶ added in v0.6.0
func (*MoQLeg) SampleRate ¶ added in v0.6.0
func (*MoQLeg) SetAcceptDTMF ¶ added in v0.6.0
func (*MoQLeg) SetAcceptText ¶ added in v0.6.0
func (*MoQLeg) SetSpeakingTap ¶ added in v0.6.0
type PCMedia ¶ added in v0.5.0
type PCMedia struct {
// contains filtered or unexported fields
}
PCMedia wraps a pion PeerConnection and exposes PCM16 io.Reader/io.Writer at the codec's native sample rate. Inbound RTP is decoded to PCM on a per-packet goroutine; outbound PCM is chunked into 20 ms frames, encoded, and written to the local RTP track.
func NewPCMedia ¶ added in v0.5.0
func NewPCMedia(cfg PCMediaConfig) (*PCMedia, error)
func (*PCMedia) AddICECandidate ¶ added in v0.5.0
func (m *PCMedia) AddICECandidate(c webrtc.ICECandidateInit) error
func (*PCMedia) AudioReader ¶ added in v0.5.0
AudioReader yields decoded PCM (16-bit LE) at the codec's native rate.
func (*PCMedia) AudioWriter ¶ added in v0.5.0
AudioWriter accepts PCM (16-bit LE) at the codec's native rate.
func (*PCMedia) ClearSpeakingTap ¶ added in v0.5.0
func (m *PCMedia) ClearSpeakingTap()
ClearSpeakingTap removes the installed tap.
func (*PCMedia) DrainLocalCandidates ¶ added in v0.5.0
func (m *PCMedia) DrainLocalCandidates() ([]webrtc.ICECandidateInit, bool)
DrainLocalCandidates returns buffered local ICE candidates and the gathering-complete flag, clearing the buffer.
func (*PCMedia) PC ¶ added in v0.5.0
func (m *PCMedia) PC() *webrtc.PeerConnection
func (*PCMedia) SampleRate ¶ added in v0.5.0
func (*PCMedia) SetSpeakingTap ¶ added in v0.5.0
type PCMediaConfig ¶ added in v0.5.0
type PCMediaConfig struct {
Codec codec.CodecType
ICEServers []string
RTPPortMin uint16
RTPPortMax uint16
Log *slog.Logger
// ExternalIPs are public addresses substituted into local host ICE
// candidates via pion's SetNAT1To1IPs. Required when VB runs behind
// NAT/Docker and the gathered host interface IPs aren't routable
// from the remote peer.
ExternalIPs []string
OnDisconnect func(reason string)
// OnConnected fires once when the peer connection reaches the
// Connected state. Subsequent state transitions don't re-fire.
OnConnected func()
// AnsweringDTLSRole forces the DTLS role on actpass offers. Use
// DTLSRoleClient against ice-lite peers (e.g. WhatsApp).
AnsweringDTLSRole webrtc.DTLSRole
// EnableTelephoneEvent advertises RFC 4733 DTMF (PT 126) in the
// answer and routes inbound telephone-event packets to OnDTMF.
EnableTelephoneEvent bool
}
PCMediaConfig configures a pion PeerConnection + audio pipeline shared by WebRTC and WhatsApp legs. The peer connection is created by NewPCMedia; the caller drives SDP negotiation via PC().
type RTPStats ¶
type RTPStats struct {
PacketsReceived uint32
PacketsLost uint32
JitterMs float64
MOSScore float64 // 1.0–5.0; 0 if insufficient data (< 2 packets)
}
RTPStats holds inbound RTP stream quality metrics.
type SIPLeg ¶
type SIPLeg struct {
// contains filtered or unexported fields
}
SIPLeg wraps a SIP dialog (inbound or outbound) with RTP media handling.
func NewSIPInboundLeg ¶
func NewSIPOutboundLeg ¶
func NewSIPOutboundPendingLeg ¶
func NewSIPOutboundPendingLeg(engine *sipmod.Engine, codecs []codec.CodecType, log *slog.Logger) *SIPLeg
NewSIPOutboundPendingLeg creates an outbound leg in ringing state with its own context. Call ConnectOutbound after the INVITE succeeds. If codecs is non-empty it overrides the engine's default codec list.
func (*SIPLeg) AcceptDTMF ¶ added in v0.3.0
func (*SIPLeg) AcceptText ¶ added in v0.6.0
AcceptText reports whether this leg currently accepts inbound RTT events.
func (*SIPLeg) Answer ¶
Answer sends 200 OK to the inbound INVITE. Codec selection respects any hint set via SignalAnswer; a CodecUnknown hint falls back to the default offer-order preference. The hint is ignored when the leg is already in StateEarlyMedia (the codec was locked in at 183).
func (*SIPLeg) AnswerCh ¶
func (l *SIPLeg) AnswerCh() <-chan struct{}
AnswerCh returns the channel that is closed when the REST answer endpoint is called.
func (*SIPLeg) AnsweredAt ¶
func (*SIPLeg) AudioReader ¶
func (*SIPLeg) AudioWriter ¶
func (*SIPLeg) ClaimDisconnect ¶ added in v0.6.0
ClaimDisconnect returns true on the first caller and false on every subsequent caller. Termination paths use this gate so only one publishes leg.disconnected, even when DELETE racing with remote BYE or RTP timeout.
func (*SIPLeg) ClearAMDTap ¶ added in v0.2.0
func (l *SIPLeg) ClearAMDTap()
ClearAMDTap removes the AMD tap.
func (*SIPLeg) ClearSpeakingTap ¶ added in v0.2.0
func (l *SIPLeg) ClearSpeakingTap()
ClearSpeakingTap removes the speaking detection tap.
func (*SIPLeg) ConnectOutbound ¶
func (l *SIPLeg) ConnectOutbound(call *sipmod.OutboundCall) error
ConnectOutbound sets the answered outbound call on the leg, negotiates the codec, starts media, and transitions to connected.
func (*SIPLeg) DialogIdentity ¶ added in v0.3.0
DialogIdentity returns (callID, localTag, remoteTag) from this leg's view.
func (*SIPLeg) DisconnectReason ¶ added in v0.6.0
DisconnectReason returns the override set by SetDisconnectReason, or "" if none. Consumed by the inbound-call goroutine when publishing leg.disconnected.
func (*SIPLeg) EnableEarlyMedia ¶
EnableEarlyMedia sends 183 Session Progress with SDP and sets up the media pipeline so audio can flow before the call is answered. Only valid for inbound legs in StateRinging.
preferred biases codec selection: when non-zero and present in both the remote offer and the supported list, it wins; otherwise selection falls back to the default offer-order preference.
func (*SIPLeg) HandleRemoteHold ¶
HandleRemoteHold processes a remote re-INVITE's SDP direction for hold/unhold.
func (*SIPLeg) Hangup ¶
Hangup transitions the leg to StateHungUp and (exactly once) sends a BYE on the underlying SIP dialog. State transition, context cancel, RTP-session close, and timer cleanup happen on every call (idempotent operations); the SIP BYE is gated by sync.Once so concurrent termination paths cannot emit duplicate BYEs.
func (*SIPLeg) JitterBufferMs ¶ added in v0.3.0
JitterBufferMs returns the configured target delay in milliseconds (0 = disabled).
func (*SIPLeg) OnHold ¶
func (l *SIPLeg) OnHold(f func())
OnHold registers a callback for when the leg is put on hold.
func (*SIPLeg) OnRTPTimeout ¶
func (l *SIPLeg) OnRTPTimeout(f func())
OnRTPTimeout sets a callback that fires when no RTP packets are received within the timeout period (30s). Called at most once.
func (*SIPLeg) OnSessionExpired ¶
func (l *SIPLeg) OnSessionExpired(f func())
OnSessionExpired registers a callback for when the session timer expires without a refresh. Typically used to hang up the call.
func (*SIPLeg) OnTextReceived ¶ added in v0.6.0
OnTextReceived registers a callback for inbound T.140 text. The callback runs on the dispatcher goroutine so the caller can do moderately expensive work (e.g. publish webhook events) without blocking the RTP read loop.
func (*SIPLeg) OnUnhold ¶
func (l *SIPLeg) OnUnhold(f func())
OnUnhold registers a callback for when the leg is taken off hold.
func (*SIPLeg) RTTNegotiated ¶ added in v0.6.0
RTTNegotiated reports whether SDP agreed on an m=text section for this leg.
func (*SIPLeg) ReInviteAnswerSDP ¶
ReInviteAnswerSDP builds an SDP body for responding to a remote re-INVITE. The direction is mirrored: if the remote sent "sendonly" (hold), we respond with "recvonly"; if "sendrecv" we respond with "sendrecv".
func (*SIPLeg) Reject ¶ added in v0.6.0
Reject sends a final non-2xx response on an unanswered inbound leg, terminating the dialog without ever creating a session. statusCode is the SIP status code (e.g. 486, 603); reasonPhrase is the SIP reason phrase shown after the status code on the response line.
Only valid on inbound legs in StateRinging or StateEarlyMedia. After Reject succeeds the dialog context is cancelled by sipgo, so the inbound-call goroutine wakes up and publishes leg.disconnected — if the caller wants the disconnect event to carry a specific reason, it should call SetDisconnectReason first.
func (*SIPLeg) RemoteOfferCodecs ¶ added in v0.6.0
RemoteOfferCodecs returns the codecs offered by the remote in the inbound INVITE SDP, in offer order. Returns nil for outbound legs or when no offer has been parsed yet.
func (*SIPLeg) ResetSessionTimer ¶
func (l *SIPLeg) ResetSessionTimer()
ResetSessionTimer resets the session timer, called when a refresh re-INVITE is received from the remote UA.
func (*SIPLeg) SIPHeaders ¶
func (*SIPLeg) SampleRate ¶
func (*SIPLeg) SendNotifySipfrag ¶ added in v0.3.0
func (l *SIPLeg) SendNotifySipfrag(ctx context.Context, statusCode int, reason string, terminated bool) error
SendNotifySipfrag emits a NOTIFY sipfrag for the implicit refer subscription.
func (*SIPLeg) SendRinging ¶ added in v0.6.0
SendRinging sends a 180 Ringing provisional response with no SDP. Only valid for inbound legs in StateRinging. May be called multiple times — each call emits another 180 (RFC-allowed; receivers tolerate re-sends).
func (*SIPLeg) SendText ¶ added in v0.6.0
SendText queues UTF-8 text for transmission as RFC 4103 RTP. Returns ErrRTTNotNegotiated when the SDP exchange did not agree on m=text.
func (*SIPLeg) SessionTimerParams ¶
SessionTimerParams returns the negotiated session timer interval and refresher. Returns (0, "") if session timers are not active.
func (*SIPLeg) SetAMDTap ¶ added in v0.2.0
SetAMDTap sets a writer that receives decoded incoming PCM for answering machine detection. Separate from inTap so AMD and recording can coexist.
func (*SIPLeg) SetAcceptDTMF ¶ added in v0.3.0
func (*SIPLeg) SetAcceptText ¶ added in v0.6.0
SetAcceptText toggles inbound RTT event acceptance on this leg.
func (*SIPLeg) SetDisconnectReason ¶ added in v0.6.0
SetDisconnectReason stores a reason that will be used in the next leg.disconnected event published for this leg, in place of the goroutine's default. Set by the API DELETE handler before calling Reject or Hangup so the user-provided cause flows through to the event.
func (*SIPLeg) SetInTap ¶
SetInTap sets a writer that receives a copy of every decoded incoming PCM frame (before it enters inFrames). Used for standalone leg recording.
func (*SIPLeg) SetJitterBuffer ¶ added in v0.3.0
SetJitterBuffer configures the SIP ingress jitter buffer. targetMs is the target play-out delay (e.g. 60 for 60 ms); 0 disables the buffer entirely (passthrough). maxMs caps the queue depth; 0 means "use a sensible default" (300 ms). Call before the leg's media pipeline is established.
func (*SIPLeg) SetOutTap ¶
SetOutTap sets a writer that receives a copy of every outgoing PCM frame (including silence) from the writeLoop. Used for standalone leg recording.
func (*SIPLeg) SetSpeakingTap ¶ added in v0.2.0
SetSpeakingTap sets a writer that receives decoded incoming PCM for voice activity detection.
func (*SIPLeg) SetupEarlyMediaOutbound ¶
func (l *SIPLeg) SetupEarlyMediaOutbound(remoteSDP *sipmod.SDPMedia, rtpSess *sipmod.RTPSession) error
SetupEarlyMediaOutbound configures the media pipeline from a 183 response's SDP before the call is answered. Only valid in StateRinging.
func (*SIPLeg) SignalAnswer ¶
SignalAnswer signals the leg to answer (called from REST API). preferred is an optional codec hint passed to Answer; pass CodecUnknown for none.
func (*SIPLeg) SupportedCodecs ¶ added in v0.9.0
SupportedCodecs returns the engine's supported codecs for this leg, in preference order. Used by the REST layer to reject answer/early-media requests that name a codec the engine wasn't configured for.
func (*SIPLeg) Transfer ¶ added in v0.3.0
func (l *SIPLeg) Transfer(ctx context.Context, target string, replaces *sipmod.ReplacesParams) error
Transfer sends an in-dialog REFER. replaces non-nil = attended (RFC 3891).
type SIPResponseLogger ¶ added in v0.5.0
type SIPResponseLogger = WhatsAppSIPController
SIPResponseLogger is an alias retained for older call sites.
type WebRTCLeg ¶
type WebRTCLeg struct {
// contains filtered or unexported fields
}
WebRTCLeg wraps a pion PeerConnection (via PCMedia) as a Leg.
func NewWebRTCLeg ¶
NewWebRTCLeg wraps a PCMedia and starts its outbound write loop.
func (*WebRTCLeg) AcceptDTMF ¶ added in v0.3.0
func (*WebRTCLeg) AcceptText ¶ added in v0.6.0
func (*WebRTCLeg) AddICECandidate ¶
func (l *WebRTCLeg) AddICECandidate(c webrtc.ICECandidateInit) error
AddICECandidate adds a remote ICE candidate.
func (*WebRTCLeg) AnsweredAt ¶
func (*WebRTCLeg) AudioReader ¶
func (*WebRTCLeg) AudioWriter ¶
func (*WebRTCLeg) ClaimDisconnect ¶ added in v0.6.0
ClaimDisconnect returns true on the first caller and false on every subsequent caller. Termination paths use this gate so only one publishes leg.disconnected.
func (*WebRTCLeg) ClearSpeakingTap ¶ added in v0.2.0
func (l *WebRTCLeg) ClearSpeakingTap()
func (*WebRTCLeg) DrainCandidates ¶
func (l *WebRTCLeg) DrainCandidates() ([]webrtc.ICECandidateInit, bool)
DrainCandidates returns buffered local ICE candidates and whether gathering is done.
func (*WebRTCLeg) Media ¶ added in v0.5.0
Media returns the underlying PCMedia (for SDP negotiation + ICE trickle).
func (*WebRTCLeg) OnTextReceived ¶ added in v0.6.0
func (*WebRTCLeg) RTTNegotiated ¶ added in v0.6.0
func (*WebRTCLeg) SIPHeaders ¶
func (*WebRTCLeg) SampleRate ¶
func (*WebRTCLeg) SetAcceptDTMF ¶ added in v0.3.0
func (*WebRTCLeg) SetAcceptText ¶ added in v0.6.0
func (*WebRTCLeg) SetSpeakingTap ¶ added in v0.2.0
type WebSocketLeg ¶ added in v0.6.0
type WebSocketLeg struct {
// contains filtered or unexported fields
}
WebSocketLeg wraps a wsmedia.Transport as a Leg, supporting both inbound (server-side upgrade) and outbound (client-side dial) directions. Both share state machinery; only Type() differs.
func NewWebSocketInboundLeg ¶ added in v0.6.0
func NewWebSocketInboundLeg(t *wsmedia.Transport, headers map[string]string, sampleRate int, rtt bool, log *slog.Logger) *WebSocketLeg
NewWebSocketInboundLeg constructs an inbound WS leg already bound to a transport. The leg goes straight to StateConnected (no ringing).
func NewWebSocketOutboundPendingLeg ¶ added in v0.6.0
func NewWebSocketOutboundPendingLeg(sampleRate int, rtt bool, log *slog.Logger) *WebSocketLeg
NewWebSocketOutboundPendingLeg constructs an outbound WS leg in StateRinging. Call AttachTransport once DialClient completes to transition to StateConnected.
func (*WebSocketLeg) AcceptDTMF ¶ added in v0.6.0
func (l *WebSocketLeg) AcceptDTMF() bool
func (*WebSocketLeg) AcceptText ¶ added in v0.6.0
func (l *WebSocketLeg) AcceptText() bool
func (*WebSocketLeg) Answer ¶ added in v0.6.0
func (l *WebSocketLeg) Answer(_ context.Context) error
func (*WebSocketLeg) AnsweredAt ¶ added in v0.6.0
func (l *WebSocketLeg) AnsweredAt() time.Time
func (*WebSocketLeg) AppID ¶ added in v0.6.0
func (l *WebSocketLeg) AppID() string
func (*WebSocketLeg) AttachTransport ¶ added in v0.6.0
func (l *WebSocketLeg) AttachTransport(t *wsmedia.Transport, headers map[string]string)
AttachTransport binds the wsmedia.Transport to the leg and starts the send loop reading from the egress pipe. headers may be nil for outbound dials where the server returned no relevant response headers.
func (*WebSocketLeg) AudioReader ¶ added in v0.6.0
func (l *WebSocketLeg) AudioReader() io.Reader
AudioReader returns inbound PCM as it arrives off the WebSocket.
func (*WebSocketLeg) AudioWriter ¶ added in v0.6.0
func (l *WebSocketLeg) AudioWriter() io.Writer
AudioWriter returns the write side of the egress pipe; the room writes mixed-minus-self PCM here, the transport's send loop reads it.
func (*WebSocketLeg) ClaimDisconnect ¶ added in v0.6.0
func (l *WebSocketLeg) ClaimDisconnect() bool
ClaimDisconnect single-flights the disconnect publication.
func (*WebSocketLeg) ClearSpeakingTap ¶ added in v0.6.0
func (l *WebSocketLeg) ClearSpeakingTap()
func (*WebSocketLeg) Context ¶ added in v0.6.0
func (l *WebSocketLeg) Context() context.Context
func (*WebSocketLeg) CreatedAt ¶ added in v0.6.0
func (l *WebSocketLeg) CreatedAt() time.Time
func (*WebSocketLeg) Hangup ¶ added in v0.6.0
func (l *WebSocketLeg) Hangup(_ context.Context) error
func (*WebSocketLeg) Headers ¶ added in v0.6.0
func (l *WebSocketLeg) Headers() map[string]string
func (*WebSocketLeg) ID ¶ added in v0.6.0
func (l *WebSocketLeg) ID() string
func (*WebSocketLeg) IsDeaf ¶ added in v0.6.0
func (l *WebSocketLeg) IsDeaf() bool
func (*WebSocketLeg) IsHeld ¶ added in v0.6.0
func (l *WebSocketLeg) IsHeld() bool
func (*WebSocketLeg) IsMuted ¶ added in v0.6.0
func (l *WebSocketLeg) IsMuted() bool
func (*WebSocketLeg) OnDTMF ¶ added in v0.6.0
func (l *WebSocketLeg) OnDTMF(_ func(rune))
func (*WebSocketLeg) OnTextReceived ¶ added in v0.6.0
func (l *WebSocketLeg) OnTextReceived(fn func(text string, lossMarker bool))
func (*WebSocketLeg) RTPStats ¶ added in v0.6.0
func (l *WebSocketLeg) RTPStats() RTPStats
func (*WebSocketLeg) RTTNegotiated ¶ added in v0.6.0
func (l *WebSocketLeg) RTTNegotiated() bool
func (*WebSocketLeg) Role ¶ added in v0.7.0
func (l *WebSocketLeg) Role() string
func (*WebSocketLeg) RoomID ¶ added in v0.6.0
func (l *WebSocketLeg) RoomID() string
func (*WebSocketLeg) SIPHeaders ¶ added in v0.6.0
func (l *WebSocketLeg) SIPHeaders() map[string]string
func (*WebSocketLeg) SampleRate ¶ added in v0.6.0
func (l *WebSocketLeg) SampleRate() int
func (*WebSocketLeg) SendDTMF ¶ added in v0.6.0
func (l *WebSocketLeg) SendDTMF(_ context.Context, _ string) error
func (*WebSocketLeg) SendText ¶ added in v0.6.0
func (l *WebSocketLeg) SendText(ctx context.Context, text string) error
func (*WebSocketLeg) SetAcceptDTMF ¶ added in v0.6.0
func (l *WebSocketLeg) SetAcceptDTMF(a bool)
func (*WebSocketLeg) SetAcceptText ¶ added in v0.6.0
func (l *WebSocketLeg) SetAcceptText(a bool)
func (*WebSocketLeg) SetAppID ¶ added in v0.6.0
func (l *WebSocketLeg) SetAppID(id string)
func (*WebSocketLeg) SetDeaf ¶ added in v0.6.0
func (l *WebSocketLeg) SetDeaf(d bool)
func (*WebSocketLeg) SetMuted ¶ added in v0.6.0
func (l *WebSocketLeg) SetMuted(m bool)
func (*WebSocketLeg) SetRole ¶ added in v0.7.0
func (l *WebSocketLeg) SetRole(r string)
func (*WebSocketLeg) SetRoomID ¶ added in v0.6.0
func (l *WebSocketLeg) SetRoomID(id string)
func (*WebSocketLeg) SetSpeakingTap ¶ added in v0.6.0
func (l *WebSocketLeg) SetSpeakingTap(io.Writer)
func (*WebSocketLeg) State ¶ added in v0.6.0
func (l *WebSocketLeg) State() LegState
func (*WebSocketLeg) Transport ¶ added in v0.6.0
func (l *WebSocketLeg) Transport() *wsmedia.Transport
Transport returns the underlying wsmedia.Transport.
func (*WebSocketLeg) Type ¶ added in v0.6.0
func (l *WebSocketLeg) Type() LegType
type WhatsAppLeg ¶ added in v0.5.0
type WhatsAppLeg struct {
// contains filtered or unexported fields
}
WhatsAppLeg is a SIP-over-TLS leg with Opus media via ICE+DTLS-SRTP. Hold/unhold/transfer are unsupported (Meta rejects re-INVITE).
func NewWhatsAppInboundLeg ¶ added in v0.5.0
func NewWhatsAppInboundLeg(dialog *sipgo.DialogServerSession, media *PCMedia, from, to string, headers map[string]string, answerSDP []byte, log *slog.Logger) *WhatsAppLeg
NewWhatsAppInboundLeg wraps an accepted UAS dialog. The 200 OK is sent by Answer() once REST issues POST /v1/legs/{id}/answer.
func NewWhatsAppOutboundPendingLeg ¶ added in v0.5.0
func NewWhatsAppOutboundPendingLeg(media *PCMedia, from, to string, log *slog.Logger) *WhatsAppLeg
NewWhatsAppOutboundPendingLeg creates a ringing-state leg without a dialog. Caller drives the INVITE asynchronously and upgrades via ConnectOutbound on 200 OK.
func (*WhatsAppLeg) AcceptDTMF ¶ added in v0.5.0
func (l *WhatsAppLeg) AcceptDTMF() bool
func (*WhatsAppLeg) AcceptText ¶ added in v0.6.0
func (l *WhatsAppLeg) AcceptText() bool
func (*WhatsAppLeg) AnswerCh ¶ added in v0.5.0
func (l *WhatsAppLeg) AnswerCh() <-chan struct{}
func (*WhatsAppLeg) AnsweredAt ¶ added in v0.5.0
func (l *WhatsAppLeg) AnsweredAt() time.Time
func (*WhatsAppLeg) AppID ¶ added in v0.5.0
func (l *WhatsAppLeg) AppID() string
func (*WhatsAppLeg) AudioReader ¶ added in v0.5.0
func (l *WhatsAppLeg) AudioReader() io.Reader
func (*WhatsAppLeg) AudioWriter ¶ added in v0.5.0
func (l *WhatsAppLeg) AudioWriter() io.Writer
func (*WhatsAppLeg) ClaimDisconnect ¶ added in v0.6.0
func (l *WhatsAppLeg) ClaimDisconnect() bool
ClaimDisconnect returns true on the first caller and false on every subsequent caller. Termination paths use this gate so only one publishes leg.disconnected.
func (*WhatsAppLeg) ClearSpeakingTap ¶ added in v0.5.0
func (l *WhatsAppLeg) ClearSpeakingTap()
func (*WhatsAppLeg) ClientDialog ¶ added in v0.5.0
func (l *WhatsAppLeg) ClientDialog() *sipgo.DialogClientSession
func (*WhatsAppLeg) ConnectOutbound ¶ added in v0.5.0
func (l *WhatsAppLeg) ConnectOutbound(dialog *sipgo.DialogClientSession) error
func (*WhatsAppLeg) Context ¶ added in v0.5.0
func (l *WhatsAppLeg) Context() context.Context
func (*WhatsAppLeg) CreatedAt ¶ added in v0.5.0
func (l *WhatsAppLeg) CreatedAt() time.Time
func (*WhatsAppLeg) From ¶ added in v0.5.0
func (l *WhatsAppLeg) From() string
func (*WhatsAppLeg) Hangup ¶ added in v0.5.0
func (l *WhatsAppLeg) Hangup(ctx context.Context) error
func (*WhatsAppLeg) Headers ¶ added in v0.6.0
func (l *WhatsAppLeg) Headers() map[string]string
func (*WhatsAppLeg) ID ¶ added in v0.5.0
func (l *WhatsAppLeg) ID() string
func (*WhatsAppLeg) IsDeaf ¶ added in v0.5.0
func (l *WhatsAppLeg) IsDeaf() bool
func (*WhatsAppLeg) IsHeld ¶ added in v0.5.0
func (l *WhatsAppLeg) IsHeld() bool
func (*WhatsAppLeg) IsMuted ¶ added in v0.5.0
func (l *WhatsAppLeg) IsMuted() bool
func (*WhatsAppLeg) Media ¶ added in v0.5.0
func (l *WhatsAppLeg) Media() *PCMedia
func (*WhatsAppLeg) OnDTMF ¶ added in v0.5.0
func (l *WhatsAppLeg) OnDTMF(f func(digit rune))
func (*WhatsAppLeg) OnTextReceived ¶ added in v0.6.0
func (l *WhatsAppLeg) OnTextReceived(_ func(text string, lossMarker bool))
func (*WhatsAppLeg) RTPStats ¶ added in v0.5.0
func (l *WhatsAppLeg) RTPStats() RTPStats
func (*WhatsAppLeg) RTTNegotiated ¶ added in v0.6.0
func (l *WhatsAppLeg) RTTNegotiated() bool
func (*WhatsAppLeg) RequestAnswer ¶ added in v0.5.0
func (l *WhatsAppLeg) RequestAnswer() error
func (*WhatsAppLeg) Role ¶ added in v0.7.0
func (l *WhatsAppLeg) Role() string
func (*WhatsAppLeg) RoomID ¶ added in v0.5.0
func (l *WhatsAppLeg) RoomID() string
func (*WhatsAppLeg) SIPHeaders ¶ added in v0.5.0
func (l *WhatsAppLeg) SIPHeaders() map[string]string
func (*WhatsAppLeg) SampleRate ¶ added in v0.5.0
func (l *WhatsAppLeg) SampleRate() int
func (*WhatsAppLeg) SendDTMF ¶ added in v0.5.0
func (l *WhatsAppLeg) SendDTMF(_ context.Context, _ string) error
func (*WhatsAppLeg) SendText ¶ added in v0.6.0
func (l *WhatsAppLeg) SendText(_ context.Context, _ string) error
func (*WhatsAppLeg) ServerDialog ¶ added in v0.5.0
func (l *WhatsAppLeg) ServerDialog() *sipgo.DialogServerSession
func (*WhatsAppLeg) SetAcceptDTMF ¶ added in v0.5.0
func (l *WhatsAppLeg) SetAcceptDTMF(a bool)
func (*WhatsAppLeg) SetAcceptText ¶ added in v0.6.0
func (l *WhatsAppLeg) SetAcceptText(_ bool)
func (*WhatsAppLeg) SetAppID ¶ added in v0.5.0
func (l *WhatsAppLeg) SetAppID(id string)
func (*WhatsAppLeg) SetDeaf ¶ added in v0.5.0
func (l *WhatsAppLeg) SetDeaf(d bool)
func (*WhatsAppLeg) SetMuted ¶ added in v0.5.0
func (l *WhatsAppLeg) SetMuted(m bool)
func (*WhatsAppLeg) SetRole ¶ added in v0.7.0
func (l *WhatsAppLeg) SetRole(r string)
func (*WhatsAppLeg) SetRoomID ¶ added in v0.5.0
func (l *WhatsAppLeg) SetRoomID(id string)
func (*WhatsAppLeg) SetSIPController ¶ added in v0.5.0
func (l *WhatsAppLeg) SetSIPController(c WhatsAppSIPController)
func (*WhatsAppLeg) SetSIPResponseLogger ¶ added in v0.5.0
func (l *WhatsAppLeg) SetSIPResponseLogger(c SIPResponseLogger)
func (*WhatsAppLeg) SetSpeakingTap ¶ added in v0.5.0
func (l *WhatsAppLeg) SetSpeakingTap(w io.Writer)
func (*WhatsAppLeg) State ¶ added in v0.5.0
func (l *WhatsAppLeg) State() LegState
func (*WhatsAppLeg) To ¶ added in v0.5.0
func (l *WhatsAppLeg) To() string
func (*WhatsAppLeg) Type ¶ added in v0.5.0
func (l *WhatsAppLeg) Type() LegType
type WhatsAppSIPController ¶ added in v0.5.0
type WhatsAppSIPController interface {
LogSyntheticResponse(req *sipproto.Request, statusCode int, reason string, body []byte, headers ...sipproto.Header)
RespondInviteSDP(dialog *sipgo.DialogServerSession, sdp []byte) error
}
WhatsAppSIPController is satisfied by *sip.Engine. The interface lives here to avoid a cyclic import on internal/sip.