RTCPeerConnection wrapper minimal — signaling-agnostic, offer/answer/ICE + data channels.
Module webrtc | Source packages/front/fw/src/dom/net/webrtc.js | Deps none | Worker-safe no
Thin wrapper around RTCPeerConnection and RTCDataChannel. Provides helpers for offer/answer SDP, ICE candidate management with automatic queue before setRemoteDescription, data channels with a send queue before opening, and structured WebRTCError errors. Signaling is out of scope — the caller manages SDP/ICE transport (WS, REST, BroadcastChannel, etc.).
Resolve
const webrtc = runtime.resolve('webrtc');
// Returns: { peer, WebRTCError }
API
| Method | Signature | Returns |
|---|---|---|
peer |
(config?: RTCConfiguration) => Peer |
WebRTC Peer instance |
WebRTCError |
Constructor on the resolved API | Structured error (see below) |
WebRTCError
Structured error wrapping all WebRTC rejections. Fields: kind (stable string), message, cause (underlying DOMException).
Defined inside the factory (worker-safe) and exposed on the resolved API, not as a top-level export. For
instanceof, use the class from the resolved module:const { WebRTCError } = runtime.resolve('webrtc'); err instanceof WebRTCError.nameis set viaObject.definePropertyto surviveError.prototypefreezing by sanity.
kind |
Origin |
|---|---|
'setLocal' |
setLocalDescription failed |
'setRemote' |
setRemoteDescription failed |
'addIceCandidate' |
ICE ingestion failed (after flush) |
'createOffer' |
SDP negotiation failed |
'createAnswer' |
SDP negotiation failed |
'sendOverflow' |
DataChannel send queue exceeded (sendQueueMax) |
'sendClosed' |
send() called after channel close |
Peer object
| Method / Property | Signature | Description |
|---|---|---|
createOffer |
(opts?) => Promise<RTCSessionDescriptionInit> |
Creates an SDP offer |
createAnswer |
(opts?) => Promise<RTCSessionDescriptionInit> |
Creates an SDP answer |
setLocal |
(desc) => Promise<void> |
setLocalDescription |
setRemote |
(desc) => Promise<void> |
setRemoteDescription + flush ICE queue |
addIceCandidate |
(candidate) => Promise<void> |
Candidate queued before setRemote, applied after |
dataChannel |
(label: string, opts?) => DataChannelWrapper |
Creates a data channel |
addTrack |
(track, ...streams) => RTCRtpSender |
Adds a media track |
removeTrack |
(sender) => void |
Removes a track |
on |
(event: string, cb: Function) => () => void |
Adds a listener (returns unsubscribe) |
off |
(event: string, cb: Function) => void |
Removes a listener |
close |
() => void |
Closes the connection, all data channels, and removes listeners |
connectionState |
getter: string |
Connection state |
iceConnectionState |
getter: string |
ICE state |
pendingIce |
getter: number |
Number of ICE candidates pending flush |
raw |
getter: RTCPeerConnection |
Native instance |
Events: 'icecandidate', 'track', 'datachannel', 'connectionstatechange', 'icegatheringstatechange', 'iceconnectionstatechange', 'icecandidateerror'
DataChannelWrapper object
| Property / Method | Description |
|---|---|
onopen |
Setter — callback on open; automatic flush of the send queue |
onmessage |
Setter — callback on receive (data, event) |
onclose |
Setter — callback on close; clears the send queue |
onerror |
Setter — callback on error (receives WebRTCError on overflow/sendClosed) |
send(data) |
Sends or queues until open. Throws WebRTCError if closed/overflow |
close() |
Closes the channel and removes all listeners |
readyState |
getter: 'connecting' | 'open' | 'closing' | 'closed' |
queuedAmount |
getter: number — messages pending flush |
raw |
getter: RTCDataChannel — native channel |
dataChannel(label, opts) options
| Option | Type | Default | Description |
|---|---|---|---|
sendQueueMax |
number |
1024 |
Max send queue size before sendOverflow |
| (others) | — | — | All native RTCDataChannelInit fields passed through |
Examples
P2P connection (data channel)
const webrtc = runtime.resolve('webrtc');
// Offerer side
const localPeer = webrtc.peer({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] });
const ch = localPeer.dataChannel('chat', { ordered: true });
ch.onopen = () => ch.send('Hello!');
ch.onmessage = (data) => console.log('Got:', data);
localPeer.on('icecandidate', (candidate) => {
// Send candidate to remote via signaling (WS, REST...)
signalingSocket.send(JSON.stringify({ type: 'ice', candidate }));
});
const offer = await localPeer.createOffer();
await localPeer.setLocal(offer);
// Send the offer via signaling
signalingSocket.send(JSON.stringify({ type: 'offer', sdp: offer }));
// Receive answer via signaling
signalingSocket.on('answer', async (sdp) => {
await localPeer.setRemote(sdp);
});
Receiving a data channel (answerer side)
const remotePeer = webrtc.peer();
remotePeer.on('datachannel', (event) => {
const ch = event.channel;
ch.onmessage = (data) => console.log('Remote says:', data);
});
// Receive offer, create answer
const answer = await remotePeer.createAnswer();
await remotePeer.setLocal(answer);
Access to native API
// For any functionality not exposed by the wrapper
const rtc = peer.raw; // native RTCPeerConnection
rtc.getStats().then(stats => console.log(stats));
Notes
- Signaling out of scope — this module provides no transport for SDP/ICE exchange. Use
ws,ajax, orbroadcastChannelas appropriate. - Not available in Web Workers —
RTCPeerConnectionis main-thread only. - ICE queue:
addIceCandidate()beforesetRemoteDescriptionbuffers candidates, flushed in order aftersetRemote(). Individual flush errors are emitted via'icecandidateerror'but do not interrupt the flush. - Send queue:
dc.send()before the'open'state buffers messages.sendQueueMaxcontrols the limit; exceeding it →WebRTCError('sendOverflow')viaonerror+ throw. close()also closes allDataChannelWrapperinstances created by this peer, releasing their listener arrays.- Error handling: switch on
err.kindto distinguish cases ('sendOverflow','setRemote', etc.) in a stable way across versions. - For camera/microphone, obtain tracks via
mediathenpeer.addTrack(track).
See also
- ws — possible signaling transport
- broadcastChannel — local signaling (same origin, multi-tab)
- media — obtain getUserMedia tracks