-1

It's time for me to experiment WebRTC.

I think I understand the principle of operation, but the remote video is black, where is my mistake ?

When i add some console.log() everything is fine, this make me crazy !

I'm using socket.io for signaling :

io.sockets.on('connection', function(socket) {
    socket.on('rtcOffer', function(offer) {
        socket.broadcast.emit('rtcOffer', offer);
    });

    socket.on('rtcOfferAnswer', function(offer) {
        socket.broadcast.emit('rtcOfferAnswer', offer);
    });

    socket.on('rtcCandidate', function(candidate) {
        socket.broadcast.emit('rtcCandidate', candidate);
    });
});

HTML :

<video id="localVideo" width="400" autoplay="autoplay" style="border:#000 1px solid;"></video>
<video id="remoteVideo" width="400" autoplay="autoplay" style="border:#000 1px solid;"></video>
<button type="button" id="bCall">Call</button>

JS :

navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.getUserMedia;
window.RTCPeerConnection = window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.RTCPeerConnection;
window.createSignalingChannel = window.mozCreateSignalingChannel || window.webkitCreateSignalingChannel || window.createSignalingChannel;
window.RTCSessionDescription = window.webkitRTCSessionDescription || window.mozRTCSessionDescription || window.RTCSessionDescription;
window.RTCIceCandidate = window.webkitRTCIceCandidate || window.mozRTCIceCandidate || window.RTCIceCandidate;

var _peerConn = null;
var _mediaConstraints = {
    mandatory : {
        /*OfferToReceiveAudio : true,*/
        OfferToReceiveVideo : true
    }
};
var _rtcConfig = {
    iceServers : [{url : 'stun:stun.ekiga.net'},
    {url : 'stun:stun.ideasip.com'},
    {url : 'stun:stun.rixtelecom.se'},
    {url : 'stun:stun.schlund.de'},
    {url : 'stun:stun.l.google.com:19302'},
    {url : 'stun:stun1.l.google.com:19302'},
    {url : 'stun:stun2.l.google.com:19302'},
    {url : 'stun:stun3.l.google.com:19302'},
    {url : 'stun:stun4.l.google.com:19302'},
    {url : 'stun:stun.voiparound.com'},
    {url : 'stun:stun.voipbuster.com'},
    {url : 'stun:stun.voipstunt.com'},
    {url : 'stun:stun.voxgratia.org'},
    {url : 'stun:stun.xten.com'},
    {
        url : 'turn:numb.viagenie.ca',
        credential : 'muazkh',
        username : 'webrtc@live.com'
    }]
};

function call(localStream) {
    _peerConn = new RTCPeerConnection(_rtcConfig, {
       optional : [{
           DtlsSrtpKeyAgreement : true
        }]
    });

    _peerConn.onicecandidate = function(e) {
        if(e.candidate) {
            _peerConn.onicecandidate = null;

            socketEmit('rtcCandidate', e.candidate);
        }
    };

    _peerConn.onaddstream = function(e) {
        if(e) {
            $('#remoteVideo')[0].src = URL.createObjectURL(e.stream);
        }
    };

    _peerConn.addStream(localStream);

    _peerConn.createOffer(function(offer) {
        _peerConn.setLocalDescription(new RTCSessionDescription(offer));

        socketEmit('rtcOffer', offer);
    }, logError, _mediaConstraints);
}
function callEnd() {
    $('video').each(function() {
        this.pause();
    });

    _peerConn.close();
}
function callAccept(localStream, offer) {
    _peerConn = new RTCPeerConnection(_rtcConfig, {
       optional : [{
           DtlsSrtpKeyAgreement: true
        }]
    });

    _peerConn.addStream(localStream);

    _peerConn.onaddstream = function(e) {
        if(e) {
            $('#remoteVideo')[0].src = window.URL.createObjectURL(e.stream);
        }
    };

    _peerConn.onicecandidate = function(e) {
        if(e.candidate) {
            _peerConn.onicecandidate = null;

            socketEmit('rtcCandidate', e.candidate);
        }
    };

    _peerConn.setRemoteDescription(new RTCSessionDescription(offer), function() {
        _peerConn.createAnswer(function(answer) {
            _peerConn.setLocalDescription(new RTCSessionDescription(answer));

            socketEmit('rtcOfferAnswer', answer);
        }, logError, _mediaConstraints);
    }, logError);
}
function rtcCandidateIncoming(candidate) {
    if(_peerConn === null) {
        setTimeout(function() {
            rtcCandidateIncoming(candidate);
        }, 500);

        return;
    }

    _peerConn.addIceCandidate(new RTCIceCandidate({
        sdpMLineIndex : candidate.sdpMLineIndex,
        candidate : candidate.candidate
    }));
}
function userMediaAsk(callback) {
    navigator.getUserMedia({
        video : true/*,
        audio : true*/
    }, function(localStream) {
        $('#localVideo')[0].src = window.URL.createObjectURL(localStream);

        callback(localStream);
    }, logError);
}
function logError(e) {
    if(typeof e == typeof {}) {
        console.log('Error : '+JSON.stringify(e));
    }
    else {
        console.log('Error : '+e);
    }

    callEnd();
}

$(document).ready(function() {
    $('#bCall').click(function() {
        userMediaAsk(function(stream) {
            call(stream);
        });
    });

    socketRegisterSignal('rtcOffer', function(offer) {
        userMediaAsk(function(stream) {
            callAccept(stream, offer);
        });
    });

    socketRegisterSignal('rtcOfferAnswer', function(answer) {
        _peerConn.setRemoteDescription(new RTCSessionDescription(answer));
    });

    socketRegisterSignal('rtcCandidate', function(candidate) {
        rtcCandidateIncoming(candidate);
    });
});

window.onbeforeunload = function() {
    if(_peerConn) {
        _peerConn.close();
    }
};

Many thanks !!

WDX
  • 57
  • 7

1 Answers1

1

I can't tell exactly what is causing the problem in your code, but my experience has been that this is caused because of a missed ice candidate exchange.

Ice candidates are generated when you do a setLocalDecription and with the way the PeerConnection will trickle the icecandidates via the onicecandidate method, sometimes the remote peer isn't ready to receive the candidates. I see the timer you've set, but I'd confirm you are sending/receiving them correctly. You can check the ice state in chrome with chrome://webrtc-internals url.

  • Thank you for your answer, the problem was _peerConn.onicecandidate = null; when receiving candidates, now it's all good ! – WDX May 22 '15 at 15:19