How to exchange streams from two peerconnections with a proposal / answer

I am trying to set up video chat where two peer-to-peer connections exchange video. This happens after creating the data channel. So this is an event process:

  • offerer creates a data channel, offers , the responder creates a response. So far, so good. We have a datachannel.
  • offerer receives a video stream through getUserMedia and adds it to a peer-to-peer connection, then the onnegotiation offerer event, offerer creates a new offer, and the responder responds with a response. Still good. The annex .
  • answerer receives the video stream through getUserMedia and adds it to the peer-to-peer connection, offerer creates a new offer, and the responder responds with the answer, Still good. > also works.

However, if I switch steps 2 and 3 (so that the responder starts the flow again), then everything starts to go wrong. Both parties should start the flow only after all steps 1, 3 and 2 have taken place.

I am sure this has something to do with the order of the SDP suggestions and answers.

When I let the defendant create a new sentence, when it has an onnegotiationneeded event, the behavior is different, but still unstable.

Now I absolutely do not know how to add suggestions and answers.

Here is the code:

navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; PeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection || window.RTCPeerConnection; IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate || window.RTCIceCandidate; SessionDescription = window.mozRTCSessionDescription || window.webkitRTCSessionDescription || window.RTCSessionDescription; var videoOfferer = document.getElementById('videoOfferer'); var videoAnswerer = document.getElementById('videoAnswerer'); var buttonOfferer = document.getElementById('buttonOfferer'); var buttonAnswerer = document.getElementById('buttonAnswerer'); var servers = { iceServers: [ {url: "stun:23.21.150.121"}, {url: "stun:stun.1.google.com:19302"} ] }; var offerer = new PeerConnection(servers), answerer = new PeerConnection(servers); var channelOfferer = null, channelAnswerer = null; offerer.onicecandidate = function(e) { if(e.candidate == null) return; answerer.addIceCandidate(new IceCandidate(e.candidate), function(){}, error); }; offerer.onaddstream = function(e) { videoOfferer.src = URL.createObjectURL(e.stream); videoOfferer.play(); }; answerer.onicecandidate = function(e) { if(e.candidate == null) return; offerer.addIceCandidate(new IceCandidate(e.candidate), function(){}, error); }; answerer.onaddstream = function(e) { videoAnswerer.src = URL.createObjectURL(e.stream); videoAnswerer.play(); }; function offerCreated(sdp) { console.log('offer'); offerer.setLocalDescription(new SessionDescription(sdp), function() { answerer.setRemoteDescription(new SessionDescription(sdp), function() { answerer.createAnswer(answerCreated, error); }, error); }, error); } function answerCreated(sdp) { console.log('answer'); answerer.setLocalDescription(new SessionDescription(sdp), function() { }, error); offerer.setRemoteDescription(new SessionDescription(sdp), function() { }, error); } function error() {} buttonOfferer.addEventListener('click', function() { navigator.getUserMedia({audio: true, video: true}, function(stream) { offerer.addStream(stream); }, function(){}); }); buttonAnswerer.addEventListener('click', function() { navigator.getUserMedia({audio: true, video: true}, function(stream) { answerer.addStream(stream); }, function(){}); }); channelOfferer = offerer.createDataChannel('channel', {reliable: true}); offerer.createOffer(offerCreated, error); answerer.ondatachannel = function(e) { channelOfferer = e.channel; channelOfferer.onmessage = function(e) { console.log(e.data); }; channelOfferer.onmessage = function(e) { console.log(e.data); }; // these are added later offerer.onnegotiationneeded = function() { offerer.createOffer(offerCreated, error); }; answerer.onnegotiationneeded = function() { offerer.createOffer(offerCreated, error); }; }; 
+2
source share
1 answer

I think the problem is in step 3, where you have a proposal initiator when the user uploads the video. In a real remote call, how would the provider know about this?

As I understand it, when the defendant needs to be re-discussed, the roles actually change, because for the purposes of review: the auditor acts as the provider, while the non-resident intermediary acts as the defendant.

In other words: the answer to pc.onnegotiationneeded always:

  • createOffer() ,
  • then setLocalDescription(description)
  • then send pc.localDescription to the other side

regardless of the party.

I am not an authority on SDP, so I don’t know for sure that this is the right approach, but the examples in spec at least suppose that the above steps are correct and I started working this way.

I tested this in this Firefox jsfiddle and it seems to work. Instructions for using the script:

  • There is no server (since this is a fiddle), so click the Offer button and copy the offer.
  • Paste the sentence in the same place in the same violin on another tab or on another machine.
  • Press ENTER, then copy the resulting answer and paste it into the first script.
  • You are now connected to two data channels: one for chat and one for signaling.
  • Now click addTrack on either end, and the video should appear on the other end.
  • Click addTrack in the other direction and you should have the video in both directions.

Could this cause glare? I'm sure there may be better ways to handle this, but this seems to work for me.

+2
source

All Articles