我已经在节点 js 中实现了信号服务器并使用 googles stun 服务器
var http = require("http");
var fs = require("fs");
var websocket = require("websocket").server;
// general variables
var port = 1234;
var webrtc_clients = [];
var webrtc_discussions = {};
// web server functions
var http_server = http.createServer(function(request, response) {
/*var matches = undefined;
if (matches = request.url.match("^/images/(.*)")) {
var path = process.cwd()+"/images/"+matches[1];
fs.readFile(path, function(error, data) {
if (error) {
log_error(error);
} else {
response.end(data);
}
});
} else {
response.end(page);
}
*/
response.write(page);
response.end();
});
http_server.listen(port, function() {
log_comment("server listening (port "+port+")");
});
var page = undefined;
fs.readFile("index.html", function(error, data) {
if (error) {
log_error(error);
} else {
page = data;
}
});
// web socket functions
var websocket_server = new websocket({
httpServer: http_server
});
websocket_server.on("request", function(request) {
log_comment("new request ("+request.origin+")");
var connection = request.accept(null, request.origin);
log_comment("new connection ("+connection.remoteAddress+")");
webrtc_clients.push(connection);
connection.id = webrtc_clients.length-1;
connection.on("message", function(message) {
if (message.type === "utf8") {
log_comment("got message "+message.utf8Data);
var signal = undefined;
try { signal = JSON.parse(message.utf8Data); } catch(e) { };
if (signal) {
if (signal.type === "join" && signal.token !== undefined) {
try {
if (webrtc_discussions[signal.token] === undefined) {
webrtc_discussions[signal.token] = {};
}
} catch(e) { };
try {
webrtc_discussions[signal.token][connection.id] = true;
} catch(e) { };
} else if (signal.type !== undefined) {
try {
Object.keys(webrtc_discussions[signal.token]).forEach(function(id) {
if (id != connection.id) {
webrtc_clients[id].send(message.utf8Data, log_error);
}
});
} catch(e) { };
} else {
log_comment("invalid signal: "+message.utf8Data);
}
} else {
log_comment("invalid signal: "+message.utf8Data);
}
}
});
connection.on("close", function(connection) {
log_comment("connection closed ("+connection.remoteAddress+")");
Object.keys(webrtc_discussions).forEach(function(token) {
Object.keys(webrtc_discussions[token]).forEach(function(id) {
if (id === connection.id) {
delete webrtc_discussions[token][id];
}
});
});
});
});
// utility functions
function log_error(error) {
if (error !== "Connection closed" && error !== undefined) {
log_comment("ERROR: "+error);
}
}
function log_comment(comment) {
console.log((new Date())+" "+comment);
}
上面是 server.js 文件,下面是 index.html
<html>
<head>
<script>
var webrtc_capable = true;
var rtc_peer_connection = null;
var rtc_session_description = null;
var get_user_media = null;
var connect_stream_to_src = null;
var stun_server = "stun.l.google.com:19302";
// initializing variables
if (navigator.getUserMedia) { // WebRTC 1.0 standard compliant browser
rtc_peer_connection = RTCPeerConnection;
rtc_session_description = RTCSessionDescription;
get_user_media = navigator.getUserMedia.bind(navigator);
connect_stream_to_src = function(media_stream, media_element) {
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=21606
media_element.srcObject = media_stream;
media_element.play();
};
} else if (navigator.mozGetUserMedia) { // early firefox webrtc implementation
rtc_peer_connection = mozRTCPeerConnection;
rtc_session_description = mozRTCSessionDescription;
get_user_media = navigator.mozGetUserMedia.bind(navigator);
connect_stream_to_src = function(media_stream, media_element) {
media_element.mozSrcObject = media_stream;
media_element.play();
};
stun_server = "74.125.31.127:19302";
} else if (navigator.webkitGetUserMedia) { // early webkit webrtc implementation
rtc_peer_connection = webkitRTCPeerConnection;
rtc_session_description = RTCSessionDescription;
get_user_media = navigator.webkitGetUserMedia.bind(navigator);
connect_stream_to_src = function(media_stream, media_element) {
media_element.src = webkitURL.createObjectURL(media_stream);
};
} else {
alert("This browser does not support WebRTC - visit WebRTC.org for more info");
webrtc_capable = false;
}
var call_token;
var signaling_server;
var peer_conn;
function start() {
peer_conn = new rtc_peer_connection({ "iceServers": [ { "url": "stun:"+stun_server },]});
signaling_server = new WebSocket("ws://192.168.1.5:1234");
peer_conn.onicecandidate = function(ice_event){
if (ice_event.candidate) {
signaling_server.send(JSON.stringify({type:"new_ice_candidate",candidate:ice_event.candidate}));
}
};
peer_conn.onaddstream = function (event){
connect_stream_to_src(event.stream,document.getElementById("remotevideo"));
};
get_user_media(
{"audio":true,
"video":true},function (stream){
connect_stream_to_src(stream,document.getElementById("localvideo"));
peer_conn.addStream(stream);
},log_error);
function new_description_created(description){
peer_conn.setLocalDescription(description,function (){
signaling_server.send(JSON.stringify({token:call_token,type:"new_description",sdp:description}));},log_error);
}
function caller_signal_handler(event){
var signal = JSON.parse(event.data);
if (signal.type === "callee_arrived") {
peer_conn.createOffer(new_description_created,log_error);
}else if (signal.type === "new_ice_candidate") {
peer_conn.addIceCandidate(new RTCIceCandidate(signal.candidate));
}else if (signal.type === "new_description") {
peer_conn.setRemoteDescription(new rtc_session_description(signal.sdp,function (){
if (peer_conn.remoteDescription.type === "answer") {
//code
}},log_error));
}
}
function callee_signal_handler(event) {
var signal = JSON.parse(event.data);
if (signal.type === "new_ice_candidate") {
peer_conn.addIceCandidate(new RTCIceCandidate(signal.candidate));
}else if (signal.type === "new_description") {
peer_conn.setRemoteDescription(new rtc_session_description(signal.sdp), function (){
if (peer_conn.remoteDescription.type == "offer") {
peer_conn.createAnswer(new_description_created,log_error);
}},log_error);
}
}
if (document.location.hash === "" || document.location.hash === undefined) {
var token = Date.now()+"-"+Math.random(Math.random * 10000);
call_token = "#"+token;
document.location.hash = token;
signaling_server.onopen = function (){
signaling_server.onmessage = caller_signal_handler;
signaling_server.send(JSON.stringify({token:call_token,type:"join"}));
};
document.title = "you are the caller";
}else {
call_token = document.location.hash;
signaling_server.onopen = function (){
signaling_server.onmessage = callee_signal_handler;
signaling_server.send(JSON.stringify({token:call_token,type:"join"}));
signaling_server.send(JSON.stringify({token:call_token,type:"callee_arrived"}));
};
document.title = "you are the callee";
}
function log_error(error) {
console.log(error);
}
};
</script>
<style>
#remotevideo{
height: 100%;
width: 100%;
}
#localvideo{
height: 25%;
width: 25%;
position: absolute;
left: 60%;
top: 60%;
}
</style>
</head>
<body onload="start()">
<video autoplay="true" id="remotevideo"></video>
<video autoplay="true" id="localvideo"></video>
</body>
</html>
我不明白,当被叫方连接时,远程视频不显示,但是当第三个被叫方连接到其他浏览器时,它甚至没有连接到呼叫