Billy Rosing
Billy Rosing

Reputation: 43

Setting up the receiver in a webRTC call

I'm using webRTC to open a data channel between 2 users, the simplified version of the website is: 1 button to create the call with onclick="myLive.initiateConnection()"
1 input with id="caller" for the SDP description to be copy pasted from the first user tab to the second's user
1 button to answer the call with onclick="myLive.join()"
1 input with id="callee" for the SDP description to be copy pasted from the second user to the first one
1 button with onclick="setCallee($('#callee').val())" to set the remote description to the first user

I'm putting the join method before the initiateConnection method because as stated below, I think the error is in the gotCallerInfo called by join:

join = function(){
connection = new peerConnection(servers);
    connection.onicecandidate = function(evt){
        if(evt.candidate){
            connection.addIceCandidate(new RTCIceCandidate(event.candidate));
        }
    };

    connection.ondatachannel = function(ev){
        dataChannel = ev.channel;
        dataChannel.onmessage = receiveMessage;
            ev.channel.onopen = function(){
                alert('connection established, callee');
            };
        };
        gotCallerInfo($("#caller").val())
    };

gotCallerInfo = function(data){
    var newDesc = JSON.parse(data);
    connection.setRemoteDescription(new RTCSessionDescription(newDesc), function(){
        connection.createAnswer(function(desc){          
            connection.setLocalDescription(desc);

This code doesn't connect the 2 users via webRTC. By tweaking the code around here and testing with chrome, I noticed that I could have my webRTC call working by clicking the join button twice... or by calling createAnswer a second time after waiting for 1s (), the webRTC call works with chrome. But with firefox, it triggers the error "createAnswer can't be called in state stable". Why do calling createAnswer a second time after a timeout artificially solves the problem with chrome (and unfortunately not with firefox)? I guess I'm doing something in the wrong order, but setRemoteDescription, createAnswer and setLocalDescription are in the right order. Desc2 created by the second createAnswer is longer than desc created by the first one, so I suspect setLocalDescription triggers the collect of some ICE candidates that are needed to be sent to the caller, in which case how can I get desc being a full description on the first call of createAnswer?

            //setTimeout(function(){
                //connection.createAnswer(function(desc){           
                    $("#callee").val(JSON.stringify(desc));
                //}, errorCallback);
            //}, 1000);
        }, errorCallback);
    }, errorCallback);
};

I'm putting the code used by the caller in case the source of the error starts way before the error itself. The caller runs the initiateConnection method by clicking the create button. Then the callee copy pastes the description from the caller tab and click join, then the caller copy pastes the description from the callee and click set callee description

initiateConnection = function(){
    connection = new peerConnection(servers);
    connection.onicecandidate = function(evt){
        if(evt.candidate){
        connection.addIceCandidate(new RTCIceCandidate(event.candidate));
        }
    };

    dataChannel = connection.createDataChannel("channel");
    dataChannel.onopen = function(){
        alert('connection established, caller');
    };
    dataChannel.onmessage = receiveMessage;
    connection.createOffer(function(description){
        connection.setLocalDescription(description);
        $("#caller").val(JSON.stringify(description));
    }, errorCallback);
};

setCallee = function(data){
    connection.setRemoteDescription(new RTCSessionDescription(JSON.parse(data)));
};

receiveMessage = function(){};

errorCallback = function(){};  

Upvotes: 4

Views: 747

Answers (1)

jib
jib

Reputation: 42430

A couple of problems:

connection.onicecandidate = function(evt){
    if(evt.candidate){
    connection.addIceCandidate(new RTCIceCandidate(event.candidate));

Here you're adding a candidate back on the same peerConnection, short circuiting it. Don't do that.

Of course, using cut'n'paste instead of signaling you don't need to trickle candidates. Instead, ignore candidates and simply wait for the null candidate before copying the offer or answer. Candidates get automatically added to the local offer/answer over time. null signals the end of that process, which can take anywhere from <1 second to ~20 seconds in some cases (sometimes seen with VPNs, VMs, multiple network cards etc.).

Incidentally, this may be why waiting a second made it work for you.

For a working cut'n'paste example, see WebRTC, ice candidates connection

Upvotes: 1

Related Questions