我正在创建一个web应用程序,用于智能手机使用WebRTC进行监控,并用于信号服务器使用socket.io.
当我发送流时,我会在接收该流的"监视"页面上创建一个RTCPeerConnection对象。我在不同的页面上发送流。用户最多可以从智能手机连接四个流,因此在"观看"页面上最多有四个RTCPeerConnection对象。
一旦"传输"页面的报价出现,就会自动接收流,然后在"监视"页面上创建RTCPeerConnection对象并连接到标准WebRTC架构。
"传输"页面:
function onCreateOfferSuccess(sdp){
//console.log(sdp);
pc.setLocalDescription(new RTCSessionDescription(sdp));
console.log('ask');
socket.emit('ask', {"sdp":JSON.stringify(pc.localDescription),
"user": loggedUserID,
"fromSocket": ownSocket});
}
"手表"页面:
socket.on('ask', function(offer){
if (offer.user === loggedUserID){
TempDescriptions = JSON.parse(offer.sdp);
console.log(TempDescriptions)
currTransmiterSocket = offer.fromSocket;
console.log(currTransmiterSocket);
getStream();
}
function getStream(){
try {
setTimeout(function(){
console.log(time, 'getStream()');
connection = getPeerConnection();
connection.setRemoteDescription(
new RTCSessionDescription(TempDescriptions),
function() {
connection.createAnswer(gotDescription, function(error){
console.log(error)
});
}, function(error){
console.log(error)
});
}, getStreamDelay*3000)
getStreamDelay++
}
catch(err){
console.log(err);
}
};
我的web应用程序需要这样的功能:当我们退出"观看"页面并再次返回时,必须显示以前包含的所有流。
为了实现此功能,我使用onicconnectionstatechange方法。如果流断开连接,则执行iceRestart函数,该函数使用选项{iceRestart:true}创建优惠
"传输"页面:
var options_with_restart = {offerToReceiveAudio: false,
offerToReceiveVideo: true,
iceRestart: true};
function iceRestart(event){
try{
setTimeout(function(){
pc.createOffer(options_with_restart).then(onCreateOfferSuccess, onCreateOfferError);
},1000);
} catch(error) {
console.log(error);
问题是,当我重新启动"观察"页面时,所有页面都会立即"发送"请求。虽然同时创建了四个RTCPeerConnection对象,但只连接了一个对象(假设用户发送了四个流)。
我已经和这个问题斗争了好几天了。我试图在对getStream()函数的后续调用中设置一个增加的时间延迟,如上面的代码所示,我试图在执行getStream()函数之前检查signallingState
连接,我尝试了其他几种方法,但都不起作用。
如果你需要我的代码的某些部分来帮助,请写下来。
编辑:
"watch"页面中的gotDescription()方法。
function gotDescription(sdp) {
try{
connection.setLocalDescription(sdp,
function() {
registerIceCandidate();
socket.emit('response', {"sdp": sdp,
"user": loggedUserID,
"fromSocket": ownSocket,
"toSocket": currTransmiterSocket});
}, function(error){
console.log(error)
});
} catch(err){
console.log(err);
}
}
我用RTCPeerConnection object
添加console.log
控制台输出:https://i.stack.imgur.com/dQXkE.png1
日志显示连接的signalingState
是"稳定的",但当我开发对象时,signalingState
等于"远程提供">
像这里
删除TempDescriptions
全局变量,并将sdp直接传递给getStream(offer.sdp)
。
否则,您已经调用了socket.on('ask', function(offer){
4次,覆盖了TempDescriptions
。3秒多后,您的4个setTimeout
s滚动,全部仅访问TempDescriptions
的最终值。
这可能就是为什么只有一个RTCPeerConnection重新连接的原因。
一般来说,使用时间延迟来分离连接似乎是个坏主意,因为它会减慢重新连接的速度。相反,为什么不发送id
呢?例如
socket.emit('ask', {id: connectionNumber++,
sdp: JSON.stringify(pc.localDescription),
user: loggedUserID,
fromSocket: ownSocket});
更新:停止向window
添加全局变量
每当你分配给这样一个未声明的变量时:
connection = getPeerConnection();
它在window
上创建了一个全局,例如window.connection
,您也有同样的问题。您有4个连接,但您将它们存储在一个变量中。
在源文件的开头键入"use strict";
以捕获以下内容:
ReferenceError: assignment to undeclared variable connection
范围界定:一般问题
您在这里处理的是4个连接,但缺少一种确定每个实例范围的方法。
大多数其他语言都会告诉您创建一个类并创建对象实例,并将包括connection
在内的所有内容都放在this
上。这是一个很好的方法。在JS中,您可以使用闭包。但至少您仍然需要4个变量来保持4个连接,或者connections
的数组。然后,您可以查找(例如,从我提到的id
)要处理的连接。
此外,您的try
/catch
不会捕获异步错误。我强烈建议在处理高度异步的WebRTC API时使用promise,甚至async/await,而不是定义所有这些回调。这使得范围界定变得微不足道。例如
const connections = [];
socket.on('ask', async ({user, id, sdp, fromSocket}) => {
try {
if (user != loggedUserID) return;
if (!connections[id]) {
connections[id] = getPeerConnection();
registerIceCandidate(connections[id]);
}
const connection = connections[id];
await connection.setRemoteDescription(JSON.parse(sdp));
await connection.setLocalDescription(await connection.createAnswer());
socket.emit('response', {sdp,
user: loggedUserID,
fromSocket: ownSocket,
toSocket: fromSocket});
} catch (err) {
console.log(err);
}
};
通过这种方式,错误处理是可靠的。