P2P-only pub/sub
The same channel pub/sub as the Pub/Sub channels demo, but this page never makes a pub/sub call until a peer-to-peer data channel is open. The signaling WebSocket is only used to find the peer and set up the connection (SDP/ICE); subscriptions and messages travel peer to peer.
- Start publishing in the Publisher panel.
- Start subscribing here, or open the share link in another tab or device. Wait for the status to show P2P open.
- Send to a channel. Subscription changes made before the channel opens are applied once it does.
Why wait for the data channel? subscribe() and unsubscribe() send with WebSocket fallback enabled, so if no data channel is open they go through the signaling server. publishToChannel() and sendData() never fall back unless you pass allowFallback: true. This page waits for dataChannelOpen before subscribing, so nothing is relayed. As in the channels demo, channels are filtered by each subscriber, not by the publisher.
Publisher
Not publishingSend a message
Connected viewers
Subscriber
Not connectedChannel subscriptions
Changes are sent to the publisher once the P2P data channel is open.
Key SDK calls in this demo
// Publisher: data-only, joins the room from the URL
await pub.connect();
await pub.joinRoom({ room });
await pub.announce({ streamID });
pub.publishToChannel('alerts', { message: 'Hi' }); // data channels only, no fallback
// Subscriber: only touch pub/sub once the P2P channel is open
let p2pOpen = false;
sub.addEventListener('dataChannelOpen', () => { p2pOpen = true; sub.subscribe(['general']); });
sub.addEventListener('dataChannelClose', () => { p2pOpen = false; });
sub.addEventListener('channelMessage', (e) => show(e.detail.channel, e.detail.data));
await sub.connect();
await sub.joinRoom({ room });
await sub.view(streamID, { audio: false, video: false });
if (p2pOpen) sub.subscribe('updates'); // otherwise queue it locally