【问题标题】:WebRTC switch cameraWebRTC切换摄像头
【发布时间】:2020-11-14 08:02:16
【问题描述】:

我目前正在为 WebRTC 多点连接工作。我想实现在通话时从前到后切换摄像头的功能。 这是我用来切换相机的代码

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));
       }
   }
}

这里connections包含了所有连接类型的RTCpeerconnection详细信息。

socketId 是我要切换摄像头的主用户 ID。所以,connections[socketId] 给了我带有 socketId 的用户的 RTCPeerConnection 详细信息。

newstream是切换相机后的流。

如果我直接将视频的 src 更新到 newstream,那么我的相机只会在我的设备上发生变化。

我进行了很多搜索,但到处都可以找到使用 replaceTrack 的解决方案,但在我的情况下它并不适用。每次我使用它时,屏幕上都没有任何反应,控制台中也没有任何错误。

更新

我使用了onnegotiationneeded 与删除和添加轨道。

tempsocketid 是另一个已连接用户的 socketId。 所以我有 2 个用户,一个用户的 socketid 存储在 socketId 中,另一个用户的 socketid 存储在 tempsocketid 中。所以目前我正在尝试使用 socketid socketId 切换用户的相机 当调用协商时,我在另一个用户控制台中遇到错误。

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

【问题讨论】:

    标签: javascript camera webrtc


    【解决方案1】:

    您可能无法引起重新协商,因此更改相机的facingMode 不会影响其他对等方,但您并没有像我看到的那样明确使用它,而是replaceTracks。但是您仍然可能无法触发重新谈判。查看导致重新协商的内容:https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpSender/replaceTrack#Usage_notes

    通过使用applyConstraints 应用约束来更改facingMode 设置可能是不使用replaceTracks 的解决方案。

    一个奇怪的想法出现在我的脑海中,自己发送negotiationneeded 事件,但我会在寻找无法通过更换轨道或更换相机以及其他一切来重新协商的原因之后尝试这个。

    关于另一个原因:至于导致重新协商的原因,您的后置摄像头分辨率很可能高于前置摄像头,所以看起来是一个原因。如果您先从后置摄像头开始,然后再切换到前置摄像头,那可能是没有理由的。我怀疑你的max 约束widthheight。根据上面链接页面中的列表,它们可能会非常低,因此导致相同的尺寸、分辨率等原因。我建议删除它们。

    同样replaceTracks返回一个promise,但是调用它的map函数没有返回任何东西,因此undefined。您应该在Promise.all 的数组参数中使用承诺。我建议return map 函数中的那些 promises

    【讨论】:

    • 我什至尝试删除高度和宽度,甚至先用后置摄像头然后前置摄像头进行测试,但问题仍然存在
    • 从调用replaceTracks的映射函数返回一个pomise而不是undefined怎么样?
    • 我已经更新了代码。它在控制台中返回我未定义。我是新手,所以如果我以错误的方式使用它,请纠正。
    • 谢谢,但输出还是一样。
    • 我建议你确保在你的 newStream 中找到一个轨道形式。还要将 cosole.log 的十个放在 Promise.all 之后,我的意思是改为链接到它。
    【解决方案2】:

    我已经解决了socketId的问题,我正在用不同的用户发送当前用户的socketId。

    由于替换轨道不起作用,所以我使用了removeTrackaddTrack 来强制协商。

    这是我的工作代码

    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;
    }
    

    【讨论】:

      猜你喜欢
      • 2016-12-31
      • 2020-10-04
      • 2018-09-04
      • 1970-01-01
      • 1970-01-01
      • 2018-07-11
      • 2020-09-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多