WebRTC 切换摄像头
WebRTC switch camera
我目前正在为 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 更新为新闻流,那么我的相机只会在我的设备上发生变化。
我已经搜索了很多,但到处都能找到使用 replaceTrack
的解决方案,但在我的情况下它并不奏效。每次我使用它时,屏幕上都没有任何反应,而且我在控制台中也没有收到任何错误。
更新
我已经使用了 onnegotiationneeded
删除和添加曲目。
tempsocketid
是另一个连接用户的socketId。
所以我有 2 个用户,一个将 socketid 存储在 socketId
中,另一个将 socketid 存储在 tempsocketid
中。所以目前我正在尝试使用 socketid socketId
切换用户的相机
当调用协商时,我在另一个用户控制台中收到错误消息。
DOMException: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate
您可能无法重新协商,因此更改相机的 facingMode
不会影响其他对等方,但您并没有像我看到的那样明确使用它,而是 replaceTracks
。但是您仍然可能无法触发重新协商。检查导致重新协商的事项:https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpSender/replaceTrack#Usage_notes
通过使用 applyConstraints
应用约束来更改 facingMode
设置可能是不使用 replaceTracks
的解决方案。
我想到了一个奇怪的想法,即自己发送 negotiationneeded
事件,但在追寻无法通过更换轨道、更换相机和其他一切来重新协商的原因后,我会尝试这个。
关于另一个原因:至于导致重新协商的原因,你的后置摄像头分辨率应该比前置摄像头高,所以看起来是一个原因。如果你先从后置摄像头开始,然后再切换到前置摄像头,那可能是没有理由的。我怀疑你 max
对 width
和 height
的限制。根据上面链接页面中的列表,两个相机的它们可能非常低,因此导致相同的尺寸、分辨率等。我建议删除它们。
replaceTracks
return 也是一个承诺,但是调用它的地图函数没有 return 任何东西,因此 undefined
。您应该在 Promise.all
的数组参数中使用 promise。我建议 return
map
函数中的那些 promises。
我已经解决了 socketId 的问题,我将当前用户的 socketId 发送给不同的用户。
由于替换轨道不起作用,所以我使用 removeTrack
和 addTrack
强制协商。
这是我的工作代码
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;
}
我目前正在为 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 更新为新闻流,那么我的相机只会在我的设备上发生变化。
我已经搜索了很多,但到处都能找到使用 replaceTrack
的解决方案,但在我的情况下它并不奏效。每次我使用它时,屏幕上都没有任何反应,而且我在控制台中也没有收到任何错误。
更新
我已经使用了 onnegotiationneeded
删除和添加曲目。
tempsocketid
是另一个连接用户的socketId。
所以我有 2 个用户,一个将 socketid 存储在 socketId
中,另一个将 socketid 存储在 tempsocketid
中。所以目前我正在尝试使用 socketid socketId
切换用户的相机
当调用协商时,我在另一个用户控制台中收到错误消息。
DOMException: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate
您可能无法重新协商,因此更改相机的 facingMode
不会影响其他对等方,但您并没有像我看到的那样明确使用它,而是 replaceTracks
。但是您仍然可能无法触发重新协商。检查导致重新协商的事项:https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpSender/replaceTrack#Usage_notes
通过使用 applyConstraints
应用约束来更改 facingMode
设置可能是不使用 replaceTracks
的解决方案。
我想到了一个奇怪的想法,即自己发送 negotiationneeded
事件,但在追寻无法通过更换轨道、更换相机和其他一切来重新协商的原因后,我会尝试这个。
关于另一个原因:至于导致重新协商的原因,你的后置摄像头分辨率应该比前置摄像头高,所以看起来是一个原因。如果你先从后置摄像头开始,然后再切换到前置摄像头,那可能是没有理由的。我怀疑你 max
对 width
和 height
的限制。根据上面链接页面中的列表,两个相机的它们可能非常低,因此导致相同的尺寸、分辨率等。我建议删除它们。
replaceTracks
return 也是一个承诺,但是调用它的地图函数没有 return 任何东西,因此 undefined
。您应该在 Promise.all
的数组参数中使用 promise。我建议 return
map
函数中的那些 promises。
我已经解决了 socketId 的问题,我将当前用户的 socketId 发送给不同的用户。
由于替换轨道不起作用,所以我使用 removeTrack
和 addTrack
强制协商。
这是我的工作代码
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;
}