信令服务器
使用node.js作为服务器
var WebSocketServer = require("ws").Server,
wss = new WebSocketServer({port:8888}),
/*存储所有的连接用户*/
users = {};
/*监听客户端发起的连接*/
wss.on("connection",function (connection) {
console.log("User connected");
/*监听客户端的消息*/
connection.on("message",function (message) {
var data;
/*保证只接受JSON格式的消息*/
try{
data = JSON.parse(message);
}catch (e) {
console.log("Error parsing JSON");
data = {};
}
switch (data.type) {
case "login":
console.log("User logged in as ",data.name);
if (users[data.name]){
sendTo(connection,
{
type:"login",
success:false
})
}else {
users[data.name] = connection;
connection.name = data.name;
sendTo(connection,
{
type:"login",
success:true
});
}
break;
case "offer":
/*data.name为客户端想要把offer发送给的人*/
console.log("Sending offer to",data.name);
/*conn为offer发往的人.connection为发送offer的人*/
var conn = users[data.name];
if (conn != null){
connection.otherName = data.name;
sendTo(conn,{
type:"offer",
offer:data.offer,
name:connection.name
});
}
break;
case "answer":
console.log("Sending answer to ",data.name);
var conn = users[data.name];
if (conn != null){
connection.otherName = data.name;
sendTo(conn,{
type:"answer",
answer:data.answer
});
}
break;
case "candidate":
console.log("have a candidate from ",connection.name);
console.log("Sending candidate to ",data.name);
var conn = users[data.name];
if (conn != null){
sendTo(conn,{
type: "candidate",
candidate: data.candidate
});
}
break;
case "leave":
console.log("Disconnecting user from ",data.name);
var conn = users[data.name];
conn.otherName = null;
if (conn != null){
sendTo(conn,{type:"leave"});
}
break;
default:
sendTo(connection,
{
type:"error",
message:"Unrecognized command:" + data.type
});
break;
}
});
connection.on("close",function () {
if (connection.name){
delete users[connection.name];
if (connection.otherName){
console.log("Disconnecting user from ",connection.otherName);
var conn = users[connection.otherName];
conn.otherName = null;
if (conn != null){
sendTo(conn,{type:"leave"});
}
}
}
})
});
wss.on("listening",function () {
console.log("Server start...");
})
function sendTo(conn,message) {
conn.send(JSON.stringify(message));
}
客户端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>web_rtc_3</title>
<style>
body{
background-color: #3D6DF2;
margin-top: 15px;
font-family: sans-serif;
color: white;
}
video{
background-color: black;
border: 1px solid gray;
}
.page{
position: relative;
display: block;
margin: 0 auto;
width: 500px;
height: 500px;
}
#yours{
width: 150px;
height: 150px;
position: absolute;
top: 15px;
right: 15px;
}
#theirs{
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<div id="login-page" class="page">
<h2>Login As</h2>
<input type="text" id="username">
<button id="login">Login</button>
</div>
<div id="call-page" class="page">
<video id="yours" autoplay></video>
<video id="theirs" autoplay></video>
<input type="text" id="their-username">
<button id="call">Call</button>
<button id="hang-up">Hang Up</button>
</div>
<script>
/*name:本用户的名称,connectedUser:要连接的用户的名称*/
var name,connectedUser;
/*与服务器进行连接*/
var connection = new WebSocket('ws://localhost:8888');
var loginPage = document.querySelector('#login-page'),
usernameInput = document.querySelector('#username'),
loginButton = document.querySelector('#login'),
callPage = document.querySelector('#call-page'),
theirUsernameInput = document.querySelector('#their-username'),
callButton = document.querySelector('#call'),
hangUPButton = document.querySelector('#hang-up');
var yourVideo = document.querySelector('#yours'),
theirVideo = document.querySelector('#theirs'),
/*yourConnection:当前页面的RTCPeerConnection*/
yourConnection,stream;
callPage.style.display = "none";
/*与服务器进行连接后的函数*/
connection.onopen = function () {
console.log("Connected");
};
/*从服务器返回数据的函数*/
connection.onmessage = function (message) {
console.log("Got message",message.data);
var data = JSON.parse(message.data);
switch (data.type) {
case "login":
onLogin(data.success);
break;
case "offer":
onOffer(data.offer,data.name);
break;
case "answer":
onAnswer(data.answer);
break;
case "candidate":
onCandidate(data.candidate);
break;
case "leave":
onLeave();
break;
default:
break ;
}
};
/*从服务器发生错误的函数*/
connection.onerror = function (error) {
console.log("Got error",error);
};
/*单击登陆按钮,向服务器发送login类型数据*/
loginButton.addEventListener("click",function (event) {
name = usernameInput.value;
if (name.length > 0){
send({
type:"login",
name:name
});
}
});
/*触发onLogin函数*/
function onLogin(success) {
if (success === false){
alert("Login unsuccessful, please try a different name.");
}else {
loginPage.style.display = "none";
callPage.style.display = "block";
startConnection();
}
};
function startConnection() {
if (hasUserMedia()){
navigator.getUserMedia(
{video:true,audio:false},
function (myStream) {
stream = myStream;
/*将自己的摄像头在自己的部分显示*/
yourVideo.srcObject = stream;
if (hasRTCPeerConnection()){
setupPeerConnection(stream);
}else {
alert("Sorry, your browser does not support WebRTC.");
}
},
function (error) {
console.log(error)
}
);
}else {
alert("Sorry, your browser does not support WebRTC.");
}
};
function setupPeerConnection(stream) {
var configuration = {};
/*创建RTCPeerConnection*/
yourConnection = new RTCPeerConnection(configuration);
yourConnection.addStream(stream);
/*由setRemoteDescription触发*/
yourConnection.onaddstream = function (e) {
theirVideo.srcObject = e.stream;
};
yourConnection.onicecandidate = function (event) {
if (event.candidate){
send({
type: "candidate",
candidate: event.candidate
});
}
};
};
/*开始于另一个用户连接*/
callButton.addEventListener("click",function () {
var theirUsername = theirUsernameInput.value;
if (theirUsername.length > 0){
startPeerConnection(theirUsername);
}
});
/*向另一个端发送offer*/
function startPeerConnection(user){
connectedUser = user;
/*开始创建offer*/
yourConnection.createOffer().then(function (offer) {
send({
type:"offer",
offer:offer
});
yourConnection.setLocalDescription(offer);
},function (error) {
alert("An error has occurred while create offer.");
});
};
/*收到另一端的offer,返回一个answer*/
function onOffer(offer,name) {
connectedUser = name;
yourConnection.setRemoteDescription(new RTCSessionDescription(offer));
yourConnection.createAnswer().then(function (answer) {
yourConnection.setLocalDescription(answer);
send({
type: "answer",
answer: answer
});
},function (error) {
alert("An error has occurred while create answer.");
})
};
/*收到answer*/
function onAnswer(answer) {
yourConnection.setRemoteDescription(new RTCSessionDescription(answer));
};
hangUPButton.addEventListener("click",function () {
send({
type:"leave"
});
onLeave();
});
function onLeave() {
connectedUser =null;
theirVideo.srcObject = null;
yourConnection.close();
yourConnection.onicecandidate = null;
yourConnection.onaddstream = null;
setupPeerConnection(stream);
};
function send(message) {
if (connectedUser){
message.name = connectedUser;
}
connection.send(JSON.stringify(message));
};
function onCandidate(candidate) {
yourConnection.addIceCandidate(new RTCIceCandidate(candidate));
};
function hasUserMedia() {
return !!navigator.getUserMedia;
};
function hasRTCPeerConnection() {
return !!window.RTCPeerConnection;
}
</script>
</body>
</html>