Работает только с один-к-одному, из которых должно было быть много-ко-многим, webrtc

Я разрабатываю приложение в стиле конференции (многие-ко-многим) для видеозвонков в этом стиле. Код доступен на 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);

person user5128061    schedule 17.07.2015    source источник
comment
Я могу подключаться один к одному, но когда я подключаю третьего человека, третье лицо подключается только к первому. Первый соединяется со вторым и третьим. Второй соединяется с первым. Третий соединяется с первым. Я потерялся в разрешении этого тупика   -  person user5128061    schedule 19.07.2015


Ответы (2)


Проблема в том, что вы пытаетесь использовать одно одноранговое соединение, но это будет работать только для одной подключенной стороны. Вам нужно будет иметь дополнительное одноранговое соединение для каждой другой стороны и иметь возможность связывать сообщения веб-сокета с пользователями и конкретным одноранговым соединением. Вы можете сделать это самостоятельно или использовать такую ​​библиотеку, как SimpleWebRTC, которая управляет несколькими пользовательскими сеансами за вас.

Изменить:

Очень упрощенное объяснение того, как работает SimpleWebRTC, - это один из вариантов создания ячеистой сети из подключенных клиентов (все клиенты подключены друг к другу):

  1. Клиент присоединяется к «комнате»
  2. Клиент уведомляется о каждом клиенте, который ранее присоединился к комнате.
  3. Для каждого другого клиента клиент создает новое одноранговое соединение и сохраняет его в массиве подключенных одноранговых узлов.
  4. Когда сообщения принимаются через веб-сокет, они должны быть связаны с идентификатором, используемым для сопоставления с правильным одноранговым соединением.

Критическое отличие этой архитектуры от вашей заключается в том, что вы создаете одиночное одноранговое соединение, но вам необходимо создать, сохранить и отслеживать массив. одноранговых соединений, и вы должны сопоставить свои сообщения веб-сокета определенным одноранговым узлам.

person xdumaine    schedule 17.07.2015
comment
Вы могли бы быть более пояснительными? Я понимаю вашу основную идею, но хочу знать, что делать более конкретно. Хотите, как исправить мой код ... - person user5128061; 17.07.2015
comment
@ user5128061 Хотите способ исправить мой код ... Нет, ваш код нельзя исправить, потому что он в корне ошибочен. Его нужно переписать или использовать библиотеку, поддерживающую несколько подключений. - person Ghedipunk; 18.07.2015
comment
вы могли бы, например, создайте массив одноранговых соединений, проиндексируйте его, например, с помощью remotepeerID, затем во все обменяемые сообщения добавьте sourceID и PeerID, чтобы сопоставить сообщение с правильным одноранговым соединением в массиве. - person Dr. Alex Gouaillard; 18.07.2015
comment
@Ghedipunk Я бы не хотел использовать библиотеку по личным причинам, тогда вы можете показать мне способы восстановить мой код? - person user5128061; 18.07.2015
comment
@AlexGouaillard Я могу немного понять его логику, но это будет на сервере или на клиентском коде? Могло бы быть более наглядным? - person user5128061; 18.07.2015
comment
@ user5128061 Предполагая, что вы написали свой исходный код, вы, кажется, более чем способны его рефакторинг, чтобы разрешить множеству пользователей. С другой стороны, если вы скопируете и вставите его, я не окажу вам никакой пользы, предоставив вам больше кода для копирования и вставки. Вы ничему не научитесь и в конечном итоге получите беспорядок в проекте, который вы не понимаете и который совершенно не в состоянии поддерживать. Каждый разработчик, который прикоснется к проекту после вас, проклянет свое имя и мое имя за то, что вы помогли. - person Ghedipunk; 18.07.2015
comment
@Ghedipunk Конечно! Совершенно понимаю, что вы говорите, но этот код действительно мой, настолько, что я обновляю, как вы можете видеть в редакции вопроса, но я непрофессионал в WebRTC, что означает, что я не знаю, куда идти . Я продвинулся в сценарии и получил кое-что существенное: я могу подключаться один к одному, но когда я подключаю третьего человека, третье лицо подключается только к первому. Первый соединяется со вторым и третьим. Второй соединяется с первым. Третий соединяется с первым. Я потерялся в разрешении этого тупика .. - person user5128061; 18.07.2015
comment
Ок, отлично. Если вам нужна дополнительная помощь (или в будущем), опубликуйте код, и люди смогут делать запросы на вытягивание. - person Dr. Alex Gouaillard; 21.07.2015

RTCPeerConnection по своей сути является однозначным соединением между двумя клиентами (одноранговыми узлами), поэтому, если вы хотите выйти за рамки этого, вам нужно быть умным.

Самый простой шаг - это создание сетки, по сути, установка одного PeerConnection для каждого из других участников, при этом все участники делают одно и то же. Таким образом, вы столкнетесь с проблемой скорости загрузки клиента довольно быстро, как правило, до 3-4 участников, обычно в зависимости от участника с самой низкой скоростью загрузки.

Для групп большего размера вам, вероятно, понадобится специальная настройка, например, MCU или решение для маршрутизатора , где, по сути, специальный сервер действует как суперучастник, к которому все подключаются, который затем либо смешивает видео всех (обычно с тем, кто говорит, как более крупное видео), либо пересылает видео каждого всем (поскольку скорость загрузки обычно узкое место).

person jib    schedule 18.07.2015
comment
Я понял то, что вы сказали в теории, но не применимо на практике, вы можете мне помочь? - person user5128061; 18.07.2015
comment
Я снова обновил свой код, пытаясь достичь, я могу подключиться один к одному, но когда я подключаю третьего человека, третье лицо подключается только к первому. Первый соединяется со вторым и третьим. Второй соединяется с первым. Третий соединяется с первым. Я потерялся в решении этого тупика - person user5128061; 18.07.2015
comment
@ user5128061 см. другой мой ответ о сетке. - person jib; 17.08.2016