Onicecandidate 不会在第二台 PC 上开火

Onicecandidate not fire at second pc

本文关键字:二台 PC 开火 Onicecandidate      更新时间:2023-09-26

我的webrtc聊天代码有问题。 我无法在对等方之间建立连接。PC1通过信号服务器发送报价请求成功,PC2添加候选人,但PC2无法向PC1发送候选人和应答,为什么?

几个小时都找不到错误,请帮我建立webrtc连接。

应用.js

var app = require('express')();
var server = require('http').createServer(app);
var virtualDirPath = process.env.virtualDirPath || '';
var io = require('socket.io')(server)//(server, { path: virtualDirPath + '/socket.io' });
var users = {};
server.listen(process.env.PORT || 8080, function () {
  console.log('Подняли сервер на *:8080');
});
app.get('/', function (req, res) {
  res.sendFile(__dirname + '/index.html');
});
app.get('/style.css', function (req, res) {
  res.sendFile(__dirname + '/style.css');
});
app.get('/index.js', function (req, res) {
  res.sendFile(__dirname + '/index.js');
});
io.on('connection', function (socket) {  
    socket.on('login', function(data){
        console.log('Зашел пользователь:', data.name);
        //Не даем подключиться если пользователь уже в чате
        if(users[data.name]) { 
            socket.emit('login', {state: 'taken'});           
        }else{
            socket.name = data.name;
            users[data.name] = socket;
            socket.broadcast.emit('newuser', {name: data.name});
            socket.emit('login', {name: data.name}); 
        }
    });
    //format offer
    socket.on('offer', function(data){//data.name, data.localDescription
        console.log('Поулчили offer для:', data.to);
        users[data.to].emit("offer", data);
    });   
    socket.on('answer', function(data){//data.name, data.localDescription
        console.log('Поулчили answer для:', data.to);
        console.log(data);
        users[data.to].emit("offer", data);
    }); 
    socket.on('candidate', function(data){//data.name, data.candidate
        console.log('Поулчили candidate для:', data.to);
        users[data.to].emit("candidate", data);
    }); 
    socket.on('disconnect', function (data) {
        console.log(data);
        io.emit('user disconnected',data.to);
        io.sockets.emit('quit', {name: data.from}) 
        delete users[data.from]; 
    });
});

索引.html:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8"> 
  <title></title>
  <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
  <link rel="stylesheet" type="text/css" href="style.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>  
</head>
<body>
<div class="modal fade" id="login-modal" tabindex="-1" role="dialog" data-keyboard="false" data-backdrop="static" aria-hidden="true" style="display: none;">
  <div class="modal-dialog">
    <div class="loginmodal-container">
      <h1>Войдите в чат</h1><br>
      <form id="loginForm">
        <input type="text" name="username" placeholder="Username">
        <input type="submit" id="login" class="login loginmodal-submit" value="Вход">
      </form>
    </div>
  </div>
</div>

<script src="https://cdn.socket.io/socket.io-1.3.5.js"></script>
<script src="index.js"></script>
</body>
</html>

索引.js:

var PeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
var IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;
var SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription;
var socket;
var peers = {};
var server = {
  iceServers: [
    {url: "stun:23.21.150.121"},
    {url: "stun:stun.l.google.com:19302"}
  ]
};
var options = {
  optional: [
    {DtlsSrtpKeyAgreement: true}, // требуется для соединения между Chrome и Firefox
    {RtpDataChannels: true} // требуется в Firefox для использования DataChannels API
  ]
}
 $(document).ready(function () {     
      $('#login-modal').modal('show');
       //Логинимся.  
      $('#loginForm').on('submit', function(e) {
        e.preventDefault();
        var name = $('input[name=username]').val();
        if (!name) {
          alert('Вы не ввели логин');
          return;
        }else{
          //подключаемся к сигнальному серверу
          socket = io.connect(':8080', {
            forceNew: true
          });
          socket.emit('login',{name: name})          
        }
        socket.on('login', function(data){
          var current_name = data.name;
          if(data.state === 'taken'){
            alert('Пльзователь с таким ником уже находится в чате');
          }else if(data.name != undefined){
            console.log('Успешно зашли в чат');
            socket.on('newuser', function(data){
              console.log('receive newuser ', data.name);
              peers[data.name] = {
                cache: []
              };              
              // Создаем новое подключение
                var pc = new PeerConnection(server, options);
              // Инициализируем его
                initConn(pc, data.name, current_name, "offer");
              // Сохраняем пир в списке
              peers[data.name].connection = pc;
              // Создаем DataChannel по которому и будет происходить обмен сообщениями
              var channel = pc.createDataChannel("chatchannel", {});
              channel.owner = data.name;
              peers[data.name].channel = channel;
              // Устанавливаем обработчики событий канала
              bindEvents(channel);
              // Создаем SDP offer
              pc.createOffer(function(offer) {
                console.log('Установили локальный дескрипшен');
                pc.setLocalDescription(offer);
              },function(err){
                console.log(err);
              });             
            });
            socket.on('candidate', function(data){
              console.log('receive candidate from ', data.from);
              createConnection(data.from, current_name);
              var pc = peers[data.from].connection;
              console.log(data.candidate);
                pc.addIceCandidate(new IceCandidate(data.candidate));
            });
            socket.on('offer', function(data){ //name,localDescription
                console.log('receive offer from ', data.from);
                createConnection(data.from, current_name);
                var pc = peers[data.from].connection;
                console.log(pc);
                pc.setRemoteDescription(new SessionDescription(data.localDescription));
                pc.createAnswer(function(answer) {                  
                  pc.setLocalDescription(answer);
                  console.log('answer created');
                },function(err){
                  console.log(err);
                });
            });
            socket.on('answer', function(data){   
              console.log('receive answer from ', data.from);           
              var pc = peers[data.name].connection;
                pc.setRemoteDescription(new SessionDescription(data.localDescription));
            });
          }else{
              alert('Ошибка при логине');
              location.reload();
          }
        });
      });      
 });

function createConnection(name, current_name){
   //Инициализируем подключение если его нет
   console.log(peers[name])
  if (peers[name] === undefined){
    peers[name] = {
      cache: []
    };
    var pc = new PeerConnection(server, options);
    initConn(pc, name, current_name, 'answer');
    peers[name].connection = pc;
    pc.ondatachannel = function(e) {
      peers[name].channel = e.channel;
      peers[name].channel.owner = name;
      bindEvents(peers[name].channel);
    }
    console.log('CreateConnection');
    console.log(pc)
  }
}
function initConn(pc, name, current_name, sdpType) {
  console.log(pc);
  console.log('-----------------------------------------')
    pc.onicecandidate = function (event) {
        if (event.candidate) {
            // При обнаружении нового ICE кандидата добавляем его в список для дальнейшей отправки
            peers[name].cache.push(event.candidate);
      console.log('1');
        } else {
            // Когда обнаружение кандидатов завершено, обработчик будет вызван еще раз, но без кандидата
            // В этом случае мы отправялем пиру сначала SDP offer или SDP answer (в зависимости от SDP запроса)
            socket.emit(sdpType, {to: name, from: current_name, localDescription: pc.localDescription});
      console.log('init conn');
      console.log(name);
      console.log(current_name);
      console.log(sdpType);
            // ...а затем все найденные ранее ICE кандидаты
            for (var i = 0; i < peers[name].cache.length; i++) {
        socket.emit("candidate", {to: name, from: current_name, candidate: peers[name].cache[i]});
            }
        }
    }
    pc.oniceconnectionstatechange = function (event) {
        if (pc.iceConnectionState == "disconnected") {
      //Пир отключился
      //TODO добавить в список пользоавтелей data.name
            delete peers[id];
        }
    }
}
function bindEvents (channel) {
    channel.onopen = function () {
    //TODO добавить в список пользоавтелей channel.owner
    };
    channel.onmessage = function (e) {
    //TODO add text of message to chat div e.data
    };
}

