Search code examples
javascriptcamerawebrtc

WebRTC switch camera


I am currently working for WebRTC multipeer connection. I want to implement feature to switch camera from front to back while on call. This is the code I am using to switch cameras

async function changevideo() {
   
   const audioSource = audioInputSelect.value;
   const videoSource = videoSelect.options[videoSelect.selectedIndex].value;
   var tempconstraints ={
       video: {
           deviceId: videoSource ? { exact: videoSource } : undefined,
           width: { max: 320 },
           height: { max: 240 }
       },
       audio: { deviceId: audioSource ? { exact: audioSource } : undefined },
   };
   var newstream = await navigator.mediaDevices.getUserMedia(tempconstraints);
  
   if (connections[socketId]) {
       Promise.all(connections[socketId].getSenders().map(function (sender) {
           debugger;
           return sender.replaceTrack(newstream.getTracks().find(function (track) {
               debugger;
               return track.kind === sender.track.kind;
           })).then(data =>
           {
               console.log(data);
           });;
       }));

       var track = localStream.getTracks().find(function (track) { return track.kind == videoTrack.kind });
       localStream.removeTrack(track);
       localStream.addTrack(videoTrack);

       connections[tempsocketid].onnegotiationneeded = function () {
           connections[tempsocketid].createOffer().then(function (offer) {
               return connections[tempsocketid].setLocalDescription(offer);
           }).then(function () {
               socket.emit('signal', socketId, JSON.stringify({ 'sdp': connections[tempsocketid].localDescription, 'room': roomNumber }), roomNumber);
           }).catch(e => console.log(e));
       }
   }
}

Here connections contains the RTCpeerconnection details of all type of connections connected.

socketId is the id of main user on which I want to switch camera. So, connections[socketId] gives me the RTCPeerConnection details of user with socketId.

newstream is the stream after switching camera.

If I directly update src of video to newstream then my camera changes only on my device.

I have searched alot but everywhere I am getting solution to use replaceTrack but it is not wokring in my case. Everytime I use it nothing happens on screen and I am also not getting any error in console.

Update

I have used the onnegotiationneeded with remove and add track.

tempsocketid is the socketId of another user who is connected. So I have 2 users one have socketid stored in socketId and another having socketid stored in tempsocketid. So currently I am trying to switch camera of user with socketid socketId and when negotiation is called then I am getting error in another users console.

DOMException: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate


Solution

  • I have fixed the issue the problem was with socketId I was sending socketId of current user with different user.

    As replace track was not working so I have used removeTrack and addTrack to force negotiation.

    Here is my working code

    if (connections[socketId]) {
        localStream.getVideoTracks()[0].enabled = false;
        var track = localStream.getTracks().find(function (track) { return track.kind == videoTrack.kind });
        localStream.removeTrack(track);
        localStream.addTrack(videoTrack);
    
        connections[tempsocketid].onnegotiationneeded = function () {
            console.log('negotiationstarted');
            connections[tempsocketid].createOffer().then(function (offer) {
                return connections[tempsocketid].setLocalDescription(offer);
            }).then(function () {
                console.log('negotiation signal sent');
                socket.emit('signal', tempsocketid, JSON.stringify({ 'sdp': connections[tempsocketid].localDescription, 'room': roomNumber }), roomNumber);
            }).catch(e => console.log(e));
        }
        localStream.getVideoTracks()[0].enabled = true;
    }