Я разрабатываю приложение стиля конференции (многие-ко-многим) для видеозвонков этого стиля. Код доступен в GitHub, но у меня мало опыта работы с node.js, поэтому я решил создать свой собственный сервер с помощью PHP.
Я создал сервер с помощью WebSockets. Это просто – он получает сообщения и пересылает их всем другим подключенным клиентам (т. Е. Не клиенту, который отправил сообщение). Только это – ничего больше; не меньше.
Но моя проблема заключается в том, что эта архитектура не позволяет клиентам подключаться более чем к одному человеку, то есть когда клиент пытается подключиться к третьему лицу, дополнительные потоки терпят неудачу. Клиенты могут подключаться только один к одному.
Я не знаю, является ли ошибка в 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, является одним из вариантов создания сетчатой сети подключенных клиентов (все клиенты подключены друг к другу):
Критическая разница в вашей архитектуре заключается в том, что вы создаете одно одноранговое соединение, но вам нужно создавать, хранить и отслеживать массив одноранговых соединений, и вам нужно сопоставлять сообщения вашего веб-узла конкретным одноранговым узлам.
RTCPeerConnection по своей сути является взаимно-однозначным соединением между двумя клиентами (одноранговыми узлами), поэтому, если вы хотите выйти за рамки этого, вам нужно быть умным.
Самый простой шаг – создание сетки, по существу, создание одного PeerConnection для каждого из других участников, причем все участники делают то же самое. Вы быстро удаляете стену в скорости загрузки клиента таким образом, хотя обычно занимаете 3-4 участника, как правило, на основе участника с самой низкой скоростью загрузки.
Для групп, которые больше, чем вы, возможно, потребуется какая-то специальная настройка, например, решение MCU или Router , где по существу специальный сервер выступает в качестве супер-участника, к которому все подключаются, что затем смешивает видео каждого (обычно с кем бы то ни было выступая как более крупное видео) или пересылает все видео всем каждому (поскольку скорость загрузки, как правило, является узким местом).