A signaling server utility for establishing WebRTC peer-to-peer connections through Colyseus rooms. Use it to add audio/video communication between clients.
This package handles signaling only — the exchange of SDP offers/answers and ICE candidates needed to establish WebRTC connections. It does not provide state synchronization over peer-to-peer; Colyseus state sync continues to work through the server as usual.
This package provides two entry points:
| Import | Environment | Purpose |
|---|---|---|
@colyseus/webrtc |
Server | Room message handlers for WebRTC signaling |
@colyseus/webrtc/client |
Browser | WebRTCClient that consumes signaling and manages peer connections |
npm install @colyseus/webrtcSpread the signaling object into your room's messages to add all the WebRTC signaling handlers. Call onPeerDisconnected from onLeave so peers are notified when someone disconnects.
import { Room, Client } from "colyseus";
import { signaling, onPeerDisconnected } from "@colyseus/webrtc";
class VideoRoom extends Room {
messages = { ...signaling };
onLeave(client: Client) {
onPeerDisconnected(this, client);
}
}Important: WebRTC SDP payloads can exceed the default Colyseus maxPayload of 4KB. Increase it on your transport:
import { WebSocketTransport } from "@colyseus/ws-transport";
const server = defineServer({
transport: new WebSocketTransport({ maxPayload: 16 * 1024 }),
// ...
});You can mix your own message handlers alongside signaling:
class VideoRoom extends Room {
messages = {
...signaling,
chat(client: Client, message: string) {
this.broadcast("chat", `${client.sessionId}: ${message}`);
},
};
}| Message | Direction | Description |
|---|---|---|
webrtc:join |
client -> server | Client signals readiness; server replies with peer list and broadcasts to others |
webrtc:offer |
client -> server -> client | Relay SDP offer to the target peer |
webrtc:answer |
client -> server -> client | Relay SDP answer to the target peer |
webrtc:ice-candidate |
client -> server -> client | Relay ICE candidate to the target peer |
webrtc:peers |
server -> client | List of existing peer session IDs (sent on join) |
webrtc:peer-joined |
server -> client | A new peer has joined |
webrtc:peer-left |
server -> client | A peer has left |
import { Client } from "@colyseus/sdk";
import { WebRTCClient } from "@colyseus/webrtc/client";
const client = new Client("ws://localhost:2567");
const room = await client.joinOrCreate("video");
const webrtc = new WebRTCClient(room);
webrtc.onLocalStream = (stream) => {
// Attach to a <video> element for self-preview
localVideo.srcObject = stream;
};
webrtc.onPeerConnected = (peerId, stream) => {
// Attach remote stream to a <video> element
};
webrtc.onPeerDisconnected = (peerId) => {
// Remove the peer's video element
};
// Request camera/mic and start signaling
await webrtc.join({ audio: true, video: true });
// Later, to stop and clean up:
webrtc.leave();
room.leave();new WebRTCClient(room, options?)room— Any object withsend(type, message)andonMessage(type, callback)(e.g. a ColyseusRoominstance).options.iceServers— Custom ICE servers. Defaults to Google STUN servers.
| Method | Description |
|---|---|
join(constraints?) |
Request user media with the given MediaStreamConstraints and start signaling. Defaults to { audio: true, video: true }. |
leave() |
Close all peer connections, stop local tracks, and unbind signaling listeners. |
| Callback | Signature | Description |
|---|---|---|
onLocalStream |
(stream: MediaStream) => void |
Fired after getUserMedia succeeds |
onPeerConnected |
(peerId: string, stream: MediaStream) => void |
Fired when a remote peer's media stream is received |
onPeerDisconnected |
(peerId: string) => void |
Fired when a peer connection closes |
| Property | Type | Description |
|---|---|---|
localStream |
MediaStream | null |
The local media stream |
peers |
Map<string, RTCPeerConnection> |
Active peer connections keyed by session ID |
streams |
Map<string, MediaStream> |
Remote media streams keyed by session ID |
The example/ directory contains a full working demo with a Colyseus server and a React client.
cd example
npm install
npm run devThis starts two processes concurrently:
- Server on
ws://localhost:2567(Colyseus + WebSocket transport) - Client on
http://localhost:3000(Vite + React)
Open http://localhost:3000 in two browser tabs (or two devices on the same network) to test video calling. The browser will ask for camera/microphone permissions.
Client A Server Client B
| | |
|--- webrtc:join ---------->| |
|<-- webrtc:peers [] | |
| | |
| |<-------- webrtc:join ------|
| |--------- webrtc:peers [A]->|
|<-- webrtc:peer-joined B --| |
| | |
| |<------ webrtc:offer (A) ---|
|<-- webrtc:offer (B) ------| |
| | |
|--- webrtc:answer (B) ---->| |
| |------- webrtc:answer (A)-->|
| | |
|<-------- ICE candidates exchanged via server --------->|
| | |
|<=============== peer-to-peer audio/video ==============>|
MIT