ofwebrtc.htmljavascript
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>HTML5 GetUserMedia Demo</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" /> <script src='jquery-1.9.1.min.js'></script> <script src='strophe.min.js'></script> <script src='ofwebrtc.js'></script> </head> <body> <p id="info"></p> <p>----------------------------------------------------------------</p> JID:<input type="text" id="input-jid" value=""> <br> 密碼:<input type="password" id="input-pwd" value=""> <br> <button id="btn-login">登陸</button><br> <br> 目標JID: <input type="text" id="input-contacts" value="mytest1@pc-20170308pkrs"> <button id="btn-call">Call</button> <p>----------------------------------------------------------------</p> Local: <br> <video id="localVideo" autoplay></video><br> Remote: <br> <video id="remoteVideo" autoplay></video> </body> </html>
ofwebrtc.jshtml
// XMPP幫助類 // boshService: XMPP服務器BOSH地址 function XMPPHelper(boshService) { var _this = this; // XMPP服務器BOSH地址 _this.boshService = boshService; // XMPP鏈接 _this.connection = null; // 當前狀態是否鏈接 _this.connected = false; // 當前登陸的JID _this.jid = ""; // 收到消息後的業務回調方法 _this.messageCallback = null; _this.setMessageCallback = function (messageCallback) { _this.messageCallback = messageCallback; } // 接收到<message> var onMessage = function (msg) { console.log('--- msg ---', msg); // 解析出<message>的from、type屬性,以及body子元素 var from = msg.getAttribute('from'); var type = msg.getAttribute('type'); var elems = msg.getElementsByTagName('body'); var json = JSON.parse(HtmlUtil.htmlDecodeByRegExp(elems[0].innerHTML)); console.log('--- json ---', json); json.fromjid = from; if (type === 'chat') { _this.messageCallback(json); } return true; } // 鏈接狀態改變的事件 var onConnect = function (status) { console.log('status: ' + status) if (status == Strophe.Status.CONNFAIL) { $('#info').html("鏈接失敗!"); } else if (status == Strophe.Status.AUTHFAIL) { $('#info').html("登陸失敗!"); } else if (status == Strophe.Status.DISCONNECTED) { $('#info').html("鏈接斷開!"); _this.connected = false; } else if (status == Strophe.Status.CONNECTED) { $('#info').html("鏈接成功!"); _this.connected = true; // 當接收到<message>節,調用onMessage回調函數 _this.connection.addHandler(onMessage, null, 'message', null, null, null); // 首先要發送一個<presence>給服務器(initial presence) _this.connection.send($pres().tree()); } }; // 登陸 _this.login = function (jid, password) { _this.connection = new Strophe.Connection(_this.boshService); _this.connection.connect(jid, password, onConnect); _this.jid = jid; }; _this.sendMessage = function (tojid, type, data) { if (_this.connected === false) { alert("請先登陸!!!"); return; } var msg = $msg({ to: tojid, from: _this.jid, type: 'chat' }).c("body", null, JSON.stringify({ type: type, data: data })); _this.connection.send(msg.tree()); }; } // WebRTC幫助類 // xmppHelper:XMPP幫助實例 // localVideo:本地視頻顯示的DOM // remoteVideo:遠端視頻顯示的DOM function WebRTCHelper(xmppHelper, localVideo, remoteVideo) { var _this = this; // 對方用戶 _this.tojid = null; // 建立PeerConnection實例 (參數爲null則沒有iceserver,即便沒有stunserver和turnserver,仍可在局域網下通信) _this.pc = new webkitRTCPeerConnection(null); _this.hasBindLocalVideo = false; // 發送ICE候選到其餘客戶端 _this.pc.onicecandidate = function(event){ if (event.candidate !== null && _this.tojid !== null) { console.log('----------- onicecandidate ------------'); console.log('candidate', event.candidate); xmppHelper.sendMessage(_this.tojid, 'candidate', event.candidate); } }; // 若是檢測到媒體流鏈接到本地,將其綁定到一個video標籤上輸出 _this.pc.onaddstream = function(event){ console.log('----------- onaddstream ------------'); remoteVideo.src = URL.createObjectURL(event.stream); }; // 發送offer和answer的函數,發送本地session描述 var sendOfferFn = function(desc){ console.log('----------- sendOfferFn ------------'); console.log('desc', desc); _this.pc.setLocalDescription(desc); xmppHelper.sendMessage(_this.tojid, 'offer', desc); }; var sendAnswerFn = function(desc){ console.log('----------- sendAnswerFn ------------'); console.log('desc', desc); _this.pc.setLocalDescription(desc); xmppHelper.sendMessage(_this.tojid, 'answer', desc); }; var mediaConfig = { video: true }; // 綁定本地視頻流 var bindLocalVideo = function (callback) { if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { navigator.mediaDevices.getUserMedia(mediaConfig).then(function(stream) { //綁定本地媒體流到video標籤用於輸出 localVideo.src = window.URL.createObjectURL(stream); //向PeerConnection中加入須要發送的流 _this.pc.addStream(stream); callback(); }); } }; // 開始視頻通信 _this.start = function (tojid) { _this.tojid = tojid; if (_this.hasBindLocalVideo === false) { bindLocalVideo(function () { // 發送一個offer信令 _this.pc.createOffer(sendOfferFn, function (error) { console.log('Failure callback: ' + error); }); }); _this.hasBindLocalVideo = true; } else { // 發送一個offer信令 _this.pc.createOffer(sendOfferFn, function (error) { console.log('Failure callback: ' + error); }); } }; // 收到對方信息後的處理 _this.onMessage = function (json) { console.log('onMessage: ', json); console.log('json.data: ', json.data); if (_this.tojid === null) { _this.tojid = json.fromjid; } if (json.type === 'candidate') { _this.pc.addIceCandidate(new RTCIceCandidate(json.data)); } else { _this.pc.setRemoteDescription(new RTCSessionDescription(json.data)); if (json.type === 'offer') { if (_this.hasBindLocalVideo === false) { bindLocalVideo(function () { _this.pc.createAnswer(sendAnswerFn, function (error) { console.log('Failure callback: ' + error); }); }); _this.hasBindLocalVideo = true; } else { _this.pc.createAnswer(sendAnswerFn, function (error) { console.log('Failure callback: ' + error); }); } } } } } $(document).ready(function() { // 實例化XMPP和WebRTC幫助類 var xmppHelper = new XMPPHelper('http://localhost:7070/http-bind/'); var webRTCHelper = new WebRTCHelper(xmppHelper, document.getElementById('localVideo'), document.getElementById('remoteVideo')); // XMPP收到消息後轉給WebRTC xmppHelper.setMessageCallback(webRTCHelper.onMessage); $('#btn-login').click(function() { console.log('jid: ' + $("#input-jid").val()); console.log('pwd: ' + $("#input-pwd").val()); xmppHelper.login($("#input-jid").val(), $("#input-pwd").val()); }); $('#btn-call').click(function() { if($("#input-contacts").val() == '') { alert("請輸入目標用戶!"); return; } tojid = $("#input-contacts").val(); webRTCHelper.start(tojid); }); }); var HtmlUtil = { /*1.用瀏覽器內部轉換器實現html轉碼*/ htmlEncode:function (html){ //1.首先動態建立一個容器標籤元素,如DIV var temp = document.createElement ("div"); //2.而後將要轉換的字符串設置爲這個元素的innerText(ie支持)或者textContent(火狐,google支持) (temp.textContent != undefined ) ? (temp.textContent = html) : (temp.innerText = html); //3.最後返回這個元素的innerHTML,即獲得通過HTML編碼轉換的字符串了 var output = temp.innerHTML; temp = null; return output; }, /*2.用瀏覽器內部轉換器實現html解碼*/ htmlDecode:function (text){ //1.首先動態建立一個容器標籤元素,如DIV var temp = document.createElement("div"); //2.而後將要轉換的字符串設置爲這個元素的innerHTML(ie,火狐,google都支持) temp.innerHTML = text; //3.最後返回這個元素的innerText(ie支持)或者textContent(火狐,google支持),即獲得通過HTML解碼的字符串了。 var output = temp.innerText || temp.textContent; temp = null; return output; }, /*3.用正則表達式實現html轉碼*/ htmlEncodeByRegExp:function (str){ var s = ""; if(str.length == 0) return ""; s = str.replace(/&/g,"&"); s = s.replace(/</g,"<"); s = s.replace(/>/g,">"); s = s.replace(/ /g," "); s = s.replace(/\'/g,"'"); s = s.replace(/\"/g,"""); return s; }, /*4.用正則表達式實現html解碼*/ htmlDecodeByRegExp:function (str){ var s = ""; if(str.length == 0) return ""; s = str.replace(/&/g,"&"); s = s.replace(/</g,"<"); s = s.replace(/>/g,">"); s = s.replace(/ /g," "); s = s.replace(/'/g,"\'"); s = s.replace(/"/g,"\""); return s; } };
一、打開Chrome,訪問ofwebrtc.html頁面,輸入JID(如admin@pc-20170308pkrs)、密碼,點擊登陸,提示鏈接成功。java
二、再打開一個Chrome訪問ofwebrtc.html頁面,輸入JID(如mytest1@pc-20170308pkrs),密碼,點擊登陸,提示鏈接成功。jquery
以後在目標JID輸入上個頁面的JID(admin@pc-20170308pkrs)點擊Call,會提示使用攝像頭,選擇容許。web
三、上個頁面也會彈出使用攝像頭提示,點擊容許正則表達式
四、效果json
後續有時間繼續補充優化... 瀏覽器