【问题标题】:WebRTC succesfully signalled offer and answer, but not getting any ICE candidatesWebRTC 成功发出报价和答复信号,但未获得任何 ICE 候选人
【发布时间】:2023-02-21 10:27:12
【问题描述】:

我正在尝试在两个浏览器之间建立 WebRTC 连接。我有一个 node.js 服务器供他们进行通信,它基本上只是将消息从一个客户端转发到另一个客户端。我在笔记本电脑上运行服务器和两个选项卡,但无法建立连接。我已经能够成功地在两个选项卡之间发送报价和答案,从而在两个选项卡中生成 pc.signalingState = 'stable'。我相信一旦完成此操作,RTCPeerConnection 对象就应该开始生成 icecandidate 事件,但这并没有发生,我不知道为什么。这是我的代码(我省略了服务器代码):

'use strict';
// This is mostly copy pasted from webrtc.org/getting-started/peer-connections.

import { io } from 'socket.io-client';

const configuration = {
    'iceServers': [
        { 'urls': 'stun:stun4.l.google.com:19302' },
        { 'urls': 'stun:stunserver.stunprotocol.org:3478' },
    ]
}

// Returns a promise for an RTCDataChannel
function join() {
    const socket = io('ws://localhost:8090');
    const pc = new RTCPeerConnection(configuration);

    socket.on('error', error => {
        socket.close();
        throw error;
    });

    pc.addEventListener('signalingstatechange', event => {
        // Prints 'have-local-offer' then 'stable' in one tab,
        // 'have-remote-offer' then 'stable' in the other.
        console.log(pc.signalingState);
    })

    pc.addEventListener('icegatheringstatechange', event => {
        console.log(pc.iceGatheringState); // This line is never reached.
    })


    // Listen for local ICE candidates on the local RTCPeerConnection
    pc.addEventListener('icecandidate', event => {
        if (event.candidate) {
            console.log('Sending ICE candidate'); // This line is never reached.
            socket.emit('icecandidate', event.candidate);
        }
    });

    // Listen for remote ICE candidates and add them to the local RTCPeerConnection
    socket.on('icecandidate', async candidate => {
        try {
            await pc.addIceCandidate(candidate);
        } catch (e) {
            console.error('Error adding received ice candidate', e);
        }
    });

    // Listen for connectionstatechange on the local RTCPeerConnection
    pc.addEventListener('connectionstatechange', event => {
        if (pc.connectionState === 'connected') {
            socket.close();
        }
    });

    // When both browsers send this signal they will both receive the 'matched' signal,
    // one with the payload true and the other with false.
    socket.emit('join');
    
    return new Promise((res, rej) => {
        socket.on('matched', async first => {
            if (first) {
                // caller side
                socket.on('answer', async answer => {
                    await pc.setRemoteDescription(new RTCSessionDescription(answer))
                        .catch(console.error);
                });
                const offer = await pc.createOffer();
                await pc.setLocalDescription(offer)
                    .catch(console.error);
                socket.emit('offer', offer);

                // Listen for connectionstatechange on the local RTCPeerConnection
                pc.addEventListener('connectionstatechange', event => {
                    if (pc.connectionState === 'connected') {
                        res(pc.createDataChannel('data'));
                    }
                });

            } else {
                // recipient side
                socket.on('offer', async offer => {
                    pc.setRemoteDescription(new RTCSessionDescription(offer))
                        .catch(console.error);
                    const answer = await pc.createAnswer();
                    await pc.setLocalDescription(answer)
                        .catch(console.error);
                    socket.emit('answer', answer);
                });

                pc.addEventListener('datachannel', event => {
                    res(event.channel);
                });
            }
        });
    });
}

join().then(dc => {
    dc.addEventListener('open', event => {
        dc.send('Hello');
    });
    dc.addEventListener('message', event => {
        console.log(event.data);
    });
});

Firefox 和 Chrome 中的行为是相同的。这种行为再次表明,要约和答案已成功发出信号,但从未创建过 ICE 候选人。有谁知道我错过了什么?

【问题讨论】:

    标签: webrtc stun


    【解决方案1】:

    好的,我发现了问题。我必须在创建报价之前创建RTCDataChannel。这是 SDP 报价前后的比较:

    # offer created before data channel:
    {
      type: 'offer',
      sdp: 'v=0
    ' +
        'o=- 9150577729961293316 2 IN IP4 127.0.0.1
    ' +
        's=-
    ' +
        't=0 0
    ' +
        'a=extmap-allow-mixed
    ' +
        'a=msid-semantic: WMS
    '
    }
    
    # data channel created before offer:
    {
      type: 'offer',
      sdp: 'v=0
    ' +
        'o=- 1578211649345353372 2 IN IP4 127.0.0.1
    ' +
        's=-
    ' +
        't=0 0
    ' +
        'a=group:BUNDLE 0
    ' +
        'a=extmap-allow-mixed
    ' +
        'a=msid-semantic: WMS
    ' +
        'm=application 9 UDP/DTLS/SCTP webrtc-datachannel
    ' +
        'c=IN IP4 0.0.0.0
    ' +
        'a=ice-ufrag:MZWR
    ' +
        'a=ice-pwd:LfptE6PDVughzmQBPoOtvaU8
    ' +
        'a=ice-options:trickle
    ' +
        'a=fingerprint:sha-256 1B:C4:38:9A:CD:7F:34:20:B8:8D:78:CA:4A:3F:81:AE:C5:55:B3:27:6A:BD:E5:49:5A:F9:07:AE:0C:F6:6F:C8
    ' +
        'a=setup:actpass
    ' +
        'a=mid:0
    ' +
        'a=sctp-port:5000
    ' +
        'a=max-message-size:262144
    '
    }
    
    

    在这两种情况下,答案看起来都与报价相似。您会看到报价要长得多,并在第二种情况下提到webrtc-datachannel。果然,我开始收到 icecandidate 事件,现在一切正常。

    【讨论】:

      猜你喜欢
      • 2016-08-18
      • 1970-01-01
      • 2014-01-03
      • 2014-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-08
      相关资源
      最近更新 更多