仅适用于 one-to-one,其中 many-to-many,webrtc
Only works on one-to-one of which was to be many-to-many, webrtc
我正在开发用于视频通话 this 风格的会议风格应用程序 (many-to-many)。该代码在 GitHub 上可用,但我没有太多 node.js 经验,因此我决定使用 PHP.
创建自己的服务器
我使用 WebSockets 创建了服务器。这很简单——它接收消息并将它们转发给所有其他连接的客户端(即,不是发送消息的客户端)。仅此而已-仅此而已;仅此而已。
但我的问题是这种架构不允许客户端与一个以上的人连接,即,当客户端尝试与第三人连接时,额外的流会失败。客户端只能连接 one-to-one.
不知道是JavaScript的错误还是需要改进服务器。我该怎么做才能连接到所有加入的客户?
查看我的代码:
HTML
<script type="text/javascript" src="http://127.0.0.1/scr/js/jquery.js"></script>
JavaScript
var Server = new WebSocket('ws://127.0.0.1:1805/'),
myStream = null,
peerConn = null,
mediaConstraints = {
'mandatory': {
'OfferToReceiveAudio': true,
'OfferToReceiveVideo': true
}
};
navigator.webkitGetUserMedia({
audio: true,
video: true
}, function(stream) {
myStream = stream;
$("body").append('<video width="320" height="240" muted="muted" autoplay="true" src="' + window.URL.createObjectURL(stream) + '"></video>');
createPeerConnection();
peerConn.addStream(myStream);
peerConn.createOffer(function(sessionDescription) {
peerConn.setLocalDescription(sessionDescription);
console.log("Sending offer description");
Server.send(JSON.stringify(sessionDescription));
}, null, mediaConstraints);
}, function() {
console.error('Error in my stream');
});
function createPeerConnection() {
console.log('Creating peer connection');
peerConn = new webkitRTCPeerConnection({
'iceServers': [{
'url': 'stun:stun.l.google.com:19302'
}, {
'url': 'turn:107.150.19.220:3478',
'credential': 'turnserver',
'username': 'subrosa'
}]
}, {
'optional': [{
'DtlsSrtpKeyAgreement': 'true'
}]
});
peerConn.onicecandidate = function(event) {
if (event.candidate) {
Server.send(JSON.stringify({
type: 'candidate',
label: event.candidate.sdpMLineIndex,
id: event.candidate.sdpMid,
candidate: event.candidate.candidate
}));
} else {
console.error('Candidate denied');
}
};
peerConn.onaddstream = function(event) {
console.log("Adding remote strem");
$("body").append('<video width="320" height="240" autoplay="true" src="' + window.URL.createObjectURL(event.stream) + '"></video>');
};
peerConn.onremovestream = function(event) {
console.log("Removing remote stream");
};
}
Server.addEventListener("message", function(message) {
var msg = JSON.parse(message.data);
if(!myStream) {
console.error('Error in my stream');
}
if (msg.type === 'offer') {
createPeerConnection();
console.log('Adding local stream...');
peerConn.addStream(myStream);
peerConn.setRemoteDescription(new RTCSessionDescription(msg));
console.log("Sending answer to peer.");
peerConn.createAnswer(function(sessionDescription) {
peerConn.setLocalDescription(sessionDescription);
Server.send(JSON.stringify(sessionDescription));
}, null, mediaConstraints);
} else if (msg.type === 'answer') {
peerConn.setRemoteDescription(new RTCSessionDescription(msg));
} else if (msg.type === 'candidate') {
var candidate = new RTCIceCandidate({
sdpMLineIndex: msg.label,
candidate: msg.candidate
});
peerConn.addIceCandidate(candidate);
}
}, false);
问题是您正在尝试使用单个对等连接,但这只适用于单个连接方。您必须为彼此建立额外的对等连接,并且能够将 websocket 消息与用户和特定的对等连接相关联。你可以自己做,或者使用像 SimpleWebRTC 这样的库来为你管理多个用户会话。
编辑:
关于 SimpleWebRTC 工作原理的一个非常简单的解释是,这是创建连接客户端的网状网络的一个选项(所有客户端都连接到其他客户端):
- 一位客户加入了 "room"
- 客户会收到有关之前加入房间的每个客户的通知
- 对于每个其他客户端,客户端创建一个新的对等连接并将其存储在连接的对等数组中
- 当通过 websocket 接收消息时,它们必须与一个 Id 相关联,用于映射到正确的对等连接
此体系结构与您的体系结构的关键区别在于您创建的是 单个 对等连接,但您需要创建、存储,并跟踪 数组 对等连接,并且您必须将您的 websocket 消息映射到特定的对等点。
RTCPeerConnection 本质上是两个客户端(对等点)之间的一对一连接,所以如果你想超越它,你必须变得聪明。
最简单的步骤是创建网格,本质上是为每个其他参与者设置一个 PeerConnection,所有参与者都做同样的事情。不过,您将以这种方式很快地在客户端上传速度方面遇到瓶颈,通常最多有 3-4 名参与者,通常基于上传速度最低的参与者。
对于比这更大的组,您可能需要一些特殊设置,例如 MCU or Router solution,其中基本上是一个特殊服务器充当每个人都连接到的超级参与者,然后将视频混合在一起每个人(通常与任何人一起作为更大的视频发言),或将每个人的视频转发给每个人(因为上传速度通常是瓶颈)。
我正在开发用于视频通话 this 风格的会议风格应用程序 (many-to-many)。该代码在 GitHub 上可用,但我没有太多 node.js 经验,因此我决定使用 PHP.
创建自己的服务器我使用 WebSockets 创建了服务器。这很简单——它接收消息并将它们转发给所有其他连接的客户端(即,不是发送消息的客户端)。仅此而已-仅此而已;仅此而已。
但我的问题是这种架构不允许客户端与一个以上的人连接,即,当客户端尝试与第三人连接时,额外的流会失败。客户端只能连接 one-to-one.
不知道是JavaScript的错误还是需要改进服务器。我该怎么做才能连接到所有加入的客户?
查看我的代码:
HTML
<script type="text/javascript" src="http://127.0.0.1/scr/js/jquery.js"></script>
JavaScript
var Server = new WebSocket('ws://127.0.0.1:1805/'),
myStream = null,
peerConn = null,
mediaConstraints = {
'mandatory': {
'OfferToReceiveAudio': true,
'OfferToReceiveVideo': true
}
};
navigator.webkitGetUserMedia({
audio: true,
video: true
}, function(stream) {
myStream = stream;
$("body").append('<video width="320" height="240" muted="muted" autoplay="true" src="' + window.URL.createObjectURL(stream) + '"></video>');
createPeerConnection();
peerConn.addStream(myStream);
peerConn.createOffer(function(sessionDescription) {
peerConn.setLocalDescription(sessionDescription);
console.log("Sending offer description");
Server.send(JSON.stringify(sessionDescription));
}, null, mediaConstraints);
}, function() {
console.error('Error in my stream');
});
function createPeerConnection() {
console.log('Creating peer connection');
peerConn = new webkitRTCPeerConnection({
'iceServers': [{
'url': 'stun:stun.l.google.com:19302'
}, {
'url': 'turn:107.150.19.220:3478',
'credential': 'turnserver',
'username': 'subrosa'
}]
}, {
'optional': [{
'DtlsSrtpKeyAgreement': 'true'
}]
});
peerConn.onicecandidate = function(event) {
if (event.candidate) {
Server.send(JSON.stringify({
type: 'candidate',
label: event.candidate.sdpMLineIndex,
id: event.candidate.sdpMid,
candidate: event.candidate.candidate
}));
} else {
console.error('Candidate denied');
}
};
peerConn.onaddstream = function(event) {
console.log("Adding remote strem");
$("body").append('<video width="320" height="240" autoplay="true" src="' + window.URL.createObjectURL(event.stream) + '"></video>');
};
peerConn.onremovestream = function(event) {
console.log("Removing remote stream");
};
}
Server.addEventListener("message", function(message) {
var msg = JSON.parse(message.data);
if(!myStream) {
console.error('Error in my stream');
}
if (msg.type === 'offer') {
createPeerConnection();
console.log('Adding local stream...');
peerConn.addStream(myStream);
peerConn.setRemoteDescription(new RTCSessionDescription(msg));
console.log("Sending answer to peer.");
peerConn.createAnswer(function(sessionDescription) {
peerConn.setLocalDescription(sessionDescription);
Server.send(JSON.stringify(sessionDescription));
}, null, mediaConstraints);
} else if (msg.type === 'answer') {
peerConn.setRemoteDescription(new RTCSessionDescription(msg));
} else if (msg.type === 'candidate') {
var candidate = new RTCIceCandidate({
sdpMLineIndex: msg.label,
candidate: msg.candidate
});
peerConn.addIceCandidate(candidate);
}
}, false);
问题是您正在尝试使用单个对等连接,但这只适用于单个连接方。您必须为彼此建立额外的对等连接,并且能够将 websocket 消息与用户和特定的对等连接相关联。你可以自己做,或者使用像 SimpleWebRTC 这样的库来为你管理多个用户会话。
编辑:
关于 SimpleWebRTC 工作原理的一个非常简单的解释是,这是创建连接客户端的网状网络的一个选项(所有客户端都连接到其他客户端):
- 一位客户加入了 "room"
- 客户会收到有关之前加入房间的每个客户的通知
- 对于每个其他客户端,客户端创建一个新的对等连接并将其存储在连接的对等数组中
- 当通过 websocket 接收消息时,它们必须与一个 Id 相关联,用于映射到正确的对等连接
此体系结构与您的体系结构的关键区别在于您创建的是 单个 对等连接,但您需要创建、存储,并跟踪 数组 对等连接,并且您必须将您的 websocket 消息映射到特定的对等点。
RTCPeerConnection 本质上是两个客户端(对等点)之间的一对一连接,所以如果你想超越它,你必须变得聪明。
最简单的步骤是创建网格,本质上是为每个其他参与者设置一个 PeerConnection,所有参与者都做同样的事情。不过,您将以这种方式很快地在客户端上传速度方面遇到瓶颈,通常最多有 3-4 名参与者,通常基于上传速度最低的参与者。
对于比这更大的组,您可能需要一些特殊设置,例如 MCU or Router solution,其中基本上是一个特殊服务器充当每个人都连接到的超级参与者,然后将视频混合在一起每个人(通常与任何人一起作为更大的视频发言),或将每个人的视频转发给每个人(因为上传速度通常是瓶颈)。