WebRTC 学习笔记创建信令服务器和连接客户端

it2026-09-20  1

信令服务器

使用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>
最新回复(0)