Многопользовательское видео - PullRequest
0 голосов
/ 16 июня 2020

Этот вопрос задавали несколько раз раньше, но мне не удалось заставить какое-либо решение работать. Я создаю многопользовательский видеочат. Однако всякий раз, когда одноранговый узел пытается подключиться, я получаю эту ошибку:

DOMException: не удалось выполнить 'setRemoteDescription' в 'RTCPeerConnection': не удалось установить удаленный ответ sdp: вызывается в неправильном состоянии: kStable

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

// When a remote user joins, an object of this class is created.
// Its job is to create am RTCPeerConnection between the local user
// and the remote user.
class VideoChat
{
    constructor(name, remoteView)
    {
        this.remoteName = name;   // ID of remote peer used by signal server
        this.remoteView = remoteView;  // html video object to display remote video

        var configuration = {"iceServers": [
            {urls: "stun:stun.l.google.com:19302"}
            {urls: "turn:numb.viagenie.ca", username: "xxx", credential: "xxx"}
        ]};

        this.pc = new RTCPeerConnection(configuration);

        // 'onicecandidate' notifies us whenever an ICE agent needs to deliver a
        // message to the other peer through the signaling server
        this.pc.onicecandidate = event => {
            if (event.candidate) {
                ChatRoom.relay("signal", this.remoteName, event.candidate);
                console.log(`onicecadidate (${this.remoteName}): ${event.candidate}`);
            }
        };

        // let the 'negotiationneeded' event create the offer
        this.pc.onnegotiationneeded = async () => {
            try {
                await this.pc.setLocalDescription();
                ChatRoom.relay("signal", this.remoteName, {desc: this.pc.localDescription})
            } catch (err) {
                console.error(err);
            }
        }

        // When a remote stream arrives display it in the #remoteView element
        this.pc.ontrack = (track, streams) => {
            log("adding remote TRACK to video element");
            // don't set srcObject again if it is already set.
            if (this.remoteView.srcObject) return;
            this.remoteView.srcObject = event.streams[0];
        };
    }

    // This is called by main program when a remote user has signed on
    // This initiates everything....
    // localVideo is html video element connected to local camera
    // stream is the main (local) user's mediaStream
    async start(localVideo, stream) {
        try {
            for (const track of stream.getTracks()) {
                this.pc.addTrack(track, stream);
            }
            localVideo.srcObject = stream;
        } catch (err) {
            console.error(err);
        }
    }

    // A message from the signal server
    async onmessage(message) {
        try {
            if (message.desc) {
                await this.pc.setRemoteDescription(message.desc);
                if (message.desc.type == "offer") {
                    await this.pc.setLocalDescription();
                    ChatRoom.relay("signal", this.remoteName, {desc: this.pc.localDescription});
                }
            }
            else if (message.candidate) {
                await this.pc.addIceCandidate(message);
            }
        } catch (err) {
            console.error(err);
        }
    }
}

Обратите внимание на функцию: ChatRoom.relay("signal", this.remoteName, something) отправляет сообщение на сервер сигналов, которое передается только на удаленный узел с идентификатором this.remoteName.

Кроме того, я использую свой собственный сервер сигналов, созданный в Java.

1 Ответ

1 голос
/ 16 июня 2020

Если вы установите удаленное описание разных одноранговых узлов в одном одноранговом соединении, это не будет работать. Как следует из названия "одноранговое соединение", оно указывается c одноранговому узлу.

Вызов this.pc.setLocalDescription() без создания предложения может поддерживаться в некоторых браузерах, но будьте осторожны. Также вы никогда не создаете ответа, а только сигнализируете о местном описании. Вы также ничего не делаете с ответами.

https://webrtc.github.io/samples/src/content/peerconnection/multiple/ - это канонический пример того, как все делать правильно.

...