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.js

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 }
建立连接的过程:
1⃣️两个浏览器都打开该页面,连接到同一个socket('wss://www.ecoblog.online/wss');
注意:webrtc只能在localhost或者https下使用,所以线上环境的话,我们的socket服务以及html页面都必须是要有https证书的;
对于wss,利用代理,在nginx的站点配置下如下配置/wss:

正如你所看到的那样,socket服务开在12345端口,所以还要去阿里云网站开一个这个端口的出入站规则;
另外centos的防火墙对该端口开放,或者直接关闭防火墙(自行百度)
socket服务写得比较简陋,但已够用,功能就是把收到的信息发给当前连接的所有c端

2⃣️两个c端已经和socket建立连接,然后任意其中一端点击“建立连接”
此时点击建立连接的端就是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服务器
