我希望能够在与WebRTC对话的过程中切换相机,而无需重新协商来电。
假设我们有2" mediaSources"使用MediaStreamTrack.getSources
方法的对象:
{
id: "id_source_1" | "id_source_2",
facing: "user" | "environment",
kind: "kind_1" | "kind_2",
label: "label_1" | "label_2"
}
我们用" source_1"开始通话(面对"用户"),我们希望用户能够切换到" source_2" (面对"环境")。
在我当前的代码中,当用户点击"切换相机"按钮执行以下操作:(callingSession
是当前的WebRTC会话)
var mediaParams = {
audio: true,
video: { deviceId : source_2.id},
options: {
muted: true,
mirror: true
},
elemId: 'localVideo'
};
callingSession.getUserMedia(mediaParams, function (error, stream) {
if (error) {
console.error('error getting user media');
} else {
var oldVideoTracks = callingSession.localStream.getVideoTracks();
var newVideoTracks = stream.getVideoTracks();
if (oldVideoTracks.length > 0 && newVideoTracks.length > 0) {
callingSession.localStream.removeTrack(oldVideoTracks[0]);
callingSession.localStream.addTrack(newVideoTracks[0]);
}
}
});
正如您所看到的mediaParams
约束现在设置为" source_2",我们将此mediaParams
带有新约束传递给getUserMedia
方法。然后我们从旧流和新流中获取视频曲目。
此代码中的主要问题是旧流仍然与新流完全相同,即使传递给getUserMedia
方法的新约束,显然也是相同的视频轨道,当然没有任何反应,相机没有切换!!!
我在这段代码中做错了什么?有没有办法在没有重新谈判 WebRTC中的呼叫的情况下切换相机?那个实验方法怎么样applyConstraint()
我无法在chrome中看到它?
谢谢。
更新 我的WebRTC应用程序是一个离线应用程序,其中有crosswalk => webview是chrome
答案 0 :(得分:5)
在撰写本文时,WebRTC specification非常有前景,但该规范的实现仍然因浏览器而异。目前Chrome的实施仍然很旧。不过感谢jib的评论和SO answer,以及对SDP (Session Description Protocol)的更多理解,我现在可以使用Chrome切换相机。
首先,对getUserMedia
方法的约束是错误的,这就是我设法传递正确约束的方法:
var mediaParams = {
// the other constraints
video: {mandatory: {sourceId: source_2.id}}
// ...
};
在使用getUserMedia
参数调用mediaParams
之后,我们需要从对等连接中删除当前流,然后像这样添加新的:
peerConnection.removeStream(peerConnection.getLocalStreams()[0]);
peerConnection.addLocalStream(stream);
这两行代码将触发onnegotiationneeded
对象上的peerConnection
,意味着对等方1必须告诉对等方2他更改了流,因此他需要一个新的描述。这就是我们需要创建商品,设置新描述并将此新描述发送给同行的原因:
peerConnection.createOffer()
.then(function (offer) {
peerConnection.setLocalDescription(offer);
})
.then(function () {
send(JSON.stringify({ "sdp": peerConnection.localDescription }));
});
此时,您可以根据自己的需要send
SDP。 (在我的用例中,我必须使用WebSockets发送它们。)
一旦另一个对等体收到新的SDP,他必须在自己的对等连接中设置它:
var obj = JSON.parse(answer).sdp;
peerConnection.setRemoteDescription(new RTCSessionDescription(obj));
我希望有一天能帮到某人。
答案 1 :(得分:1)
replaceTrack API就是为此而定义的。
最终chrome将支持RTCRtpSender.replaceTrack方法(http://w3c.github.io/webrtc-pc/#rtcrtpsender-interface),该方法可用于替换没有重新协商的轨道。您可以在此处跟踪Chrome中该功能的开发:https://www.chromestatus.com/feature/5347809238712320
它在本机API中已经在某种程度上可用。但它目前正在开发中,因此请自担风险。
答案 2 :(得分:0)
为了替换当前的相机,而又不丢失候选过程,您必须使用以下示例代码,显然替换您自己的变量:
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream){
localVideo.srcObject = stream;
stream.getVideoTracks().forEach(function(track) {
var sender = peerConnCallee.getSenders().find(function(s) {
return s.track.kind == track.kind;
});
sender.replaceTrack(track);
});
})
.catch(function(e) { });
您可以在下一个站点中看到它的运行情况: Can Peek
答案 3 :(得分:0)
我们可以替换Track时不需要重新协商
以下为我工作了多个peerConnection。
https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpSender/replaceTrack
'''
navigator.mediaDevices
.getUserMedia({
video: {
deviceId: {
exact: window.selectedCamera
}
}
})
.then(function(stream) {
let videoTrack = stream.getVideoTracks()[0];
PCs.forEach(function(pc) {
var sender = pc.getSenders().find(function(s) {
return s.track.kind == videoTrack.kind;
});
console.log('found sender:', sender);
sender.replaceTrack(videoTrack);
});
})
.catch(function(err) {
console.error('Error happens:', err);
});
'''
答案 4 :(得分:0)
我不知道为什么只有我有这个问题,但如果其他人因为您的相机忙(notReadableError:无法启动视频源)而无法调用 navigator.mediaDevices.getUserMedia(),请尝试在此之前添加调用 getUserMedia:
for(let p in pc){
let pName = pc[p];
pc[pName] && pc[pName].getSenders().forEach(s => s.track && s.track.stop());
}
myStream.getTracks().length ? myStream.getTracks().forEach(track => track.stop()) : '';
远程对等点和您的本地流可能很忙。