代码之家  ›  专栏  ›  技术社区  ›  J03M4gnus

WebRTC:Firefox v 53之后ICE失败

  •  5
  • J03M4gnus  · 技术社区  · 7 年前

    我的webRTC项目有问题。我的代码在Chrome和Firefox上运行良好,直到52版。由于Firefox 53,我出现了错误:“ICE失败,请参阅关于:webrtc了解更多详细信息”。这是我的代码:

    let connection;
    let dataChannel;
    
     const initCon = (initiatorBoolean, choosenONE) => {
         createConnection();
         startConnection(initiatorBoolean, choosenONE);
         console.log('initCon(' + initiatorBoolean + ') / choosenONE = ' +choosenONE);
     }
    var boolJoin =  false;
    var lobbies = [];
    var me = prompt("Please enter your name", "Bert");
    
    
    // Helper für das Errorlogging
    const logErrors = err => console.log(err);
    
    // Websockets-Verbindung herstellen
    const socket = io.connect('http://7daysclub.de:8080');
    
    /* Methode to send information between to Users
    *@param
    *receiver= User who get the message
    *type= Type of the message: could be init, joined, getUsers, setUsers, offer, answer, candidate
    *descr= Content of the message
    */
     const sendMessage = (receiver, type, descr) => {
       message = Object.assign({to: 'default'}, {
           user: receiver,
           type: type,
           descr: descr,
           from: me
       });
       socket.emit('message', message);
       console.log("send: " + message.type + ". to: " + message.user);
    };
    
    const createConnection = () => {
        //Verbindung erstellen
        connection = new RTCPeerConnection( {
        'iceServers': [
            {
    
              /*
              'urls': 'stun:stun.l.google.com:19302'
              */
              'urls': 'stun:185.223.29.90:3478'
    
    
            },
            {
    
              'urls': 'turn:185.223.29.90:3478',
              'credential': '***',
              'username': '***'
    
    
            }
        ]
        });
        connection.oniceconnectionstatechange = function(event) {
          console.log('state: '+connection.iceConnectionState );
          if (connection.iceConnectionState === "failed" ||
              connection.iceConnectionState === "disconnected" ||
              connection.iceConnectionState === "closed") {
            // Handle the failure
          }
        };
    
    }
    
    const call = choosenONE => {
    
        if (!boolJoin) {
            sendMessage(choosenONE, 'joined', null);
        }
    
    };
    
    // Nachricht vom Signaling-Kanal empfangen
    const receiveMessage = message => {
       console.log("receive: " + message.type);
    
       //Filter messages
       if (message.user != 'all' && message.user != me) {
           console.log("Block= " + message.user);
           return;
       }
       // Nachricht verarbeiten
       switch (message.type) {
    
           // Partner ist verfügbar
          case 'joined':
             choosenONE = message.from;
             sendMessage( choosenONE, 'init', null);
             boolJoin = true;
             initCon(true, choosenONE);
             break;
    
          case 'getUsers':
             sendMessage(message.from,'setUsers', null)
             lobbies.push(message.from);
             lobbylist();
             console.log('add User: ' + lobbies[lobbies.length-1] + ' to List');
             break;
    
          case 'setUsers':
             lobbies.push(message.from);
             console.log('add User: ' + lobbies[lobbies.length-1] + ' to List');
             lobbylist();
             break;
    
          // Verbindungsaufbau wurde vom Partner angefordert
          case 'init':
             choosenONE = message.from;
             boolJoin = true;
             initCon(false, choosenONE);
             break;
    
    
          // Ein SDP-Verbindungsangebot ist eingegangen – wir erstellen eine Antwort
          case 'offer':
            connection
              .setRemoteDescription(new RTCSessionDescription(message.descr))
              .then(() => connection.createAnswer())
              .then(answer => connection.setLocalDescription(new RTCSessionDescription(answer)))
              .then(() => sendMessage(message.from,'answer', connection.localDescription, me))
              .catch(logErrors);
             break;
    
          // Eine SDP-Verbindungsantwort auf unsere Anfrage ist eingegangen.
          case 'answer':
             connection.setRemoteDescription(new RTCSessionDescription(message.descr));
             break;
    
          // Der Partner hat eine mögliche Host-Port-Kombination ("ICE Candidate") gefunden
          case 'candidate':
             connection.addIceCandidate(new RTCIceCandidate({candidate: message.descr}));
             break;
       }
    };
    
    socket.on('message', receiveMessage);
    
    
    
    // Verbindung initialisieren
    const startConnection = (isCreator, choosenONE) => {
        // Wenn wir mögliche Kommunikationsendpunkte finden, diese an den Partner weitergeben
        connection.onicecandidate = event => {
            if (event.candidate) {
                sendMessage(choosenONE, 'candidate', event.candidate.candidate);
            }
        };
    
        // Wenn die Gegenseite einen Stream hinzufügt, diesen an das video-element hängen
       connection.ontrack = (e) => {
          document.getElementById('vidRemote').src = window.URL.createObjectURL(e.stream);
       };
    
       // Falls wir der erste Teilnehmer sind, starten wir den Verbindungsaufbau
       if (isCreator) {
          // Datenkanal anlegen
          dataChannel = connection.createDataChannel('chat');
          onDataChannelCreated(dataChannel);
    
          connection
            .createOffer()
            .then(offer => connection.setLocalDescription(new RTCSessionDescription(offer)))
            .then(() => sendMessage(choosenONE, 'offer', connection.localDescription))
            .catch(logErrors);
    
       } else {
    
          // Wenn wir nicht der Initiator sind, reagieren wir nur auf das Anlegen eines Datenkanals
          connection.ondatachannel = function (event) {
             dataChannel = event.channel;
             onDataChannelCreated(dataChannel);
          };
    
       }
    };
    
    
    
    const onDataChannelCreated = (channel, choosenONE) => {
       // Sobald der Datenkanal verfügbar ist, Chateingaben zulassen
       channel.onopen = () => {
          const enterChat = document.getElementById('enterChat');
          enterChat.disabled = false;
          enterChat.onkeyup = (keyevent) => {
             // Bei "Enter" absenden
             if (keyevent.keyCode === 13) {
                dataChannel.send(enterChat.value);
                appendChatMessage(me+':', enterChat.value);
                enterChat.value = '';
             }
          }
       };
       channel.onmessage = (message) => appendChatMessage(choosenONE+':', message.data);
    };
    
    const appendChatMessage = (name, text) => {
       const displayChat = document.getElementById('displayChat');
       const time = new Date().toString('H:i:s');
       displayChat.innerHTML = `<p>${name} - ${time}<br>${text}</p>` + displayChat.innerHTML;
    };
    
    
    
    function lobbylist() {
        allusers = "";
        lobbies.forEach( element => {
            allusers += "<li><button onclick=\"call('"+element+"')\">"+element+"</button></li>"
        });
        document.getElementById('lobbylist').innerHTML = allusers;
    }
    
    //Alle User bei Ankunft erfragen
    sendMessage('all','getUsers', null);
    lobbylist();
    

    关于:webrtc=

    (注册表/信息)插入“ice”(注册表)成功:ice

    (注册表/信息)插入“ice”。pref’(注册表)成功:ice。首选项

    (注册表/信息)插入“ice”。pref.type’(注册表)成功:ice。首选类型

    (注册表/信息)插入“ice”。首选类型。srv\u rflx’(UCHAR)成功:0x64

    (注册表/信息)插入“ice”。首选类型。对等rflx’(UCHAR)成功:0x6e

    (注册表/信息)插入“ice”。首选类型。主机(UCHAR)成功:0x7e

    (注册表/信息)插入“ice”。首选类型。中继(UCHAR)成功:0x05

    (注册表/信息)插入“ice”。首选类型。srv\u rflx\u tcp’(UCHAR)成功:0x63

    (注册表/信息)插入“ice”。首选类型。对等rflx\U tcp’(UCHAR)成功:0x6d

    (注册表/信息)插入“ice”。首选类型。host_tcp(UCHAR)成功:0x7d

    (注册表/信息)插入“ice”。首选类型。中继tcp(UCHAR)成功:0x00

    (注册表/信息)插入“stun”(注册表)成功:stun

    (注册表/信息)插入“stun”。客户端(注册表)成功:stun。客户

    (注册表/信息)插入“stun”。客户最大传输次数(UINT4)成功:7

    (注册表/信息)插入“ice”。涓流宽限期(UINT4)成功:5000

    (注册表/信息)插入“ice”。tcp'(注册表)成功:ice。tcp协议

    (注册表/信息)插入“ice”。tcp。so\u sock\u count’(INT4)成功:0

    (注册表/信息)插入“ice”。tcp。listen\u backlog“(INT4)成功:10

    (注册表/信息)插入“ice”。tcp。禁用'(字符)成功:\000

    (通用/紧急)退出连接的UDP套接字

    (generic/ERR)UDP套接字错误:z:/build/build/src/dom/network/UDPSocketParent处的内部错误。cpp:283这=00000000 120CC400

    (ice/INFO)z:/build/build/src/media/mtransport/third\u party/nICEr/src/net/nr\u socket\u multi\u tcp。c: 173函数nr\u socket\u multi\u tcp\u create\u stun\u server\u socket跳过UDP stun server(地址:IP4:185.223.29.90:3478/UDP)

    (ice/INFO)z:/build/build/src/media/mtransport/third\u party/nICEr/src/net/nr\u socket\u multi\u tcp。c: 173函数nr\u socket\u multi\u tcp\u create\u stun\u server\u socket跳过UDP stun server(地址:IP4:185.223.29.90:3478/UDP)

    (ice/WARNING)z:/build/build/src/media/mttransport/third\u party/nICEr/src/net/nr\u socket\u multi\u tcp。c: 617函数nr\u socket\u multi\u tcp\u listen失败,出现错误3

    (ice/警告)ice(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/ )):未能创建被动TCP主机候选:3

    (ice/通知)ice(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/ )):对等(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/):default )没有具有非空检查表的流

    (ice/通知)ice(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/ )):对等(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/):默认值 )没有带有预应答请求的流

    (ice/通知)ice(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/ )):对等(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/):默认值 )无需开始检查

    (ice/ERR)ice(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/ )):对等(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/):默认值 )配对本地涓流ICE候选主机(IP4:192.168.0.4:54605/UDP)

    (ice/ERR)ice(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/ )):对等(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/):默认值 )配对本地涓流ICE候选主机(IP4:192.168.0.4:62417/TCP)处于活动状态

    (stun/INFO)无法识别的属性:0x802b

    (stun/INFO)stun-CLIENT(srflx(IP4:192.168.0.4:54605/UDP | IP4:185.223.29.90:3478/UDP)):收到响应;处理

    (ice/ERR)ice(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/ )):对等(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/):默认值 )配对本地涓流冰候选srflx(IP4:192.168.0.4:54605/UDP | IP4:185.223.29.90:3478/UDP)

    (stun/INFO)stun-CLIENT(中继(IP4:192.168.0.4:54605/UDP | IP4:185.223.29.90:3478/UDP)::TURN):收到响应;处理

    (stun/WARNING)stun-CLIENT(中继(IP4:192.168.0.4:54605/UDP | IP4:185.223.29.90:3478/UDP)::TURN):错误处理响应:可能会重试,stun错误代码401。

    (stun/INFO)stun-CLIENT(中继(IP4:192.168.0.4:54605/UDP | IP4:185.223.29.90:3478/UDP)::TURN):收到响应;处理

    (stun/WARNING)stun-CLIENT(中继(IP4:192.168.0.4:54605/UDP | IP4:185.223.29.90:3478/UDP)::TURN):错误处理响应:可能会重试,stun错误代码401。

    (转向/警告)转向(中继(IP4:192.168.0.4:54605/UDP | IP4:185.223.29.90:3478/UDP)):超过重试次数

    (转向/警告)转向(继电器(IP4:192.168.0.4:54605/UDP | IP4:185.223.29.90:3478/UDP))失败

    (转弯/警告)ICE-候选(中继(IP4:192.168.0.4:54605/UDP | IP4:185.223.29.90:3478/UDP)):nr_turn_allocated_cb调用状态4

    (转弯/警告)候选ICE(中继(IP4:192.168.0.4:54605/UDP | IP4:185.223.29.90:3478/UDP)):nr_转弯_分配的cb失败

    (ice/INFO)ice(PC:1512241952789000(id=19327352835 url= )):对等(PC:1512241952789000(id=19327352835 url= )涓流宽限期结束;将每个只有故障对的组件标记为故障。

    (ice/INFO)ice-PEER(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/):default)/STREAM(0-1512241952789000 (id=19327352835 url= http://7daysclub.de/webrtc2/ )aLevel=0)/COMP(1):所有对都失败,并且已过宽限期。将组件标记为故障。

    (ice/INFO)ice-PEER(PC:1512241952789000(id=19327352835 url= http://7daysclub.de/webrtc2/):默认值

    (通用/紧急)退出连接的UDP套接字

    (generic/ERR)UDP套接字错误:z:/build/build/src/dom/network/UDPSocketParent处的内部错误。cpp:283这=000000000 BAE3000

    (ice/INFO)z:/build/build/src/media/mtransport/third\u party/nICEr/src/net/nr\u socket\u multi\u tcp。c: 173函数nr\u socket\u multi\u tcp\u create\u stun\u server\u socket跳过UDP stun server(地址:IP4:185.223.29.90:3478/UDP)

    (ice/INFO)z:/build/build/src/media/mtransport/third\u party/nICEr/src/net/nr\u socket\u multi\u tcp。c: 173函数nr\u socket\u multi\u tcp\u create\u stun\u server\u socket跳过UDP stun server(地址:IP4:185.223.29.90:3478/UDP)

    (ice/WARNING)z:/build/build/src/media/mttransport/third\u party/nICEr/src/net/nr\u socket\u multi\u tcp。c: 617函数nr\u socket\u multi\u tcp\u listen失败,出现错误3

    (ice/警告)ice(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/ )):未能创建被动TCP主机候选:3

    http://7daysclub.de/webrtc2/ )):对等(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/):默认值 )没有具有非空检查表的流

    (ice/通知)ice(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/ )):对等(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/):默认值 )没有带有预应答请求的流

    (ice/通知)ice(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/ )):对等(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/):默认值 )无需开始检查

    (ice/ERR)ice(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/ )):对等(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/):默认值 )配对本地涓流ICE候选主机(IP4:192.168.0.4:63286/UDP)

    (ice/ERR)ice(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/ )):对等(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/):默认值 )配对本地涓流ICE候选主机(IP4:192.168.0.4:54433/TCP)处于活动状态

    (stun/INFO)无法识别的属性:0x802b

    (stun/INFO)stun-CLIENT(srflx(IP4:192.168.0.4:63286/UDP | IP4:185.223.29.90:3478/UDP)):收到响应;处理

    (ice/ERR)ice(PC:151224212537500(id=19327352836 url= )):对等(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/):默认值 )配对本地涓流冰候选srflx(IP4:192.168.0.4:63286/UDP | IP4:185.223.29.90:3478/UDP)

    (stun/INFO)stun-CLIENT(中继(IP4:192.168.0.4:63286/UDP | IP4:185.223.29.90:3478/UDP)::TURN):收到响应;处理

    (stun/WARNING)stun-CLIENT(中继(IP4:192.168.0.4:63286/UDP | IP4:185.223.29.90:3478/UDP)::TURN):错误处理响应:可能会重试,stun错误代码401。

    (stun/INFO)stun-CLIENT(中继(IP4:192.168.0.4:63286/UDP | IP4:185.223.29.90:3478/UDP)::TURN):收到响应;处理

    (turn/INFO)turn(中继(IP4:192.168.0.4:63286/UDP | IP4:185.223.29.90:3478/UDP)):成功分配地址IP4:185.223.29.90:50497/UDP生存期=3600

    (ice/ERR)ice(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/ )):对等(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/):默认值 )配对本地涓流冰候选转向继电器(IP4:192.168.0.4:63286/UDP | IP4:185.223.29.90:50497/UDP)

    (ice/INFO)ice(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/ )):对等(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/):默认值 )涓流宽限期结束;将每个只有故障对的组件标记为故障。

    (ice/INFO)ice-PEER(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/):default)/STREAM(0-1512242125375000 (id=19327352836 url= http://7daysclub.de/webrtc2/ )aLevel=0)/COMP(1):所有对都失败,并且已过宽限期。将组件标记为故障。

    (ice/INFO)ice-PEER(PC:151224212537500(id=19327352836 url= http://7daysclub.de/webrtc2/):默认值 ):所有检查完成成功=0失败=1

    +++++++结束++++++++

    我的turnserver配置如下所示:

    # TURN listener port for UDP and TCP (Default: 3478).
    # Note: actually, TLS & DTLS sessions can connect to the 
    # "plain" TCP & UDP port(s), too - if allowed by configuration.
    #
    listening-port=3478
    
    # TURN listener port for TLS (Default: 5349).
    # Note: actually, "plain" TCP & UDP sessions can connect to the TLS & DTLS
    # port(s), too - if allowed by configuration. The TURN server 
    # "automatically" recognizes the type of traffic. Actually, two listening
    # endpoints (the "plain" one and the "tls" one) are equivalent in terms of
    # functionality; but we keep both endpoints to satisfy the RFC 5766 specs.
    # For secure TCP connections, we currently support SSL version 3 and 
    # TLS version 1.0, 1.1 and 1.2. SSL2 "encapculation mode" is also supported.
    # For secure UDP connections, we support DTLS version 1.
    #
    tls-listening-port=5349
    
    # Listener IP address of relay server. Multiple listeners can be specified.
    # If no IP(s) specified in the config file or in the command line options, 
    # then all IPv4 and IPv6 system IPs will be used for listening.
    #
    listening-ip=185.223.29.90
    
    # Relay address (the local IP address that will be used to relay the 
    # packets to the peer).
    # Multiple relay addresses may be used.
    # The same IP(s) can be used as both listening IP(s) and relay IP(s).
    #
    # If no relay IP(s) specified, then the turnserver will apply the default
    # policy: it will decide itself which relay addresses to be used, and it 
    # will always be using the client socket IP address as the relay IP address
    # of the TURN session (if the requested relay address family is the same
    # as the family of the client socket).
    #
    relay-ip=185.223.29.90
    
    
    lt-cred-mech
    
    
    # Realm for long-term credentials mechanism and for TURN REST API.
    #
    realm=7daysclub.de
    
    
    #Local system IP address to be used for CLI server endpoint. Default value
    # is 127.0.0.1.
    #
    cli-ip=185.223.29.90
    
    # CLI server port. Default is 5766.
    #
    cli-port=5766
    
    1 回复  |  直到 7 年前
        1
  •  10
  •   Philipp Hancke    7 年前

    查看您的在线演示,远程SDP中没有a=candidate行,这表明从未添加候选人。 sendMessage(choosenONE, 'candidate', event.candidate.candidate); 这将丢弃需要用信号发送给远程对等方的sdpMid和sdpMLineIndex。添加。捕获addIceCandidate以记录任何错误。