WebRTC: unable to successfully complete data transfer using DataChannel

I am having trouble setting up a WebRTC session and am trying to simplify this problem as much as possible. So I wrote a simple copy and paste example where you simply paste the sentence / response into web forms and click Submit.

HTML + JS, all in one file, can be found here: http://pastebin.com/Ktmb3mVf

I am on the local network and therefore delete the initialization process of the ICE server to make this example as possible as possible.

Here are the steps that I follow in the example:

Page 1

  • Page 1 (loads the page), enters the name of the channel (e.g. test ) and presses create .

  • A new Host object is created, new PeerConnection() and createDataChannel .

  • createOffer , and the received offerSDP inserted into the offer text area.

Page 2

  1. Copy offerSDP from page 1 and paste the offer text into the text on page 2, click join .

  2. A new Guest object, PeerConnection and the ondatachannel handler are ondatachannel .

  3. setRemoteDescription is called for the Guest object with the offerSDP data.

  4. createAnswer is called and the result is inserted into the answer textarea field.

Page 1

  1. answerSDP copied from page 2 and pasted into the answer text area of ​​page 1, submit answer .

  2. Host.setRemoteDescription is called with answerSDP data. This creates a SessionDescription , then peer.setRemoteDescription is peer.setRemoteDescription with the resulting data.

These are the steps taken in this example, but it seems I am missing something critical. After the remoteDescription providers are set using answerSDP , I try to send a test message to dataChannel :

Chrome 40

 "-- complete" > host.dataChannel.send('hello world'); VM1387:2 Uncaught DOMException: Failed to execute 'send' on 'RTCDataChannel': RTCDataChannel.readyState is not 'open' 

Firefox 35

 "-- complete" ICE failed, see about:webrtc for more details > host.dataChannel.send('hello world'); InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable 

I also had a more complicated demo with the WebSocket signaling server and ICE candidates, but it was getting the same error. Therefore, I hope that this simplification will help to identify the problem.

Again, a link to a single file: http://pastebin.com/Ktmb3mVf

+5
source share
1 answer

For webRTC clients to connect to each other, you need ICE. Although STUN and TURN, which you do not need for such a test, are part of this, even without these helpers, you still need to use ICE to tell the other end to which the IP / port / protocol is connected.

There are two ways to do this: Google "trickle ice", where the SDP (response / offer) is transmitted without any ICE candidates. Then they are transferred along a separate signal layer and added as they are detected. This speeds up the connection process because ICE takes time and some later ICE candidates may not be needed.

The classic method is to wait until all ICE candidates have been collected, and then generate SDP with those already included.

I changed your latest version to do this: http://pastebin.com/g2YVvrRd

You also need to wait for the datachannel / connection to become available before you can use it, so I moved the sending of the message to the onopen channel event.

Significant changes in the source code:

Interface callbacks have been removed from Host.prototype.createOffer and Guest.prototype.createAnswer, instead we attach the provided callback function to the corresponding objects for later use.

 self.cb = cb; 

The host and guest have an additional ICE handler for PeerConnection:

 var self = this; this.peer.onicecandidate = function (event) { // This event is called for every discovered ICE candidate. // If this was trickle ICE, you'd pass them on here. // An event without an actual candidate signals the end of the // ICE collection process, which is what we need for classic ICE. if (!event.candidate) { // We fetch the up to date description from the PeerConnection // It now contains lines with the available ICE candidates self.offer = self.peer.localDescription; // Now we move on to the deferred callback function self.cb(self.offer); } } 

For the guest user, self.offer becomes self.answer

Interface handler $ ("# submitAnswer"). click () no longer sends a message, but is sent when the datanel is ready in the onopen event defined in setChannelEvents ().

 channel.onopen = function () { console.log('** channel.onopen'); channel.send('hello world!'); }; 
+1
source

Source: https://habr.com/ru/post/1212723/


All Articles