SuperYegorius
SuperYegorius

Reputation: 794

WebRTC - how to switch between getUserMedia and getDisplayMedia tracks inside RTCPeerConnection

I'm trying to develop an app where users can can video call to each other and share their screens using WebRTC technology. I have succeed with either video call or screen sharing app and now I'm trying to make it to be able to switch between getUserMedia and getDisplayMedia on button click during a call inside the same RTCPeerConnection but it doesn't work.

This is how I thought it could work:

            function onLogin(success) { 

                var configuration = { offerToReceiveAudio: true, offerToReceiveVideo: true, "iceServers" : [ { "url" : "stun:stun.1.google.com:19302" } ] }; 

                myConnection = window.RTCPeerConnection ? new RTCPeerConnection(configuration, { optional: [] }) : new RTCPeerConnection(configuration, { optional: [] }); 

                myConnection.onicecandidate = function (event) { 
                    console.log("onicecandidate");
                    if (event.candidate) send({ type: "candidate", candidate: event.candidate });
                };
                
                myConnection.ontrack=function(e){
                    try{remoteVideo.src = window.webkitURL?window.webkitURL.createObjectURL(e.streams[0]):window.URL.createObjectURL(e.streams[0])}
                    catch(err){remoteVideo.srcObject=e.streams[0]}
                }
                
                myConnection.ondatachannel=openDataChannel
                openDataChannel();
                
                startAVStream();
                //startSStream()
            };

            function startAVStream(enable){
                if(sStream)sStream.getTracks().forEach( function (track) {
                            try{myConnection.removeTrack( track, sStream );}
                            catch(e){}
                        } );
                        
                navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(s => {
                    if(!avStream){
                        avStream = s;
                        avStream.getTracks().forEach( function (track) {
                            myConnection.addTrack( track, avStream );
                        } );
                    }
                }, function (error) { console.log(error); }); 
            }
            
            function startSStream(enable){
                if(avStream)avStream.getTracks().forEach( function (track) {
                            try{myConnection.removeTrack( track, avStream );}
                            catch(e){}
                        } );
                        
                navigator.mediaDevices.getDisplayMedia({ video: true }).then(s => {
                    if(!sStream){
                        sStream = s;
                        sStream.getTracks().forEach( function (track) {
                            myConnection.addTrack( track, sStream );
                        } );
                    }
                }, function (error) { console.log(error); }); 
            }

Can anyone tell me how I can switch between tracks inside the same RTCPeerConnection or should I create 2 separate RTCPeerConnection - one for video/audio streaming and another for screen sharing?

Any help appreciated! Thanks!

Upvotes: 0

Views: 1460

Answers (2)

Tolga EGE
Tolga EGE

Reputation: 9

 shareScreen = () =>{
const success = (stream) => {
  window.localStream = stream
  // this.localVideoref.current.srcObject = stream
  // localStream.replaceStream(stream);
  this.setState({
    localStream: stream
  })

  Object.values(this.state.peerConnections).forEach(pc => {
    pc.getSenders().forEach(async s => {
      console.log("s.track ",s.track);
      if(s.track && s.track.kind === 'video'){
        stream.getTracks().forEach(track => {
          // pc.addTrack(track, this.state.localStream)
          s.replaceTrack(track);   
        });
      }
    });
  });
}
const failure = (e) => {
  console.log('getUserMedia Error: ', e)
}
navigator.mediaDevices.getDisplayMedia({ cursor: true }).then(success).catch(failure)}

Upvotes: 0

jch
jch

Reputation: 5651

You could use RTCRtpSender.replaceTrack to splice the screen capture track. This doesn't require renegotiation, and therefore has very low latency.

let newstream = navigator.mediaDevices.getDisplayMedia({});
let newtrack = newstream.getTracks()[1];
if(newtrack.kind !== 'video')
    throw new Error('Eek!?');
pc.getSenders().forEach(async s => {
    if(s.track && s.track.kind === 'video')
        await s.replaceTrack(newtrack);
});

The test for s.track not being null deals with the case where you previously called replaceTrack(..., null).

Upvotes: 2

Related Questions