-
Notifications
You must be signed in to change notification settings - Fork 2
WebRTC
GABPBX 1.1.2 makes chan_sofia a WebRTC endpoint. A browser running a
SIP-over-WebSocket library (for example SIP.js or JsSIP) can register, place a
call and receive a call, with two-way audio, two-way video, and relayed
DataChannels, secured by DTLS-SRTP. The implementation is self-contained: there is no pjproject and
no libnice in the tree. The same forked RTP engine that carries plain SIP
calls carries WebRTC, so non-WebRTC media is unchanged.
This page covers how it fits together and how to turn it on. The per-feature catalogue is Features; the security model is Security.
- Two WSS browsers can hold a real two-way audio call end to end.
- Two-way video (VP8 or H.264) rides on top of the audio call.
- Opus passes through both-Opus calls without transcoding.
- Two browsers can open a DataChannel and exchange text or binary messages relayed back-to-back through GABPBX.
- Setup, teardown and NAT survival all route correctly back over the accepted WebSocket.
| Concern | Mechanism | RFC | Where |
|---|---|---|---|
| SIP transport | SIP over secure WebSocket | RFC 7118 | channels/chan_sofia.c:11568-11660 |
| Media keying | DTLS-SRTP | RFC 5763/5764 | res/res_rtp_gabpbx.c:1001 |
| Connectivity | ICE-lite STUN responder | RFC 8445 | res/res_rtp_gabpbx.c:1265 |
| One socket per stream | rtcp-mux | RFC 5761 | channels/sofia/sofia_sdp.c:268 |
| Multiplexed media | BUNDLE + a=mid | RFC 8843 | channels/sofia/sofia_sdp.c:359 |
| Packet demux | STUN / DTLS / SRTP by first byte | RFC 7983 | res/res_rtp_gabpbx.c:1732 |
| Audio codec | Opus | RFC 7587 | channels/sofia/sofia_sdp.c:172 |
| DataChannel transport | SCTP over DTLS | RFC 8831 | channels/sofia/sofia_datachannel.c |
| DataChannel setup | DCEP OPEN/ACK | RFC 8832 | channels/sofia/sofia_datachannel.c |
| DataChannel SDP | m=application UDP/DTLS/SCTP | RFC 8841 | channels/sofia/sofia_sdp.c |
The browser registers and signals over a secure WebSocket. chan_sofia opens a
dedicated WSS listener from wssbindport. sofia-sip looks for fixed certificate
filenames inside a cert directory (agent.pem/cafile.pem for TLS,
wss.pem/ca-bundle.crt for WSS), so chan_sofia bridges the operator's real
files to those names automatically:
-
tlscertfilemay be the cert directory or the real cert+key file. When it names a file, the directory is derived from it andagent.pemis soft-linked to that file — so you can point straight at an externally managed certificate without renaming it.tlscafileis likewise soft-linked tocafile.pem. - The WSS-named files are then soft-linked from the TLS ones (
wss.pemfromagent.pem,ca-bundle.crtfromcafile.pem). All links are created only when missing and never overwrite existing files.
Certificate immunity: if a configured TLS or WSS listener has no usable
certificate, chan_sofia logs an error and disables only that listener — UDP,
TCP and WS keep serving and the module still loads, instead of the whole driver
failing. tlsenable/wsenable/wssenable (default on) explicitly turn a
listener off even when its bind port is set.
A browser's Contact host is always a placeholder, so in-dialog ACK/BYE
are routed back over the exact accepted WebSocket connection rather than to the
Contact (channels/chan_sofia.c:542-589), and ;transport=wss is appended to
the request-URI (mandatory for WSS per RFC 7118).
A WebRTC offer/answer uses the UDP/TLS/RTP/SAVPF media transport
(channels/sofia/sofia_sdp.c:380) instead of plain RTP/AVP. The SDP carries
a=ice-lite, ICE ufrag/pwd/candidate, a=fingerprint:sha-256, a=setup,
a=rtcp-mux, a=mid, and a session-level a=group:BUNDLE.
GABPBX is permanently the controlled, lite ICE agent
(res/res_rtp_gabpbx.c:1265, role AST_RTP_ICE_ROLE_CONTROLLED). It does not
gather candidates or send checks; it answers the browser's STUN binding
requests, learns the peer transport address from the first authenticated check,
and latches the nominated pair on USE-CANDIDATE. The STUN responder is armed in
sofia_webrtc_provision_offer before the offer leaves the wire, so the
browser's earliest connectivity checks are never dropped into a dead window.
Keys are not in the SDP. After ICE connectivity, a DTLS handshake runs over the
media path; SRTP keys are exported from it. The cert is ephemeral, self-signed,
EC P-256, CN gabpbx. a=setup advertises the engine's real negotiated role so
the two sides never both try to be the DTLS client. A dedicated retransmit
scheduler honors DTLS exponential backoff. gabpbx_dtls engine at
res/res_rtp_gabpbx.c:1001; key install at :1015-1071.
The trust anchor is the SDP a=fingerprint (RFC 8827/5763): the
self-signed cert cannot chain-verify, so on handshake completion the engine
demands a peer cert, requires a stored remote fingerprint, and does a
hash-matched X509_digest + memcmp against the SDP fingerprint. Any absence
or mismatch fails the call closed as a possible MITM
(res/res_rtp_gabpbx.c:1097-1120).
With rtcp-mux, a single socket per stream carries STUN, DTLS and
(S)RTP/RTCP interleaved. __rtp_recvfrom demuxes by the first byte
(res/res_rtp_gabpbx.c:1732-1786): STUN to the ICE responder, DTLS records to
the handshake, RTP to SRTP-unprotect, with muxed SRTCP dropped and a flood
guard. This path is dormant unless DTLS is active, so plain RTP is untouched.
Audio is the tagged BUNDLE transport. A browser typically offers audio + video
- datachannel; the datachannel m-line is accepted and bundled on the audio
DTLS (see §9 below), while any genuinely unsupported m-line is reflected back
as a port-0 rejection in order (RFC 3264 §6) rather than 488-ing the whole
session (
channels/sofia/sofia_sdp.c). This is what lets a browser's audio+video+datachannel offer be answered cleanly.
Video does not ride the audio BUNDLE. The accepted/offered m=video is
emitted on its own port with its own ICE/fingerprint/setup/candidate,
a=rtcp-mux, and a distinct a=mid — a separate DTLS association from the
audio (channels/sofia/sofia_sdp.c:386-491). GABPBX both accepts a browser's
offered video (answerer) and offers video itself (offerer), so two browsers can
see each other.
A both-Opus call passes through with no transcoding. The three fixes that made browser-to-browser Opus clean:
- codec selection now knows Opus,
- the format rate returns 48 kHz, so the RTP TX timestamp advances +960 per 20 ms frame (not +160),
- the RTP smoother no longer re-chunks Opus's variable-size frames
(
res/res_rtp_gabpbx.c:2840-2845).
Opus is offered with useinbandfec=1;usedtx=0 and channels=2
(channels/sofia/sofia_sdp.c:172-174).
GABPBX bridges WebRTC DataChannels back-to-back between two WebRTC legs.
When a browser offers m=application UDP/DTLS/SCTP webrtc-datachannel, the
channel is negotiated on the same BUNDLE'd DTLS transport as the audio (no
separate association), and the SCTP association is carried by an optional
usrsctp build.
-
Offer and answer, both ways. GABPBX accepts an inbound DataChannel offer
and offers one to the bridged far leg, so a
createDataChannelbetween two browsers reaches end to end. The far leg negotiates its own SCTP; GABPBX proxies the DCEPOPEN/ACK(RFC 8832) and relays each message preserving its PPID, so both text and binary channels cross. - One worker lane. The receive path runs on a single dedicated worker off the RTP instance lock; the relay reaches the far leg with a non-blocking channel trylock + reference and releases all channel locks before the SCTP send, so the two legs can never deadlock against each other.
-
Bounded.
a=max-message-sizeis honored per RFC 8841 §6 (absent → the 64 KiB default; explicit0→ unbounded, hard-capped); the negotiated stream count is capped to bound memory. - Clean teardown. When a leg ends, its SCTP socket is abortively closed (SO_LINGER 0) so no library timer outlives the channel.
It is build-gated by usrsctp (HAVE_USRSCTP) and opt-in per peer with
datachannel=yes (inherited from [general], requires webrtc=yes). Without
the usrsctp build, or with datachannel=no, an offered datachannel m-line is
simply port-0 rejected and audio/video are unaffected. Implementation:
channels/sofia/sofia_datachannel.c plus the engine DTLS-appdata seam in
main/rtp_engine.c / res/res_rtp_gabpbx.c.
WebRTC is opt-in per peer with webrtc=yes, which is inherited from
[general] and can be overridden per peer
(channels/chan_sofia.c:2181, :2591, :13173).
[general]
; cert DIR, or the real cert+key FILE (agent.pem is soft-linked to it).
; WSS names (wss.pem / ca-bundle.crt) are auto-linked from the TLS ones.
tlscertfile=/etc/gabpbx/keys/gabpbx.pem
tlscafile=/etc/gabpbx/keys/ca.crt
; secure WebSocket listener for browsers
wssbindaddr=0.0.0.0
wssbindport=8089
; tlsenable / wsenable / wssenable default to yes; set to no to disable a
; listener even when its bind port is set (e.g. a node with no certificate).
; default new peers to WebRTC (or set per peer)
webrtc=yes
; relay browser-to-browser DataChannels (needs a usrsctp build)
datachannel=yes
[browser-200]
type=peer
host=dynamic
defaultuser=browser-200
secret=change-this-secret
context=internal
webrtc=yes
disallow=all
allow=opus
allow=ulawA webrtc=yes peer fails the call rather than ever falling back to insecure
media, and direct media is force-disabled on any DTLS/SRTP leg so keys are
never bridged or disclosed (channels/chan_sofia.c:3129-3134).
-
sip show peer <name>andsip show settingsreport the WebRTC state of a peer and the global default. - A reverse proxy (for example nginx) terminating browser HTTPS/WSS in front of
chan_sofiais a common deployment; route the WebSocket to thewssbindportlistener. When debugging the WSS leg, capture on the loopback the proxy forwards to. - After editing
sofia.confas root, restore ownership so GABPBX can read it (chown gabpbx:gabpbx /etc/gabpbx/sofia.conf).
- Full (non-lite) ICE with candidate gathering and TURN — GABPBX is the ICE-lite controlled agent by design.
SIP — chan_sofia
Subsystems
Realtime & data
Operations