Javascript WebRTC iceConnectionState仍处于';检查';状态
我想创建一个简单的视频聊天应用程序。我在Node.js中使用WebRTC和WebSocket。我想连接同一网络中的两个设备,但iceConnectionState始终处于“检查”状态。有什么问题吗 编辑 server.jsJavascript WebRTC iceConnectionState仍处于';检查';状态,javascript,html,websocket,webrtc,stun,Javascript,Html,Websocket,Webrtc,Stun,我想创建一个简单的视频聊天应用程序。我在Node.js中使用WebRTC和WebSocket。我想连接同一网络中的两个设备,但iceConnectionState始终处于“检查”状态。有什么问题吗 编辑 server.js //var uuid = require('uuid'); var fs = require('fs'); var webSocketServer = require('websocket').server; var cfg = { ssl: false,
//var uuid = require('uuid');
var fs = require('fs');
var webSocketServer = require('websocket').server;
var cfg = {
ssl: false,
port: 15555,
ssl_key: '/etc/apache2/ssl/apache.key',
ssl_cert: '/etc/apache2/ssl/apache.crt'
};
var httpServer = (cfg.ssl) ? require('https') : require('http');
var server = null;
if(cfg.ssl) {
server = httpServer.createServer(
{
key: fs.readFileSync(cfg.ssl_key),
cert: fs.readFileSync(cfg.ssl_cert)
}, function() {} ).listen(cfg.port);
} else {
server = httpServer.createServer().listen(cfg.port);
}
var wsServer = new webSocketServer({
httpServer: server
});
rooms = {};
// this is executed each time the websocket
// server receives an request
wsServer.on('request', function(request) {
// allow all incoming connections
var connection = request.accept(null, request.origin);
// here we read the incoming messages and try to parse them to JSON
connection.on('message', function(message) {
// try to parse JSON
try {
var data = JSON.parse(message.utf8Data);
} catch (e) {
console.log('This does not look like valid JSON');
}
// if JSON is valid process the request
if (data !== undefined && data.type !== undefined) {
switch (data.type) {
case 'createRoom':
var roomName = data.roomName;
console.log('CREATE_ROOM request received');
rooms[roomName] = {
creatorConnection: connection,
partnerConnection: false,
}
var data = {
type: 'roomCreated',
payload: roomName
};
return send(rooms[roomName].creatorConnection, data);
break;
case 'offer':
console.log('OFFER received from client');
if (rooms[data.roomName].partnerConnection) {
// send error to user
var data = {
type: 'error',
payload: 'room is already full'
};
return send(connection, data);
}
rooms[data.roomName].partnerConnection = this;
console.log('OFFER send to host');
return send(rooms[data.roomName].creatorConnection, data);
break;
// send to other guy
default:
if (this === rooms[data.roomName].partnerConnection) {
console.log('send to creator : ' + data.type);
return send(rooms[data.roomName].creatorConnection, data);
}
console.log('send to parther : ' + data.type);
return send(rooms[data.roomName].partnerConnection, data);
break;
}
}
// if JSON is invalid or type is missing send error
else {
var data = {
type: 'error',
payload: 'ERROR FROM SERVER: Incorrect data or no data received'
};
send(connection, data);
}
});
// this function sends data to the other user
var send = function(connection, data) {
try {
connection.sendUTF(JSON.stringify(data));
} catch (e) {
console.log('\n\n!!!### ERROR while sending message ###!!!\n');
console.log(e + '\n');
return;
}
};
});
client.js
function WebRTC() {
var wsServer = false;
var localStream = false;
var remoteStream = false;
var peerConnection = false;
var roomName = null;
var otherSDP = false;
var othersCandidates = []; // other guy's icecandidates
var socketEvent = document.createEvent('Event');
socketEvent.initEvent('socketEvent', true, true);
var mediaConstraints = {
audio: true,
video: true
};
var peerConnectionConfig = {
iceServers: [
{url : 'stun:stun.l.google.com:19302'},
{url : 'stun:stun.anyfirewall.com:3478'},
{url : 'turn:turn.bistri.com:80',
credential: 'homeo',
username: 'homeo'},
{url : 'turn:turn.anyfirewall.com:443?transport=tcp',
credential: 'webrtc',
username: 'webrtc'}
]
};
var offerAnswerConstraints = { mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
}};
var sendToServer = function(data) {
try {
wsServer.send(JSON.stringify(data));
return true;
} catch (e) {
logError(e);
return false;
}
};
var createRTCIceCandidate = function(candidate) {
var iceCandidate;
debug(candidate);
debug(JSON.parse(candidate));
if (typeof(webkitRTCIceCandidate) === 'function') {
iceCandidate = new webkitRTCIceCandidate(candidate);
} if (typeof(mozRTCIceCandidate) === 'function') {
iceCandidate = new mozRTCIceCandidate((candidate));
} else if (typeof(RTCIceCandidate) === 'function') {
iceCandidate = new RTCIceCandidate(candidate);
}
return iceCandidate;
};
var createRTCSessionDescription = function(description) {
var newSdp;
if (typeof(RTCSessionDescription) === 'function') {
newSdp = new RTCSessionDescription(description);
} else if (typeof(webkitRTCSessionDescription) === 'function') {
newSdp = new webkitRTCSessionDescription(description);
} else if (typeof(mozRTCSessionDescription) === 'function') {
newSdp = new mozRTCSessionDescription(description);
}
return newSdp;
};
var getRTCPeerConnection = function(stream) {
var peerConnection = null;
if (typeof(RTCPeerConnection) === 'function') {
peerConnection = new RTCPeerConnection(peerConnectionConfig);
} else if (typeof(webkitRTCPeerConnection) === 'function') {
peerConnection = new webkitRTCPeerConnection(peerConnectionConfig);
} else if (typeof(mozRTCPeerConnection) === 'function') {
peerConnection = new mozRTCPeerConnection(peerConnectionConfig);
}
debug("Creating new RTCPeerConnection");
peerConnection.addStream(stream);
peerConnection.onaddstream = function(e) {
debug("Remote stream received");
remoteStream = e.stream;
socketEvent.eventType = 'streamAdded';
document.dispatchEvent(socketEvent);
};
peerConnection.onicecandidate = function(event) {
debug("Retrieving ICE data status changed : " + event.target.iceGatheringState)
var data = {
type: 'iceCandidate',
roomName: roomName,
payload: event
};
sendToServer(data);
};
peerConnection.oniceconnectionstatechange = function(event) {
debug("ICE connection status changed : " + event.target.iceConnectionState)
};
return peerConnection;
};
var setIceCandidates = function(iceCandidate) {
// push icecandidate to array if no SDP of other guys is available
if (!otherSDP) {
othersCandidates.push(iceCandidate);
}
// add icecandidates immediately if not Firefox & if remoteDescription is set
if (otherSDP && iceCandidate.candidate && iceCandidate.candidate !== null) {
peerConnection.addIceCandidate(createRTCIceCandidate(iceCandidate.candidate));
}
};
var handshakeDone = function() {
console.log('handshakeDone');
peerConnection.setRemoteDescription(createRTCSessionDescription(otherSDP), function() {
// add other guy's ice-candidates to connection
for (var i = 0; i < othersCandidates.length; i++) {
if (othersCandidates[i].candidate) {
peerConnection.addIceCandidate(ceateRTCIceCandidate(othersCandidates[i].candidate));
}
}
// fire event
socketEvent.eventType = 'p2pConnectionReady';
document.dispatchEvent(socketEvent);
}, logError);
};
var createOffer = function() {
peerConnection = getRTCPeerConnection(localStream);
debug('Offer creating');
peerConnection.createOffer(function(description) {
debug('Offer created');
debug('Local description setting');
peerConnection.setLocalDescription(description, function() {
debug('Local description set');
var data = {
type: 'offer',
roomName: roomName,
payload: description
};
sendToServer(data);
}, logError);
}, logError);
};
var createAnswer = function() {
peerConnection = getRTCPeerConnection(localStream);
debug('Offer answering');
debug('Remote description setting');
peerConnection.setRemoteDescription(createRTCSessionDescription(otherSDP), function () {
debug('Remote description set');
debug('Answer creating');
peerConnection.createAnswer(function(description) {
debug('Answer created');
debug('Local description setting');
peerConnection.setLocalDescription(description, function() {
debug('Local description set');
for (var i = 0; i < othersCandidates.length; i++) {
if (othersCandidates[i].candidate) {
peerConnection.addIceCandidate(ceateRTCIceCandidate(othersCandidates[i].candidate));
}
}
// send SDP to other guy
var data = {
type: 'answer',
roomName: roomName,
payload: description
};
sendToServer(data);
}, logError);
}, logError);
}, logError);
};
this.connectToSocket = function(wsUrl) {
wsServer = new WebSocket(wsUrl);
wsServer.onopen = function(event) {
console.log((new Date()) + ' Connection successfully established');
};
wsServer.onerror = function(e) {
console.log((new Date()) + ' WebSocket connection error: ');
logError(e);
};
wsServer.onclose = function(event) {
console.log((new Date()) + ' Connection was closed');
logError(e);
};
wsServer.onmessage = function(message) {
try {
var data = JSON.parse(message.data);
} catch (e) {
logError(e);
return;
}
switch (data.type) {
case 'roomCreated':
roomName = data.payload;
socketEvent.eventType = 'roomCreated';
document.dispatchEvent(socketEvent);
break;
case 'offer':
otherSDP = data.payload;
createAnswer();
break;
case 'answer':
otherSDP = data.payload;
handshakeDone();
break;
case 'iceCandidate':
setIceCandidates(data.payload);
break;
}
};
};
this.getRoomName = function() {
return roomName;
};
this.createRoom = function(roomName) {
var media = getMedia();
var onSuccess = function(stream) {
localVideo.attr('src', URL.createObjectURL(stream));
localStream = stream;
var data = {
type: 'createRoom',
roomName: roomName,
payload: false
};
return sendToServer(data)
};
media(mediaConstraints, onSuccess, logError);
};
this.joinRoom = function(rName) {
var media = getMedia();
var onSuccess = function(stream) {
localVideo.attr('src', URL.createObjectURL(stream));
localStream = stream;
//TODO
roomName = rName;
createOffer();
};
media(mediaConstraints, onSuccess, logError);
};
var getMedia = function() {
var media = null;
if (navigator.getUserMedia) {;
media = navigator.getUserMedia.bind(navigator);
} else if (navigator.webkitGetUserMedia) {
media = navigator.webkitGetUserMedia.bind(navigator);
} else if (navigator.mozGetUserMedia) {
media = navigator.mozGetUserMedia.bind(navigator);
}
return media;
};
// get the other guys media stream
this.getRemoteStream = function() {
return remoteStream;
};
}
common.js
function debug(message) {
console.log(message);
}
function logError(e) {
console.error(e);
}
index.html
<!doctype html>
<html>
<head>
<title>WebRTC</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<link href="css/bootstrap.css" rel="stylesheet">
</head>
<body style="padding: 5em;">
<section id="loginSection">
<div class="row" style="margin-bottom: 2em;">
<div clsss="col-xs-12">
<button id="createRoomButton" type="button" class="btn btn-default btn-lg center-block">
Create room
</button>
</div>
</div>
<div class="row" style="margin-bottom: 4em;">
<div clsss="col-xs-12">
<button id="joinRoomButton" type="button" class="btn btn-default btn-lg center-block">
Join room
</button>
</div>
</div>
<div class="row">
<div clsss="col-xs-4">
<input id="roomNameInput" type="text" style="width: 200px;" class="form-control center-block"
placeholder="Room's name" aria-describedby="basic-addon2">
</div>
</div>
</section>
<section id="roomSection" style="display: none;">
<h3>
Room's name:
<span id="roomNameField" style="font-weight: bold;"></span>
</h3>
<div class="video-wrapper">
<video id="remoteVideo" autoplay="true"></video>
<video id="localVideo" autoplay="true" muted="true" width="200" height="200"></video>
</div>
</section>
<script src="js/jquery-2.1.4.js" type="text/javascript"></script>
<script src="js/bootstrap.js" type="text/javascript"></script>
<script src="js/common.js" type="text/javascript"></script>
<script src="js/client.js" type="text/javascript"></script>
<script src="js/main.js" type="text/javascript"></script>
</body>
</html>
WebRTC
创造空间
会客室
房间名称:
对于Mozilla vs.Chrome,您可能仍然需要对此进行填充,但问题似乎是您试图通过WebSocket发送RTICeCandidateEvent
,而不仅仅是RTICeCandidate
,而且它没有通过套接字
我试过这个:
peerConnection.onicecandidate = function(event) {
debug("Retrieving ICE data status changed : " + event.target.iceGatheringState)
console.log(event);
console.log(event.candidate);
if(event.candidate) {
var data = {
type: 'iceCandidate',
roomName: roomName,
payload: event.candidate
};
sendToServer(data);
}
};
然后在您的wsServer.onmessage
将其传递给setIceCandidates
后,将其添加到另一端(但正如我所说,您可能需要为Firefox填充):
我建议在peerConnection.onicecandidate
中过滤掉发送方端的未定义的候选ICE
,而不是在接收端的设置候选ICE
中。另外,我认为您不需要将ICE候选
存储在othersCandidates
数组中,然后再添加它们。在我的版本中,我从来没有这样做过。iceCandidate
的东西似乎自动化程度很好,不需要额外的帮助。(如果你知道这样做的好处,请告诉我。)
另一方面,使用debug
函数来执行console.log()
,会更紧凑一些,但它会替换提供错误源的行号 html在哪里?我愿意测试和调试WebRTC的东西,但我不想在开始之前编写html以适应您的JavaScript。(特别是如果你已经写了!)我添加了html并编辑了其他文件。它只适用于Firefox 28和Android版谷歌Chrome的本地网络。我还有一个问题。我想在一个房间里为许多用户实现视频聊天。我有两个选择:星形拓扑和网状拓扑。在我看来,网格拓扑是最容易实现的,但是对于一个房间中的许多用户来说,它可能太慢了。我更喜欢星型拓扑。我正在寻找库/框架,帮助我实现代理服务器,在用户之间传输数据。我发现了licode
,但我认为这是一个高层次的框架,因为我为我的工程论文创建了这个应用程序,这并不容易……对不起,我对这两个方面都没有任何经验。
peerConnection.onicecandidate = function(event) {
debug("Retrieving ICE data status changed : " + event.target.iceGatheringState)
console.log(event);
console.log(event.candidate);
if(event.candidate) {
var data = {
type: 'iceCandidate',
roomName: roomName,
payload: event.candidate
};
sendToServer(data);
}
};
var setIceCandidates = function(iceCandidate) {
peerConnection.addIceCandidate(new RTCIceCandidate(iceCandidate));
};