8

I'm really struggling to get a complete example of a WebRTC datachannel example that I can copy/paste and it works.

I would like a JavaScript example of WebRTC datachannel with manual signaling, i.e., when the example loads, it provides the Signaling data in one text box.

I copy data manually (highlight, copy) and paste it in the peer's window which has a text box to accept that signaling data. I believe there needs to be an "answer" in the signaling data, so there need to be corresponding text boxes waiting for that input as well.

Could the example use Google's free STUN server, please?

I get really confused with bit by bit examples. I want one file, please, that contains the HTML and JavaScript (no CSS or jQuery, please). It is enough for the code to work on Chrome only.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
khalidsafir
  • 165
  • 1
  • 9
  • I think this basic question about how the data channel API works deserves a simple answer. – jib Mar 04 '19 at 15:43

1 Answers1

25

Here it is. Click the blue button below in two different tabs/windows/browsers/machines:

const output = document.getElementById('output');
const config = {
  iceServers: [{
    urls: "stun:stun.l.google.com:19302" // list of free STUN servers: https://gist.github.com/zziuni/3741933
  }]
};
const pc = new RTCPeerConnection(config);
const dc = pc.createDataChannel("chat", {
  negotiated: true,
  id: 0
});
const log = msg => output.innerHTML += `<br>${msg}`;
dc.onopen = () => chat.select();
dc.onmessage = e => log(`> ${e.data}`);
pc.oniceconnectionstatechange = e => log(pc.iceConnectionState);

chat.onkeypress = function(e) {
  if (e.keyCode != 13) return;
  dc.send(chat.value);
  log(chat.value);
  chat.value = "";
};

async function createOffer() {
  button.disabled = true;
  await pc.setLocalDescription(await pc.createOffer());
  pc.onicecandidate = ({
    candidate
  }) => {
    if (candidate) return;
    offer.value = pc.localDescription.sdp;
    offer.select();
    answer.placeholder = "Paste answer here. And Press Enter";
  };
}

offer.onkeypress = async function(e) {
  if (e.keyCode != 13 || pc.signalingState != "stable") return;
  button.disabled = offer.disabled = true;
  await pc.setRemoteDescription({
    type: "offer",
    sdp: offer.value
  });
  await pc.setLocalDescription(await pc.createAnswer());
  pc.onicecandidate = ({
    candidate
  }) => {
    if (candidate) return;
    answer.focus();
    answer.value = pc.localDescription.sdp;
    answer.select();
  };
};

answer.onkeypress = function(e) {
  if (e.keyCode != 13 || pc.signalingState != "have-local-offer") return;
  answer.disabled = true;
  pc.setRemoteDescription({
    type: "answer",
    sdp: answer.value
  });
};

pc.onconnectionstatechange = ev => handleChange();
pc.oniceconnectionstatechange = ev => handleChange();

function handleChange() {
  let stat = 'ConnectionState: <strong>' + pc.connectionState + '</strong> IceConnectionState: <strong>' + pc.iceConnectionState + '</strong>';
  document.getElementById('stat').innerHTML = stat;
  console.log('%c' + new Date().toISOString() + ': ConnectionState: %c' + pc.connectionState + ' %cIceConnectionState: %c' + pc.iceConnectionState,
    'color:yellow', 'color:orange', 'color:yellow', 'color:orange');
}
handleChange();
<p id=stat></p>
<button id="button" onclick="createOffer()">Offer:</button>
<textarea id="offer" placeholder="Paste offer here. And press Enter"></textarea> Answer: <textarea id="answer"></textarea><br> Chat: <input id="chat"><br>
<pre id="output">Chat: </pre>

Then follow these steps:

  1. In Window A, press the Offer button and copy the offer to the clipboard.
  2. In Window B, paste that offer into "Paste offer here" and hit the Enter key.
  3. Copy the answer that appears after a few seconds.
  4. Return to window A and paste that answer where it says "Paste answer here" and hit Enter.

You should now see a message saying you're "connected". Type in the chat box to chat!

If you and a friend exchange the offer/answer somehow, you now have a direct peer-to-peer connection. This should work around the world (modulo symmetric NAT routers); no data server involved.

jib
  • 40,579
  • 17
  • 100
  • 158
  • Thank you so much for replying. I can't quite figure out how to use it. Could you give me a step by step guide i.e. 1) press offer button on window 1. 2) copy text from offer text box in window 1 and paste it into offer text box in window 2.... Thank you so much. – khalidsafir Mar 04 '19 at 15:20
  • Ok let me refine the steps – jib Mar 04 '19 at 15:21
  • 3
    Thank you so much! It worked! Your answer is so well laid out, even the steps on how to use it. I'm sure it would've cost me loads of money to get this done if it wasn't for you, Stackoverflow and the internet. Amazing! – khalidsafir Mar 04 '19 at 16:24
  • This seems to work in Firefox 69.0.1 for me, but not Chrome Version 78.0.3904.97 (Official Build) (64-bit). Any ideas why? – Cameron Nov 09 '19 at 01:01
  • @Cameron Just tested it and still works for me in Chrome! Are you testing on the same machine or LAN, or between different networks? How long are you taking to cut'n'paste back and forth? Maybe Chrome times out on the answer after some number of seconds? – jib Nov 09 '19 at 17:28
  • @jib I would suspect just a couple of seconds, same machine, same window, different tabs. – Cameron Nov 10 '19 at 19:23
  • @Cameron I don't know why it doesn't work for you in Chrome in that situation. It'd be interesting to learn if this [this fiddle](https://stackoverflow.com/questions/35268660/webrtc-between-two-pages-in-the-same-machine/35300241#35300241) which automates the signaling using localStorage, works for you. – jib Nov 11 '19 at 14:00