11

I'm trying to send text over an RTCPeerConnection with RTCDataChannel using WebRTC's adapter.js, but I'm getting the following error:

Uncaught InvalidStateError:
Failed to execute 'send' on 'RTCDataChannel':
RTCDataChannel.readyState is not 'open'

My code is available via this fiddle and below:

var peerConnection = new RTCPeerConnection(null, {
  optional: [{
    RtpDataChannels: true
  }]
});

peerConnection.ondatachannel = function(event) {
  receiveChannel = event.channel;
  receiveChannel.onmessage = function(event){
    alert(event.data);
  };
};

var dataChannel = peerConnection.createDataChannel("data", {reliable: false});
dataChannel.send("Hello");

Am I doing anything wrong?

mhenry
  • 1,487
  • 5
  • 17
  • 31
  • So it looks like you have never worked with RTC before. The sites noted below are good to start with, but I suggest you to read [this](http://stackoverflow.com/a/21103641/2844473). It will talk you in to setting up an RTC connection. – MarijnS95 Mar 18 '14 at 11:43
  • Offtopic: rtp data channels are deprecated. You should use sctp ones. [here](https://groups.google.com/forum/#!topic/discuss-webrtc/y2A97iCByTU) you can find more info – Svetlin Mladenov Mar 28 '14 at 12:04

2 Answers2

10

I wrote the following code this morning that uses RTCPeerConnection and RTCDataChannel in a single page. The order in which these functions are declared is important.

var localPeerConnection, remotePeerConnection, sendChannel, receiveChannel;

localPeerConnection = new RTCPeerConnection(null, {
  optional: [{
    RtpDataChannels: true
  }]
});

localPeerConnection.onicecandidate = function(event) {
  if (event.candidate) {
    remotePeerConnection.addIceCandidate(event.candidate);
  }
};

sendChannel = localPeerConnection.createDataChannel("CHANNEL_NAME", {
  reliable: false
});

sendChannel.onopen = function(event) {
  var readyState = sendChannel.readyState;
  if (readyState == "open") {
    sendChannel.send("Hello");
  }
};

remotePeerConnection = new RTCPeerConnection(null, {
  optional: [{
    RtpDataChannels: true
  }]
});

remotePeerConnection.onicecandidate = function(event) {
  if (event.candidate) {
    localPeerConnection.addIceCandidate(event.candidate);
  }
};

remotePeerConnection.ondatachannel = function(event) {
  receiveChannel = event.channel;
  receiveChannel.onmessage = function(event) {
    alert(event.data);
  };
};

localPeerConnection.createOffer(function(desc) {
  localPeerConnection.setLocalDescription(desc);
  remotePeerConnection.setRemoteDescription(desc);
  remotePeerConnection.createAnswer(function(desc) {
    remotePeerConnection.setLocalDescription(desc);
    localPeerConnection.setRemoteDescription(desc);
  });
});
mhenry
  • 1,487
  • 5
  • 17
  • 31
  • what is the purpose of optional "RtpDataChannels" here ? – Sukhmeet Singh Apr 10 '14 at 14:36
  • I actually have no idea. I included it because I saw other examples using it; mainly on the [official WebRTC site](http://www.webrtc.org/chrome). It should default to true without the optional parameters, but I didn't want to risk something not working by assuming defaults that could be implemented differently across browsers. – mhenry Apr 11 '14 at 15:48
  • RtpDataChannels is required if we want to make use of the DataChannels API on Firefox. reference : https://developer.mozilla.org/en-US/docs/Web/Guide/API/WebRTC/WebRTC_basics#options_%28See_.22Note.22_above_first.%29 – mido Jan 08 '15 at 02:09
  • 2
    RtpDataChannels was an old Chrome thing actually, should not be used anymore. – jib Aug 17 '16 at 02:41
  • I think this should be included in official docs or something. Thanks a lot man... – Armaan Nov 10 '21 at 12:12
2

You can't just create peerConnection, dataChannel and start using it right away. And btw you don't have 2 peers here...

  1. You'll need to create peerConnections object in the 2 peers
  2. Transfer SDP's
  3. get ice candidates
  4. and only after that the dataChannel is open and then you can send information on top of it

I suggest start by reading this, it will give you knowledge of the basic concepts And then continue to this awesome code lab by Sam Dutton.

Update to answer mhenry's request: Here's the entirety of setting up data channel in one class: https://gist.github.com/shacharz/9661930 Follow the comments, you'll just need to:

  1. Add signaling, sending SDP's ice candidates to the other peer (targetId)
  2. If you'de like to handle all the connection lost and stuff like that by a higher level logic.
  3. Make sure that when receiving an sdp you call the "Handlmessage" method
  4. Use the class with its public methods: SetupCall, Send, Close
shacharz
  • 213
  • 3
  • 8
  • 1
    I guess what I'm looking for is a straight forward example of using `RTCPeerConnection` and `RTCDataChannel` in a single page (copy text from one area to another, or like in my example code pushing text to an alert) without the bloat of using `RTCPeerConnection` for video or JavaScript code for modifying the user interface. A lot of the code available on the internet that I've seen is messy and has been copied from place to place, so it includes functions with unreachable code. – mhenry Mar 18 '14 at 12:53
  • Do you want to see a 'dumbed down' local example of 2 peers in a single page? Or an example that you'll need 2 tabs to run, which will also work between 2 remote machines? – shacharz Mar 19 '14 at 08:24
  • The latter would be the best. – mhenry Mar 19 '14 at 21:18
  • I also have an example, although the code is a mess. Instead of textboxes, it uses a key of four characters and a signalling server. When you get the key, the only thing you need to do is share that with someone else. If the other person enters that key, the server knows between which computers it should exchange data (over websockets, as these can send data 2 ways, where you would need to reopen an xhr - but that is also an option). It does not use data channels but stream channels for audio and video. I am still searching for the version with datachannels though. – MarijnS95 Mar 20 '14 at 08:14