這篇文章主要參考了 Webrtc WebSocket實現音視頻通信,很是感謝提供代碼javascript
前端部分徹底是從這篇文章複製過來的,只是修改了webscket的url,還有加入了webrtc-adapterjs ,至於作什麼,能夠點擊連接進行了解html
前端代碼部分(主要來自開頭說起的博文)前端
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> Welcome<br/><input id="text" type="text" /> <button onclick="send()">發送消息</button> <hr/> <button onclick="closeWebSocket()">關閉WebSocket鏈接</button> <hr/> <div id="message"></div> <video id="vid1" width="320" height="240" autoplay></video> <video id="vid2" width="320" height="240" autoplay></video><br> <a id="create" href="webrtc.html#true" onclick="init()">點擊此連接新建聊天室</a><br> <p id="tips" style="background-color:red">請在其餘瀏覽器中打開:http://此電腦 加入此視頻聊天</p> <script type="text/javascript" src="http://cdn.staticfile.org/webrtc-adapter/zv4.1.1/adapter.min.js"></script> <script type="text/javascript"> navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; var isCaller = window.location.href.split('#')[1]; var websocket = null; //判斷當前瀏覽器是否支持WebSocket if('WebSocket' in window) { websocket = new WebSocket("ws://192.168.31.175:8181"); } else { alert('當前瀏覽器 Not support websocket') } //鏈接發生錯誤的回調方法 websocket.onerror = function() { setMessageInnerHTML("WebSocket鏈接發生錯誤"); }; //鏈接成功創建的回調方法 websocket.onopen = function() { setMessageInnerHTML("WebSocket鏈接成功"); } // 建立PeerConnection實例 (參數爲null則沒有iceserver,即便沒有stunserver和turnserver,仍可在局域網下通信) var pc = new window.RTCPeerConnection(null); // 發送ICE候選到其餘客戶端 pc.onicecandidate = function(event) { setMessageInnerHTML("我看看 1"); if(event.candidate !== null) { setMessageInnerHTML("我看看 2"); websocket.send(JSON.stringify({ "event": "_ice_candidate", "data": { "candidate": event.candidate } })); } }; //接收到消息的回調方法 websocket.onmessage = function(event) { setMessageInnerHTML("接收到的信息"); setMessageInnerHTML(event.data); if(event.data == "new user") { console.log("new user"); location.reload(); } else { var json = JSON.parse(event.data); console.log('onmessage: ', json); //若是是一個ICE的候選,則將其加入到PeerConnection中,不然設定對方的session描述爲傳遞過來的描述 if(json.event === "_ice_candidate") { pc.addIceCandidate(new RTCIceCandidate(json.data.candidate)); } else { pc.setRemoteDescription(new RTCSessionDescription(json.data.sdp)); // 若是是一個offer,那麼須要回覆一個answer if(json.event === "_offer") { pc.createAnswer(sendAnswerFn, function(error) { console.log('Failure callback: ' + error); }); } } } } //鏈接關閉的回調方法 websocket.onclose = function() { setMessageInnerHTML("WebSocket鏈接關閉"); } //監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket鏈接,防止鏈接還沒斷開就關閉窗口,server端會拋異常。 window.onbeforeunload = function() { closeWebSocket(); } //將消息顯示在網頁上 function setMessageInnerHTML(innerHTML) { document.getElementById('message').innerHTML += innerHTML + '<br/>'; } //關閉WebSocket鏈接 function closeWebSocket() { websocket.close(); } //發送消息 function send() { var message = document.getElementById('text').value; websocket.send(message); } // stun和turn服務器 var iceServer = { "iceServers": [{ "url": "stun:stunserver.org" }, { "url": "turn:numb.viagenie.ca", "username": "webrtc@live.com", "credential": "muazkh" }] }; // 若是檢測到媒體流鏈接到本地,將其綁定到一個video標籤上輸出 pc.onaddstream = function(event) { document.getElementById('vid2').src = URL.createObjectURL(event.stream); }; // 發送offer和answer的函數,發送本地session描述 var sendOfferFn = function(desc) { pc.setLocalDescription(desc); websocket.send(JSON.stringify({ "event": "_offer", "data": { "sdp": desc } })); }, sendAnswerFn = function(desc) { pc.setLocalDescription(desc); websocket.send(JSON.stringify({ "event": "_answer", "data": { "sdp": desc } })); }; // 獲取本地音頻和視頻流 navigator.getUserMedia({ "audio": true, "video": true }, function(stream) { //綁定本地媒體流到video標籤用於輸出 document.getElementById('vid1').src = URL.createObjectURL(stream); document.getElementById('vid1').muted = true; //向PeerConnection中加入須要發送的流 pc.addStream(stream); //若是是發起方則發送一個offer信令 if(isCaller) { pc.createOffer(sendOfferFn, function(error) { console.log('Failure callback: ' + error); }); } }, function(error) { //處理媒體流建立失敗錯誤 console.log('getUserMedia error: ' + error); }); window.onload = function() { if(isCaller == null || isCaller == undefined) { var tips = document.getElementById("tips"); tips.remove(); } else { var create = document.getElementById("create"); create.remove(); } }; function init() { location.reload(); } </script> </body> </html>
說起博文的java部分,我用了.net 控制檯程序簡單實現了一個,至關於一個極簡的信令服務器吧(Fleck 能夠在vs的管理nuget程序包中得到)java
static void Main(string[] args) { //客戶端url以及其對應的Socket對象字典 IDictionary<string, IWebSocketConnection> dic_Sockets = new Dictionary<string, IWebSocketConnection>(); var server = new WebSocketServer("ws://192.168.31.175:8181"); //出錯後重啓 server.RestartAfterListenError = true; server.Start(socket => { socket.OnOpen = () => { //獲取客戶端網頁的url string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort; dic_Sockets.Add(clientUrl, socket); Console.WriteLine(DateTime.Now.ToString() + "|服務器:和客戶端網頁:" + clientUrl + " 創建WebSock鏈接!"); }; socket.OnClose = () => //鏈接關閉事件 { string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort; //若是存在這個客戶端,那麼對這個socket進行移除 if (dic_Sockets.ContainsKey(clientUrl)) { //注:Fleck中有釋放 //關閉對象鏈接 //if (dic_Sockets[clientUrl] != null) //{ //dic_Sockets[clientUrl].Close(); //} dic_Sockets.Remove(clientUrl); } Console.WriteLine(DateTime.Now.ToString() + "|服務器:和客戶端網頁:" + clientUrl + " 斷開WebSock鏈接!"); }; socket.OnMessage = message => //接受客戶端網頁消息事件 { string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort; foreach (var item in dic_Sockets.Where(a=>a.Key!=clientUrl)) { item.Value.Send(message); } //Console.WriteLine(DateTime.Now.ToString() + "|服務器:【收到】來客戶端網頁:" + clientUrl + "的信息:\n" + message); }; socket.OnBinary = b => { }; }); Console.ReadKey(); }
記錄完畢,這個東西僅僅只是個demo,能夠拿來玩一下web