html:html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>webrtc</title> <style> #yours{ width:300px; position:absolute; top:200px; left:100px; } #theirs{ width:300px; position:absolute; top:200px; left:400px; } </style> </head> <body> <button onclick="createOffer()">創建鏈接</button> <video id="yours" autoplay></video> <video id="theirs" autoplay></video> </body> <script src="./lib/jquery.min.js"></script> <script src="./lib/webrtc.js"></script> </html>
webrtc.jsjquery
1 var websocket; 2 3 function randomNum(minNum,maxNum){ 4 switch(arguments.length){ 5 case 1: 6 return parseInt(Math.random()*minNum+1,10); 7 break; 8 case 2: 9 return parseInt(Math.random()*(maxNum-minNum+1)+minNum,10); 10 break; 11 default: 12 return 0; 13 break; 14 } 15 } 16 const userid = 'user' + randomNum(0,100000); 17 18 function hasUserMedia() { 19 navigator.getUserMedia = navigator.getUserMedia || navigator.msGetUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; 20 return !!navigator.getUserMedia; 21 } 22 function hasRTCPeerConnection() { 23 window.RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection || window.msRTCPeerConnection; 24 return !!window.RTCPeerConnection; 25 } 26 27 var yourVideo = document.getElementById("yours"); 28 var theirVideo = document.getElementById("theirs"); 29 var Connection; 30 31 32 function startPeerConnection() { 33 //return; 34 var config = { 35 'iceServers': [ 36 //{ 'urls': 'stun:stun.xten.com:3478' }, 37 //{ 'urls': 'stun:stun.voxgratia.org:3478' }, 38 { 'url': 'stun:stun.l.google.com:19302' } 39 ] 40 }; 41 config = { 42 iceServers: [ 43 { urls: 'stun:stun.l.google.com:19302' }, 44 { urls: 'stun:global.stun.twilio.com:3478?transport=udp' } 45 ], 46 //sdpSemantics: 'unified-plan' 47 }; 48 // { 49 // "iceServers": [{ 50 // "url": "stun:stun.1.google.com:19302" 51 // }] 52 // }; 53 Connection = new RTCPeerConnection(config); 54 Connection.onicecandidate = function(e) { 55 console.log('onicecandidate'); 56 if (e.candidate) { 57 websocket.send(JSON.stringify({ 58 "userid":userid, 59 "event": "_ice_candidate", 60 "data": { 61 "candidate": e.candidate 62 } 63 })); 64 } 65 } 66 Connection.onaddstream = function(e) { 67 console.log('onaddstream'); 68 69 //theirVideo.src = window.URL.createObjectURL(e.stream); 70 theirVideo.srcObject = e.stream; 71 } 72 } 73 74 75 createSocket(); 76 startPeerConnection(); 77 78 if (hasUserMedia()) { 79 navigator.getUserMedia({ video: true, audio: false }, 80 stream => { 81 yourVideo.srcObject = stream; 82 window.stream = stream; 83 Connection.addStream(stream) 84 }, 85 err => { 86 console.log(err); 87 }) 88 } 89 90 91 function createOffer(){ 92 //發送offer和answer的函數,發送本地session描述 93 Connection.createOffer().then(offer => { 94 Connection.setLocalDescription(offer); 95 websocket.send(JSON.stringify({ 96 "userid":userid, 97 "event": "offer", 98 "data": { 99 "sdp": offer 100 } 101 })); 102 }); 103 } 104 105 106 107 function createSocket(){ 108 //websocket = null; 109 websocket = new WebSocket('wss://www.ecoblog.online/wss'); 110 eventBind(); 111 }; 112 function eventBind() { 113 //鏈接成功 114 websocket.onopen = function(e) { 115 console.log('鏈接成功') 116 }; 117 //server端請求關閉 118 websocket.onclose = function(e) { 119 console.log('close') 120 }; 121 //error 122 websocket.onerror = function(e) { 123 124 }; 125 //收到消息 126 websocket.onmessage = (event)=> { 127 if(event.data == "new user") { 128 location.reload(); 129 } else { 130 var json = JSON.parse(event.data); 131 console.log('onmessage: ', json); 132 if(json.userid !=userid){ 133 //若是是一個ICE的候選,則將其加入到PeerConnection中,不然設定對方的session描述爲傳遞過來的描述 134 if(json.event === "_ice_candidate"&&json.data.candidate) { 135 Connection.addIceCandidate(new RTCIceCandidate(json.data.candidate)); 136 }else if(json.event ==='offer'){ 137 Connection.setRemoteDescription(json.data.sdp); 138 Connection.createAnswer().then(answer => { 139 Connection.setLocalDescription(answer); 140 console.log(window.stream) 141 websocket.send(JSON.stringify({ 142 "userid":userid, 143 "event": "answer", 144 "data": { 145 "sdp": answer 146 } 147 })); 148 }) 149 }else if(json.event ==='answer'){ 150 Connection.setRemoteDescription(json.data.sdp); 151 console.log(window.stream) 152 153 } 154 } 155 } 156 }; 157 }
創建鏈接的過程:nginx
1⃣️兩個瀏覽器都打開該頁面,鏈接到同一個socket('wss://www.ecoblog.online/wss');web
注意:webrtc只能在localhost或者https下使用,因此線上環境的話,咱們的socket服務以及html頁面都必須是要有https證書的;json
對於wss,利用反向代理,在nginx的站點配置下以下配置/wss:centos
正如你所看到的那樣,socket服務開在12345端口,因此還要去阿里雲網站開一個這個端口的出入站規則;瀏覽器
另外centos的防火牆對該端口開放,或者直接關閉防火牆(自行百度)服務器
socket服務寫得比較簡陋,但已夠用,功能就是把收到的信息發給當前鏈接的全部c端websocket
2⃣️兩個c端已經和socket創建鏈接,而後任意其中一端點擊「創建鏈接」session
此時點擊創建鏈接的端就是offer(攜帶信號源信息),發給另一個端,另一個端收到offer以後,發出響應answer(攜帶信號源信息),offer端收到answer端信息進行存儲;
這樣每一個端都有了本身的信息和對方的信息,
3⃣️candidata信息的發送
其實這塊,網上有的說法是offer發出answer發出後設置了localDescription和remoteDescription後就會觸發onicecandidate,可是我測試的時候貌似沒有,因此
我這裏是在獲取攝像頭信息後經過
Connection.addStream(stream)
來觸發Connection.onicecandidate,在這個事件監聽的回調裏,發出自身端的candidata給對方,如此一來,雙方都有了對方的localDescription、remoteDescription和candidata;
三者齊全以後,就會觸發Connection.onaddstream,這樣,直接經過:
theirVideo.srcObject = e.stream;
把流寫到video裏面去,這樣就能展現對方的視頻信息了:
可是這樣,只能在局域網內使用,若是要在公網使用的話,還要一個穿透服務器,網上找的一些免費的好像都不能用了?仍是說我寫得有問題?
具體的可百度,webrtc搭建stun服務器