4

I'm having a strange problem with RTCDataChannel.

I'm doing some research on WebRTC and I have working WebRTC audio/video chat already. Now I wanted to add text chat and file sharing to it using RTCDataChannel.

I've created RTCDataChannel like this:

var dataChannelOptions = {
    reliable: true,
    maxRetransmitTime: "2000"
};

dataChannel = yourConnection.createDataChannel("testDataChannel", dataChannelOptions);

dataChannel.onerror = function (error) {
    console.log("dataChannel.OnError:", error);
};

dataChannel.onmessage = function (event) {
    console.log("dataChannel.OnMessage:", event);
};

dataChannel.onopen = function (event) {
    console.log("dataChannel.OnOpen", event);
    dataChannel.send("Hello World!");
};

dataChannel.onclose = function (event) {
    console.log("dataChannel.OnClose", event);
};

And only thing that I receieve on both sides is log from first line of dataChannel.onopen. I don't receive log from dataChannel.onmessage.

No errors..

When I manually call dataChannel.send result is the same.

Tested on:
Google Chrome (50.0.2661.94)
Firefox (45.0.2)

Anyone can help with that?

4 Answers4

20

this is a common mistake people make, you are creating datachannel on both browsers, but not accepting on either, you need use the RTCPeerConnection's ondatachannel event and set the listeners

mido
  • 24,198
  • 15
  • 92
  • 117
6

I was facing the same issue. As per RTCDataChannel documentation, you should handle a callback on Peer Connection object to receive the data on data channel. Below code might be helpful :

Step 1 : Define Callback Handlers :

  var handleDataChannelOpen = function (event) {
    console.log("dataChannel.OnOpen", event);
    dataChannel.send("Hello World!");
  };

  var handleDataChannelMessageReceived = function (event) {
    console.log("dataChannel.OnMessage:", event);
  };

  var handleDataChannelError = function (error) {
    console.log("dataChannel.OnError:", error);
  };

  var handleDataChannelClose = function (event) {
    console.log("dataChannel.OnClose", event);
  };

  var handleChannelCallback = function (event) {
     dataChannel = event.channel;
     dataChannel.onopen = handleDataChannelOpen;
     dataChannel.onmessage = handleDataChannelMessageReceived;
     dataChannel.onerror = handleDataChannelError;
     dataChannel.onclose = handleDataChannelClose;
  };

Step 2 : Create RTC Peer Connection :

  var pc = new RTCPeerConnection();
  pc.ondatachannel = handleChannelCallback;

Step 3 : Create Data Channel :

  var dataChannel = pc.createDataChannel('dataChannelName', {});

  dataChannel.onopen = handleDataChannelOpen;
  dataChannel.onmessage = handleDataChannelMessageReceived;
  dataChannel.onerror = handleDataChannelError;
  dataChannel.onclose = handleDataChannelClose;

In your code you just need to add ondatachannel callback handler to receive the data.

Nikhil Maheshwari
  • 2,198
  • 18
  • 25
1

