RTCDataChannel for signaling?

I read this article to solve the alarm. The author mentions signaling using RTCDataChannel when connections are established.

Using RTCDataChannel for signaling

A signaling service is required to start a WebRTC session.

However, once a connection is established between two peers, the RTCDataChannel can, in theory, take on the role of a signaling channel. This can reduce the delay for signaling — as messages fly straight — and help reduce signaling server throughput and processing costs. We don’t have a demo, but watch this space!

Why do I need an alarm, since the connections are already established?

+5
source share
1 answer

Each side initially states which audio and / or video tracks it sends so that it can open the required number of ports, as well as determine the permissions and formats that work for both peers. The signaling channel is needed to send the resulting SDP proposal / response, as well as flow ICE candidates for each port, on the other hand.

After connecting, if you leave this setting yourself - basically never add tracks to the connection, do not delete or change the attributes of the tracks significantly - then you will no longer need an alarm server.

If you do change any of these things, then reconciliation is required, which is what it looks like: another round on the signal channel, similar to the first.

The reasons for adding the track may be a second camera, a different video source (possibly from another participant) or, possibly, screen sharing, something like that.

The article is true that a data channel can be used. Here is a demo ! (Firefox just for now.)

The article is incorrect about the need for an alarm service if you have another means of detection, as the demonstration proves.

The initial connection is for chat only, but both sides can click to add video to the mix. Re-negotiation for this is done via the data channel (since there is no signaling server!)

Instructions for using the script:

  • There is no server (since this is a fiddle), so click the Offer button and copy the offer.
  • Paste the sentence in the same place in the same violin on another tab or on another machine.
  • Press ENTER, then copy the resulting answer and paste it into the first script.
  • Press ENTER again (not addTrack !)
  • You are now connected to two data channels: one for chat and one for signaling.
  • Now click addTrack at both ends and the video should appear on the other end.
  • Click addTrack in the other direction and you should have the video in both directions.

 var dc = null, sc = null, pc = new mozRTCPeerConnection(), live = false; pc.onaddstream = e => v2.mozSrcObject = e.stream; pc.ondatachannel = e => dc? scInit(sc = e.channel) : dcInit(dc = e.channel); v2.onloadedmetadata = e => { log("Face time!"); }; function addTrack() { navigator.mediaDevices.getUserMedia({video:true, audio:true}) .then(stream => pc.addStream(v1.mozSrcObject = stream)); } pc.onnegotiationneeded = e => { pc.createOffer().then(d => pc.setLocalDescription(d)).then(() => { if (live) sc.send(JSON.stringify({ "sdp": pc.localDescription })); }).catch(failed); }; function scInit() { sc.onmessage = e => { var msg = JSON.parse(e.data); if (msg.sdp) { var desc = new mozRTCSessionDescription(JSON.parse(e.data).sdp); if (desc.type == "offer") { pc.setRemoteDescription(desc).then(() => pc.createAnswer()) .then(answer => pc.setLocalDescription(answer)).then(() => { sc.send(JSON.stringify({ "sdp": pc.localDescription })); }).catch(failed); } else { pc.setRemoteDescription(desc).catch(failed); } } else if (msg.candidate) { pc.addIceCandidate(new mozRTCIceCandidate(msg.candidate)).catch(failed); } }; } function dcInit() { dc.onopen = () => { live = true; log("Chat!"); }; dc.onmessage = e => log(e.data); } function createOffer() { button.disabled = true; dcInit(dc = pc.createDataChannel("chat")); scInit(sc = pc.createDataChannel("signaling")); pc.createOffer().then(d => pc.setLocalDescription(d)).catch(failed); pc.onicecandidate = e => { if (e.candidate) return; if (!live) { offer.value = pc.localDescription.sdp; offer.select(); answer.placeholder = "Paste answer here"; } else { sc.send(JSON.stringify({ "candidate": e.candidate })); } }; }; offer.onkeypress = e => { if (e.keyCode != 13 || pc.signalingState != "stable") return; button.disabled = offer.disabled = true; var obj = { type:"offer", sdp:offer.value }; pc.setRemoteDescription(new mozRTCSessionDescription(obj)) .then(() => pc.createAnswer()).then(d => pc.setLocalDescription(d)) .catch(failed); pc.onicecandidate = e => { if (e.candidate) return; if (!live) { answer.focus(); answer.value = pc.localDescription.sdp; answer.select(); } else { sc.send(JSON.stringify({ "candidate": e.candidate })); } }; }; answer.onkeypress = e => { if (e.keyCode != 13 || pc.signalingState != "have-local-offer") return; answer.disabled = true; var obj = { type:"answer", sdp:answer.value }; pc.setRemoteDescription(new mozRTCSessionDescription(obj)).catch(failed); }; chat.onkeypress = e => { if (e.keyCode != 13) return; dc.send(chat.value); log(chat.value); chat.value = ""; }; var log = msg => div.innerHTML += "<p>" + msg + "</p>"; var failed = e => log(e.name + ": " + e.message + " line " + e.lineNumber); 
 <video id="v1" height="120" width="160" autoplay muted></video> <video id="v2" height="120" width="160" autoplay></video><br> <button id="button" onclick="createOffer()">Offer:</button> <textarea id="offer" placeholder="Paste offer here"></textarea><br> Answer: <textarea id="answer"></textarea><br> <button id="button" onclick="addTrack()">AddTrack</button> <div id="div"></div><br> Chat: <input id="chat"></input><br> 
+5
source

All Articles