OniceCandidate不会在第二台电脑上启动

我的webrtc聊天代码有问题。 我不能在同伴之间build立联系。 PC1通过信号服务器发送报价请求sucessfull,pc2添加候选人,但pc2不能发送候选人和答复pc1,为什么?

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

app.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]; }); }); 

index.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> 

index.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 PeerConnection日志:

 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 : "answer" __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标志已经过期。 不要使用它。 保重你自己。 现在一切正在进行。