I think the biggest misconception, at least for me, is that each client needs to keep a reference to TWO channels (please correct me if wrong, because it doesn't feel right at all). One for sending, one for receiving. This is basically what @Nikhil's answer is showing. He creates named functions for the handlers, in order to use them twice.

Also note that you can define the data connection right after peerConnection instantiation. I've read conflicting things saying you have to do it from only the caller, or only after the connection is ready. Maybe that was true of older versions of WebRTC but this works in current chrome (whatever is out as of oct 2017).

let pc = new RTCPeerConnection({"iceServers": [{"url": "stun:stun.l.google.com:19302"}]});

const handleDataChannelOpen = (event) =>{
    console.log("dataChannel.OnOpen", event);
    sendChannel.send("Hello World!");
};

const handleDataChannelMessageReceived = (event) =>{
    console.log("dataChannel.OnMessage:", event);
};

const handleDataChannelError = (error) =>{
    console.log("dataChannel.OnError:", error);
};

const handleDataChannelClose = (event) =>{
    console.log("dataChannel.OnClose", event);
};


let sendChannel = pc.createDataChannel('text', {});
sendChannel.onopen = handleDataChannelOpen;
sendChannel.onmessage = handleDataChannelMessageReceived;
sendChannel.onerror = handleDataChannelError;
sendChannel.onclose = handleDataChannelClose;


pc.ondatachannel = (event) =>{
    console.log("on data channel")
    let receiveChannel = event.channel;
    receiveChannel.onopen = handleDataChannelOpen;
    receiveChannel.onmessage = handleDataChannelMessageReceived;
    receiveChannel.onerror = handleDataChannelError;
    receiveChannel.onclose = handleDataChannelClose;

    let button = document.getElementById(this.id + "-submit");
    button.onclick = () =>{
        receiveChannel.send("hello from " + this.id)
    };
};

//... do your connection with servers
1mike12
  • 2,946
  • 3
  • 27
  • 36
0

This is working Client Side Code, I am sharing here, may be it helped somebody. Please do appreciate if it helped you:

            var connection = new WebSocket('wss://127.0.0.1:3000'); 
            var name = "";

            var loginInput = document.querySelector('#loginInput'); 
            var loginBtn = document.querySelector('#loginBtn'); 

            var otherUsernameInput = document.querySelector('#otherUsernameInput'); 
            var connectToOtherUsernameBtn = document.querySelector('#connectToOtherUsernameBtn'); 
            var msgInput = document.querySelector('#msgInput'); 
            var sendMsgBtn = document.querySelector('#sendMsgBtn'); 
            var connectedUser, myConnection, dataChannel;

            //when a user clicks the login button 
            loginBtn.addEventListener("click", function(event) { 
               name = loginInput.value; 

               if(name.length > 0) { 
                  send({ 
                     type: "login", 
                     name: name 
                  }); 
               } 
            });

            //handle messages from the server 
            connection.onmessage = function (message) {
            //    if(message)
                var data = JSON.parse(message.data);
                console.log("Got message", data.type);
               switch(data.type) { 
                  case "login": 
                     onLogin(data.success); 
                     break; 
                  case "offer": 
                     onOffer(data.offer, data.name); 
                     break; 
                  case "answer":
                     onAnswer(data.answer); 
                     break; 
                  case "candidate": 
                     onCandidate(data.candidate); 
                     break; 
                  default: 
                     break; 
               } 
            }; 

            //when a user logs in 
            function onLogin(success) { 

               if (success === false) { 
                  alert("oops...try a different username"); 
               } else { 
                  //creating our RTCPeerConnection object 
                  var configuration = { 
                     "iceServers": [{ "url": "stun:stun.1.google.com:19302" }] 
                  }; 

                  myConnection = new RTCPeerConnection(configuration); 

                  console.log("RTCPeerConnection object was created"); 
                  console.log(myConnection); 

                  //setup ice handling 
                  //when the browser finds an ice candidate we send it to another peer 
                  myConnection.onicecandidate = function (event) { 

                     if (event.candidate) { 
                        send({ 
                           type: "candidate", 
                           candidate: event.candidate 
                        });
                     } 
                  }; 
                  myConnection.ondatachannel = function (event) {
                      var receiveChannel = event.channel;
                      receiveChannel.onmessage = function (event) {
                          console.log("ondatachannel message:", event.data);
                      };
                  }; 

                  openDataChannel();
                  console.log("DataChannel Opened..");

               } 
            };

            connection.onopen = function () { 
               console.log("Connected"); 
            }; 

            connection.onerror = function (err) { 
               console.log("Got error", err); 
            };

            // Alias for sending messages in JSON format 
            function send(message) { 
               if (connectedUser) { 
                  message.name = connectedUser; 
               }

               connection.send(JSON.stringify(message)); 
            };

            //setup a peer connection with another user 
            connectToOtherUsernameBtn.addEventListener("click", function () {

               var otherUsername = otherUsernameInput.value;
               connectedUser = otherUsername;

               if (otherUsername.length > 0) { 
                  //make an offer 
                  myConnection.createOffer(function (offer) { 
                     console.log(offer); 

                     send({ 
                        type: "offer", 
                        offer: offer 
                     }); 

                     myConnection.setLocalDescription(offer); 
                  }, function (error) { 
                     alert("An error has occurred."); 
                  }); 
               } 
            });

            //when somebody wants to call us 
            function onOffer(offer, name) { 
               connectedUser = name; 
               myConnection.setRemoteDescription(new RTCSessionDescription(offer));

               myConnection.createAnswer(function (answer) { 
                  myConnection.setLocalDescription(answer); 

                  send({ 
                     type: "answer", 
                     answer: answer 
                  }); 

               }, function (error) { 
                  alert("oops...error"); 
               }); 
            }

            //when another user answers to our offer 
            function onAnswer(answer) { 
               myConnection.setRemoteDescription(new RTCSessionDescription(answer)); 
            }

            //when we got ice candidate from another user 
            function onCandidate(candidate) { 
               myConnection.addIceCandidate(new RTCIceCandidate(candidate)); 
            }


            //creating data channel 
            function openDataChannel() { 

               var dataChannelOptions = { 
                  reliable:true 
                };

               dataChannel = myConnection.createDataChannel("myDataChannel", dataChannelOptions);

               dataChannel.onerror = function (error) { 
                  console.log("Error:", error); 
               };

               dataChannel.onmessage = function (event) { 
                  console.log("Got message:", event.data); 
               };  
            }

            //when a user clicks the send message button 
            sendMsgBtn.addEventListener("click", function (event) { 
               console.log("send message");
               var val = msgInput.value; 
               dataChannel.send(val); 
            });
prakash
  • 57
  • 2
  • 11
Sohail Malik
  • 305
  • 1
  • 2
  • 12