Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebRTC with 3 users connection

I'm now implementing the source code from WebRTC Samples to become 3 users connection by using mesh topology.

However, my code doesn't work as I thought it would be. I think I'm stuck at calling function iceCallBack# (# refers to number 1, 2 ,3) because the output result is the same as the original. It only can connect 2 users.

I don't know how to fix it in proper way.

Here is some of my JavaScript code that I have been working on:

    var audio2 = document.querySelector('audio#audio2');
    var audio3 = document.querySelector('audio#audio3');
    var pc1;
    var pc2;
    var pc3;

    function call() {
      callButton.disabled = true;
      codecSelector.disabled = true;
      trace('Starting call');
      var servers = null;
      var pcConstraints = {
        'optional': []
      };
      pc1 = new RTCPeerConnection(servers, pcConstraints);
      trace('Created local peer connection object pc1');
      pc1.onicecandidate = iceCallback1;

      pc2 = new RTCPeerConnection(servers, pcConstraints);
      trace('Created remote peer connection object pc2');
      pc2.onicecandidate = iceCallback2;
      pc2.onaddstream = gotRemoteStream;
      trace('Requesting local stream');

      pc3 = new RTCPeerConnection(servers, pcConstraints);
      trace('Created remote peer connection object pc2');
      pc3.onicecandidate = iceCallback3; 
      pc3.onaddstream = gotRemoteStream2;
      trace('Requesting local stream');

      navigator.mediaDevices.getUserMedia({
        audio: true,
        video: false
      })
      .then(gotStream)
      .catch(function(e) {
        alert('getUserMedia() error: ' + e.name);
      });
    }


    //Description of pc1 creating offer to pc2
    function gotDescription1(desc) {
      desc.sdp = forceChosenAudioCodec(desc.sdp);
      trace('Offer from pc1 \n' + desc.sdp);
      pc1.setLocalDescription(desc, function() {
        pc2.setRemoteDescription(desc, function() {
          pc2.createAnswer(gotDescription2, onCreateSessionDescriptionError);
        }, onSetSessionDescriptionError);
      }, onSetSessionDescriptionError);
    }

    //Description of pc1 creating offer to pc3
    function gotDescription3(desc) {
      desc.sdp = forceChosenAudioCodec(desc.sdp);
      trace('Offer from pc1 \n' + desc.sdp);
      pc1.setLocalDescription(desc, function() {
        pc3.setRemoteDescription(desc, function() {
          pc3.createAnswer(gotDescription4, onCreateSessionDescriptionError); //Must edit gotDescription4
        }, onSetSessionDescriptionError);
      }, onSetSessionDescriptionError);
    }

    //Creating answer from pc2
    function gotDescription2(desc) {
      desc.sdp = forceChosenAudioCodec(desc.sdp);
      pc2.setLocalDescription(desc, function() {
        trace('Answer from pc2 \n' + desc.sdp);
        pc1.setRemoteDescription(desc, function() {
        }, onSetSessionDescriptionError);
      }, onSetSessionDescriptionError);
    }

    //Creating answer from pc3
    function gotDescription4(desc) {
      desc.sdp = forceChosenAudioCodec(desc.sdp);
      pc3.setLocalDescription(desc, function() {
        trace('Answer from pc2 \n' + desc.sdp);
        pc1.setRemoteDescription(desc, function() {
        }, onSetSessionDescriptionError);
      }, onSetSessionDescriptionError);
    }

    function iceCallback1(event) {
      if (event.candidate) {
        pc2.addIceCandidate(new RTCIceCandidate(event.candidate),
            onAddIceCandidateSuccess, onAddIceCandidateError);
        pc3.addIceCandidate(new RTCIceCandidate(event.candidate),
            onAddIceCandidateSuccess, onAddIceCandidateError);
        trace('Local ICE candidate: \n' + event.candidate.candidate);
      }
    }

    function iceCallback2(event) {
      if (event.candidate) {
        pc1.addIceCandidate(new RTCIceCandidate(event.candidate),
            onAddIceCandidateSuccess, onAddIceCandidateError);
        pc3.addIceCandidate(new RTCIceCandidate(event.candidate),
            onAddIceCandidateSuccess, onAddIceCandidateError);
        trace('Remote ICE candidate: \n ' + event.candidate.candidate);
      }
    }

    function iceCallback3(event) {
      if (event.candidate) {
        pc1.addIceCandidate(new RTCIceCandidate(event.candidate),
            onAddIceCandidateSuccess, onAddIceCandidateError);
        pc2.addIceCandidate(new RTCIceCandidate(event.candidate),
            onAddIceCandidateSuccess, onAddIceCandidateError);
        trace('Remote ICE candidate: \n ' + event.candidate.candidate);
      }
    }
<div id="audio">
      <div>
        <div class="label">Local audio:</div><audio id="audio1" autoplay controls muted></audio>
      </div>
      <div>
        <div class="label">Remote audio2:</div><audio id="audio2" autoplay controls></audio>
      </div>
      <div>
        <div class="label">Remote audio3:</div><audio id="audio3" autoplay controls></audio>
      </div>
</div>

Note: I'm new with webRTC. I might be dumb in some way, please forgive me.

Thank you so much.

like image 922
benji Avatar asked Apr 27 '16 09:04

benji


1 Answers

A mesh of 3 users means each user sets up two connections, one to each of the other two users. At each client's end, these are two entirely different RTCPeerConnections, and you can't reuse candidates between them, as each candidate contains port numbers allocated specifically for the media and the target it is to be sent to.

If you know how to set up one connection, you know how to set up two. Just keep things separate.

like image 67
jib Avatar answered Oct 08 '22 16:10

jib