PC2 具有 localDescription 和 remoteDescription。PC2 对等连接日志:

RTCPeerConnection {localDescription: RTCSessionDescription, remoteDescription: RTCSessionDescription, signalingState: "stable", iceGatheringState: "new", iceConnectionState: "new"…}
iceConnectionState
:
"new"
iceGatheringState
:
"new"
localDescription
:
RTCSessionDescription
sdp
:
"v=0
↵o=- 4651396889672739307 2 IN IP4 127.0.0.1
↵s=-
↵t=0 0
↵a=msid-semantic: WMS
↵m=application 0 UDP/TLS/RTP/SAVPF 127
↵c=IN IP4 0.0.0.0
↵a=rtcp:9 IN IP4 0.0.0.0
↵a=mid:data
↵a=recvonly
↵a=rtcp-mux
↵a=rtpmap:127 google-data/90000
↵"
type
:
"answerswer"
__proto__
:
RTCSessionDescription
onaddstream
:
null
ondatachannel
:
(e)
onicecandidate
:
(event)
oniceconnectionstatechange
:
(event)
onnegotiationneeded
:
null
onremovestream
:
null
onsignalingstatechange
:
null
remoteDescription
:
RTCSessionDescription
sdp
:
"v=0
↵o=- 1739995165662969380 2 IN IP4 127.0.0.1
↵s=-
↵t=0 0
↵a=group:BUNDLE data
↵a=msid-semantic: WMS
↵m=application 2740 UDP/TLS/RTP/SAVPF 127
↵c=IN IP4 5.141.232.232
↵b=AS:30
↵a=rtcp:2120 IN IP4 5.141.232.232
↵a=candidate:985767174 1 udp 2113937151 192.168.100.2 58907 typ host generation 0
↵a=candidate:985767174 2 udp 2113937150 192.168.100.2 58909 typ host generation 0
↵a=candidate:842163049 1 udp 1677729535 5.141.232.232 2740 typ srflx raddr 192.168.100.2 rport 58907 generation 0
↵a=candidate:842163049 2 udp 1677729534 5.141.232.232 2120 typ srflx raddr 192.168.100.2 rport 58909 generation 0
↵a=candidate:842163049 2 udp 1677729534 5.141.232.232 2910 typ srflx raddr 192.168.100.2 rport 58909 generation 0
↵a=candidate:842163049 1 udp 1677729535 5.141.232.232 2830 typ srflx raddr 192.168.100.2 rport 58907 generation 0
↵a=ice-ufrag:TYKF98cRmZWIRAm5
↵a=ice-pwd:viHciQB6l36zfTuHdZCnJDPY
↵a=fingerprint:sha-256 10:01:2C:0C:5D:B8:CC:32:15:D3:0D:0A:D3:50:BD:13:B8:9F:87:DF:97:1C:15:13:84:80:68:83:AB:FA:44:E8
↵a=setup:actpass
↵a=mid:data
↵a=sendrecv
↵a=rtcp-mux
↵a=rtpmap:127 google-data/90000
↵a=ssrc:2123048988 cname:pRuKm8BiQ79bLvJg
↵a=ssrc:2123048988 msid:chatchannel chatchannel
↵a=ssrc:2123048988 mslabel:chatchannel
↵a=ssrc:2123048988 label:chatchannel
↵"
type
:
"offer"
__proto__
:
RTCSessionDescription
signalingState
:
"stable"
__proto__
:
RTCPeerConnection

我生命中最后14个小时的问题是Chrome和Firefox中的RTPDataChannels标志已经过时了。不要使用它。照顾好自己。现在一切都在轮子上。