@gogoqiu/tencent-http-server 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/gogoqiu-node-http-service +3 -0
- package/dist/build.d.ts +3 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +3 -0
- package/dist/build.js.map +1 -0
- package/dist/routes/index.d.ts +4 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +106 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +318 -0
- package/dist/server.js.map +1 -0
- package/dist/serverCmd.d.ts +8 -0
- package/dist/serverCmd.d.ts.map +1 -0
- package/dist/serverCmd.js +44 -0
- package/dist/serverCmd.js.map +1 -0
- package/dist/shell/install.d.ts +5 -0
- package/dist/shell/install.d.ts.map +1 -0
- package/dist/shell/install.js +221 -0
- package/dist/shell/install.js.map +1 -0
- package/dist/shell/postinst.d.ts +2 -0
- package/dist/shell/postinst.d.ts.map +1 -0
- package/dist/shell/postinst.js +4 -0
- package/dist/shell/postinst.js.map +1 -0
- package/dist/shell.d.ts +2 -0
- package/dist/shell.d.ts.map +1 -0
- package/dist/shell.js +249 -0
- package/dist/shell.js.map +1 -0
- package/package.json +82 -0
- package/public/captures1//346/265/213/350/257/225/347/224/250captures +0 -0
- package/public/chat/offer.html +796 -0
- package/public/chat/options.html +58 -0
- package/public/chat/server-info.html +32 -0
- package/public/chat2.html +272 -0
- package/public/chat3.html +246 -0
- package/public/chat4.html +302 -0
- package/public/chat5.html +41 -0
- package/public/formdata.html +41 -0
- package/public/hls-player.htm +41 -0
- package/public/img/back.svg +1 -0
- package/public/img/offline.svg +1 -0
- package/public/img/online.svg +1 -0
- package/public/ip-record.html +28 -0
- package/public/js/encrypt.js +36 -0
- package/public/js/socket.io.min.js +7 -0
- package/public/js/socket.io.min.js.map +1 -0
- package/public/myhost/hostReg.html +35 -0
- package/public/mylog-chat.htm +260 -0
- package/public/mylog3.html +245 -0
- package/public/navbar.css +17 -0
- package/public/readme.txt +3 -0
- package/public/scroll.htm +139 -0
- package/public/ssh-client.html +0 -0
- package/public/upload-file.html +226 -0
- package/public/upload.html +23 -0
- package/public/uploads1/files-1757866537383-447469495.jpg +0 -0
- package/public/uploads1/files-1757867389485-764531720.jpg +0 -0
- package/public/uploads1/files-1757867518311-278635302.jpg +0 -0
- package/public/uploads1/files-1757867629687-688924576.jpg +0 -0
- package/public/uploads1/files-1757868630683-52261917.jpg +0 -0
- package/public/uploads1/files-1757869187061-619427683.jpg +0 -0
- package/public/uploads1/small_files-1757869187061-619427683.jpg +0 -0
- package/public/uploads1//346/265/213/350/257/225/347/224/250upload +0 -0
- package/public/utils.html +57 -0
- package/public/utils.js +161 -0
- package/public/webrtc/rtc-client.html +238 -0
- package/public/webrtc/rtc-file-transfer-client.html +238 -0
- package/public/webrtc/rtc-file-transfer-server.html +453 -0
- package/public/webrtc/rtc-server.html +453 -0
- package/public/webrtc/video-client-input.html +264 -0
- package/public/webrtc/video-server-input.html +312 -0
- package/public/webrtc/webrtc-chat-with-files.html +581 -0
- package/public/webrtc/webrtc-chat.html +367 -0
- package/public/webrtc/webrtc-file-offer.html +88 -0
- package/public/webrtc/webrtc1.html +186 -0
- package/readme.txt +71 -0
- package/views/chat.ejs +53 -0
- package/views/index.ejs +125 -0
- package/views/special-message.ejs +8 -0
- package/views/ssh.ejs +142 -0
- package/views/utils.ejs +0 -0
- package/views/webrtc/client.ejs +203 -0
- package/views/webrtc/server.ejs +365 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
|
|
6
|
+
<meta charset="utf-8">
|
|
7
|
+
<meta name="description" content="WebRTC code samples">
|
|
8
|
+
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1, maximum-scale=1">
|
|
9
|
+
<meta itemprop="description" content="Client-side WebRTC code samples">
|
|
10
|
+
<meta itemprop="image" content="../../../images/webrtc-icon-192x192.png">
|
|
11
|
+
<meta itemprop="name" content="WebRTC code samples">
|
|
12
|
+
<meta name="mobile-web-app-capable" content="yes">
|
|
13
|
+
<meta id="theme-color" name="theme-color" content="#ffffff">
|
|
14
|
+
|
|
15
|
+
<base target="_blank">
|
|
16
|
+
|
|
17
|
+
<title>手动构建WebRTC/Cliet</title>
|
|
18
|
+
|
|
19
|
+
<script src="/js/socket.io.min.js"></script>
|
|
20
|
+
<style>
|
|
21
|
+
video{
|
|
22
|
+
width: 400px;
|
|
23
|
+
height: 300px;
|
|
24
|
+
}
|
|
25
|
+
</style>
|
|
26
|
+
</head>
|
|
27
|
+
|
|
28
|
+
<body>
|
|
29
|
+
|
|
30
|
+
<div id="container">
|
|
31
|
+
<P><a href="/">CLIENT</a></P>
|
|
32
|
+
<div id="log"></div>
|
|
33
|
+
<div>
|
|
34
|
+
<!--reflect-->
|
|
35
|
+
<!--copy出去-->
|
|
36
|
+
<textarea id="candidate" placeholder="candidate from ice"></textarea>
|
|
37
|
+
</div>
|
|
38
|
+
<div>
|
|
39
|
+
<!--get-->
|
|
40
|
+
<!--copy进来-->
|
|
41
|
+
<textarea id="offer" placeholder="copy offer from server"></textarea>
|
|
42
|
+
<button id="set-offer" onclick="fillRemoteAndLocal()">set offer</button>
|
|
43
|
+
<textarea id="server-candidate" placeholder="copy candidate from server"></textarea>
|
|
44
|
+
<button id="" onclick="setServerCandidate()">setServerCandidate</button>
|
|
45
|
+
</div>
|
|
46
|
+
<div>
|
|
47
|
+
<!--gen-->
|
|
48
|
+
<!--copy出去-->
|
|
49
|
+
<textarea id="answer" placeholder="answer by gen"></textarea>
|
|
50
|
+
</div>
|
|
51
|
+
<video id="video" autoplay controls></video>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<script>
|
|
55
|
+
|
|
56
|
+
'use strict';
|
|
57
|
+
|
|
58
|
+
//var leftVideo = document.getElementById('leftVideo');
|
|
59
|
+
var video, pc
|
|
60
|
+
var startTime;
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
function initWs() {
|
|
64
|
+
const socket = io();
|
|
65
|
+
const hostId = new Date().getTime();
|
|
66
|
+
|
|
67
|
+
//会导致connected=false,然后无法emit信息
|
|
68
|
+
//socket.onconnect = function(){ console.log(arguments) }
|
|
69
|
+
|
|
70
|
+
/*
|
|
71
|
+
server/client共有的部分
|
|
72
|
+
socket.on('ice-candidate', ...
|
|
73
|
+
pc = new RTCPeerConnection(configuration);
|
|
74
|
+
*/
|
|
75
|
+
socket.on('webrtc ice-candidate', function (msg) {
|
|
76
|
+
//socket.emit('ice-candidate', { host:hostId, candidate: event.candidate})
|
|
77
|
+
//msg.candidate
|
|
78
|
+
if (msg.host != hostId) {
|
|
79
|
+
//pc1.addIceCandidate( msg.candidate )
|
|
80
|
+
pc.addIceCandidate(msg.candidate)
|
|
81
|
+
.then(() => {
|
|
82
|
+
console.log('addIceCandidate success', msg.candidate)
|
|
83
|
+
})
|
|
84
|
+
.catch(function (err) {
|
|
85
|
+
console.error('Error adding candidate:' + err)
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// 互作为候选
|
|
89
|
+
console.log("webrtc ice-candidate", msg)
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
socket.on('webrtc offer', function (desc) {
|
|
93
|
+
console.log('got offer', "offer desc", desc)
|
|
94
|
+
//
|
|
95
|
+
pc.setRemoteDescription(desc, function () {
|
|
96
|
+
// offer description
|
|
97
|
+
console.log('!!!!!!setRemoteDescription ok');
|
|
98
|
+
}, (error) => console.error('Failed to set session description: ' + error.toString()));
|
|
99
|
+
//console.log(desc)
|
|
100
|
+
pc.createAnswer((desc) => {
|
|
101
|
+
// answer with client description
|
|
102
|
+
pc.setLocalDescription(desc, function () {
|
|
103
|
+
console.log('!!!!!!setLocalDescription ok');
|
|
104
|
+
}, (error) => console.log('Failed to set session description: ' + error.toString())
|
|
105
|
+
);
|
|
106
|
+
// 特定类型的消息
|
|
107
|
+
socket.emit('webrtc answer', desc);
|
|
108
|
+
},
|
|
109
|
+
(error) => console.log('Failed to create session description: ' + error.toString()));
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
socket.on('webrtc answer', function (desc) {
|
|
113
|
+
//pc1.setRemoteDescription(desc)
|
|
114
|
+
console.log(desc)
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 对应<!--copy进来--><textarea id="server-candidate"></textarea>
|
|
119
|
+
// copy进来的元素,都对应一个set函数
|
|
120
|
+
function setServerCandidate(){
|
|
121
|
+
const candidate = document.getElementById('server-candidate').value
|
|
122
|
+
const cds = JSON.parse(candidate)
|
|
123
|
+
cds.forEach(element => {
|
|
124
|
+
/*
|
|
125
|
+
{
|
|
126
|
+
"candidate": "candidate:2316088585 1 udp 2113937151 a2ead078-c10d-4db3-a197-5d853e320c5f.local 60373 typ host generation 0 ufrag VGiA network-cost 999",
|
|
127
|
+
"sdpMid": "0",
|
|
128
|
+
"sdpMLineIndex": 0,
|
|
129
|
+
"usernameFragment": "VGiA"
|
|
130
|
+
}
|
|
131
|
+
Error adding candidate:InvalidStateError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': The remote description was null
|
|
132
|
+
remote description, 先要吸收offer?
|
|
133
|
+
设置远方描述,再设置远方描述的网络候选者?
|
|
134
|
+
*/
|
|
135
|
+
pc.addIceCandidate(element)
|
|
136
|
+
.then(() => {
|
|
137
|
+
console.log('addIceCandidate success', element)
|
|
138
|
+
})
|
|
139
|
+
.catch(function (err) {
|
|
140
|
+
console.error('Error adding candidate:' + err)
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function setOffer(){
|
|
146
|
+
const desc = document.getElementById('offer').value
|
|
147
|
+
if( !desc ){
|
|
148
|
+
alert('Please enter offer')
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
// 发起pc.onicecandidate前重置
|
|
152
|
+
cds = []
|
|
153
|
+
// 会立即触发:pc.onicecandidate
|
|
154
|
+
pc.setRemoteDescription(JSON.parse(desc), ()=> {
|
|
155
|
+
// offer description
|
|
156
|
+
console.log('!!!!!!setRemoteDescription ok');
|
|
157
|
+
}, (error) => console.error('Failed to set session description: ' + error.toString()));
|
|
158
|
+
//console.log(desc)
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function createAnswer() {
|
|
163
|
+
pc.createAnswer((desc) => {
|
|
164
|
+
document.getElementById('answer').value = JSON.stringify(desc, null, 2)
|
|
165
|
+
// answer with client description
|
|
166
|
+
pc.setLocalDescription(desc, function () {
|
|
167
|
+
console.log('!!!!!!setLocalDescription ok');
|
|
168
|
+
}, (error) => console.log('Failed to set session description: ' + error.toString())
|
|
169
|
+
);
|
|
170
|
+
// 特定类型的消息
|
|
171
|
+
//socket.emit('webrtc answer', desc);
|
|
172
|
+
},
|
|
173
|
+
(error) => console.log('Failed to create session description: ' + error.toString()));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// 先配置远端描述
|
|
177
|
+
function fillRemoteAndLocal() {
|
|
178
|
+
if( setOffer() ) {
|
|
179
|
+
createAnswer()
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
var cds = [];
|
|
184
|
+
function initPC() {
|
|
185
|
+
const configuration = {
|
|
186
|
+
iceServers: [
|
|
187
|
+
//stun协议服务器。反馈外网信息
|
|
188
|
+
{ urls: 'stun:stun.l.google.com:19302' },
|
|
189
|
+
/*
|
|
190
|
+
{
|
|
191
|
+
urls: 'turn:yourturnserver.com:3478',
|
|
192
|
+
username: 'yourusername',
|
|
193
|
+
credential: 'yourpassword'
|
|
194
|
+
}*/
|
|
195
|
+
]
|
|
196
|
+
};
|
|
197
|
+
// 获得外网信息?
|
|
198
|
+
pc = new RTCPeerConnection(configuration);
|
|
199
|
+
pc.onicecandidate = function (e) {
|
|
200
|
+
// 与ice通讯的结果,从ice服务器获得的自身外网情况
|
|
201
|
+
//console.log('onicecandidate', event);
|
|
202
|
+
//document.getElementById("candidate").value = event.candidate;
|
|
203
|
+
//socket.emit('webrtc ice-candidate', { host: hostId, candidate: event.candidate });
|
|
204
|
+
console.log('onicecandidate', e.candidate)
|
|
205
|
+
cds.push( e.candidate )
|
|
206
|
+
document.getElementById('candidate').value = JSON.stringify(cds, null, 2);
|
|
207
|
+
};
|
|
208
|
+
pc.oniceconnectionstatechange = function (e) {
|
|
209
|
+
console.log('ICE state change event: ', e);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
pc.ontrack = gotRemoteStream;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function gotRemoteStream(event) {
|
|
216
|
+
console.log('got remote stream', event);
|
|
217
|
+
// 会不会触发onresize
|
|
218
|
+
if (video.srcObject !== event.streams[0]) {
|
|
219
|
+
// video控件竟然支持碎片解析播放
|
|
220
|
+
// 绑定
|
|
221
|
+
video.srcObject = event.streams[0];
|
|
222
|
+
console.log('pc received remote stream', event);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function initVideo() {
|
|
227
|
+
video = document.getElementById('video');
|
|
228
|
+
/*
|
|
229
|
+
也能部署在php下,只要广播能用
|
|
230
|
+
*/
|
|
231
|
+
video.onloadedmetadata = function () {
|
|
232
|
+
console.log('Remote video videoWidth: ' + this.videoWidth +
|
|
233
|
+
'px, videoHeight: ' + this.videoHeight + 'px');
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
video.onresize = function () {
|
|
237
|
+
console.log('Remote video size changed to ' +
|
|
238
|
+
video.videoWidth + 'x' + video.videoHeight);
|
|
239
|
+
// We'll use the first onresize callback as an indication that
|
|
240
|
+
// video has started playing out.
|
|
241
|
+
if (startTime) {
|
|
242
|
+
var elapsedTime = window.performance.now() - startTime;
|
|
243
|
+
console.log('Setup time: ' + elapsedTime.toFixed(3) + 'ms');
|
|
244
|
+
startTime = null;
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
video.onerror = function (err) {
|
|
248
|
+
console.log(err);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
window.onload = function() {
|
|
253
|
+
initVideo()
|
|
254
|
+
initPC()
|
|
255
|
+
/*
|
|
256
|
+
等待server的offer的产生,复制过来,fillRemoteAndLocal
|
|
257
|
+
*/
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
</script>
|
|
261
|
+
|
|
262
|
+
</body>
|
|
263
|
+
|
|
264
|
+
</html>
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
|
|
3
|
+
<html>
|
|
4
|
+
|
|
5
|
+
<head>
|
|
6
|
+
|
|
7
|
+
<meta charset="utf-8">
|
|
8
|
+
<meta name="description" content="WebRTC code samples">
|
|
9
|
+
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1, maximum-scale=1">
|
|
10
|
+
<meta itemprop="description" content="Client-side WebRTC code samples">
|
|
11
|
+
<meta itemprop="image" content="../../../images/webrtc-icon-192x192.png">
|
|
12
|
+
<meta itemprop="name" content="WebRTC code samples">
|
|
13
|
+
<meta name="mobile-web-app-capable" content="yes">
|
|
14
|
+
<meta id="theme-color" name="theme-color" content="#ffffff">
|
|
15
|
+
|
|
16
|
+
<base target="_blank">
|
|
17
|
+
|
|
18
|
+
<title>手动构建WebRTC/Server</title>
|
|
19
|
+
|
|
20
|
+
<!--link rel="icon" sizes="192x192" href="../../../images/webrtc-icon-192x192.png">
|
|
21
|
+
<link href="//fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet" type="text/css">
|
|
22
|
+
<link rel="stylesheet" href="../../../css/main.css" />
|
|
23
|
+
<link rel="stylesheet" href="css/main.css" /-->
|
|
24
|
+
<script src="/js/socket.io.min.js"></script>
|
|
25
|
+
<style>
|
|
26
|
+
video{
|
|
27
|
+
width: 400px;
|
|
28
|
+
height: 300px;
|
|
29
|
+
}
|
|
30
|
+
</style>
|
|
31
|
+
</head>
|
|
32
|
+
|
|
33
|
+
<body>
|
|
34
|
+
|
|
35
|
+
<div id="container">
|
|
36
|
+
|
|
37
|
+
<h1><a href="/"><span>SERVER</span></a></h1>
|
|
38
|
+
|
|
39
|
+
<video id="srcVideo" controls muted crossorigin="anonymous">
|
|
40
|
+
<!-- NB CORS: https://bugzilla.mozilla.org/show_bug.cgi?id=1177793 -->
|
|
41
|
+
<source src="http://git.my.host:28888/200_pages1/mnt/disk2/sd2.3.2.mp4" type="video/mp4" />
|
|
42
|
+
<source src="http://git.my.host:28888/200_pages1/mnt/disk2/sd2.3.1.mp4" type="video/mp4" />
|
|
43
|
+
<p>This browser does not support the video element.</p>
|
|
44
|
+
</video>
|
|
45
|
+
<div>
|
|
46
|
+
<!--reflect-->
|
|
47
|
+
<!--copy出去-->
|
|
48
|
+
<textarea id="candidate" placeholder="candidate from ice"></textarea>
|
|
49
|
+
</div>
|
|
50
|
+
<div>
|
|
51
|
+
<!--gen-->
|
|
52
|
+
<!--copy出去-->
|
|
53
|
+
<textarea id="offer" placeholder="offer by gen"></textarea>
|
|
54
|
+
</div>
|
|
55
|
+
<div>
|
|
56
|
+
<!--get-->
|
|
57
|
+
<!--copy进来-->
|
|
58
|
+
<textarea id="client-candidate" placeholder="copy candidate from client"></textarea>
|
|
59
|
+
<button id="" onclick="setClientCandidate()">setClientCandidate</button>
|
|
60
|
+
<textarea id="answer" placeholder="copy answer from client"></textarea>
|
|
61
|
+
<button id="set-answer" onclick="setAnswer()">set Answer</button>
|
|
62
|
+
</div>
|
|
63
|
+
<p>获取stun/turn回掉</p>
|
|
64
|
+
<div>
|
|
65
|
+
使用方法:
|
|
66
|
+
两处分别打开server/client, 服务器端分别点击init/call, 就能实现视频的同步播放。
|
|
67
|
+
</div>
|
|
68
|
+
<!--
|
|
69
|
+
操作次序:
|
|
70
|
+
点击"发起请求",
|
|
71
|
+
copy本页offer到client, 点击client"set offer",copy本页candidate到client, 点击setServerCandidate
|
|
72
|
+
copy客户页answer到本页,点击client"set answer", copy客户页candidate到本页, 点击setClientCandidate
|
|
73
|
+
-->
|
|
74
|
+
<button onclick="createOffer()">发起请求</button>
|
|
75
|
+
<!--button onclick="init()">初始化PeerConnect</button>
|
|
76
|
+
<p>建立offer</p>
|
|
77
|
+
<button onclick="call()">发起请求</button-->
|
|
78
|
+
<!--button>播放</button-->
|
|
79
|
+
|
|
80
|
+
<!--video id="rightVideo" autoplay controls></video-->
|
|
81
|
+
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<script>
|
|
85
|
+
|
|
86
|
+
'use strict';
|
|
87
|
+
|
|
88
|
+
function initWs() {
|
|
89
|
+
let socket;
|
|
90
|
+
//window.onload = function() {
|
|
91
|
+
socket = io();
|
|
92
|
+
const hostId = new Date().getTime();
|
|
93
|
+
|
|
94
|
+
socket.on('webrtc ice-candidate', function (msg) {
|
|
95
|
+
//socket.emit('ice-candidate', { host:hostId, candidate: event.candidate})
|
|
96
|
+
//msg.candidate
|
|
97
|
+
if (msg.host != hostId) {
|
|
98
|
+
//pc.addIceCandidate( msg.candidate )
|
|
99
|
+
(pc).addIceCandidate(msg.candidate)
|
|
100
|
+
.then(() => {
|
|
101
|
+
console.log('addIceCandidate success', msg.candidate)
|
|
102
|
+
})
|
|
103
|
+
.catch(function (err) {
|
|
104
|
+
console.error('Error adding candidate:' + err)
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
console.log(msg)
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
socket.on('webrtc offer', function (msg) {
|
|
111
|
+
console.log(msg)
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
/*
|
|
115
|
+
事件
|
|
116
|
+
装入video, metadata
|
|
117
|
+
收到ice反馈
|
|
118
|
+
收到客户端ice反馈
|
|
119
|
+
*/
|
|
120
|
+
socket.on('webrtc answer', function (desc) {
|
|
121
|
+
console.log('got answer')
|
|
122
|
+
pc.setRemoteDescription(desc, function () {
|
|
123
|
+
console.log('!!!!!!setRemoteDescription ok');
|
|
124
|
+
}, (error) => console.log('Failed to set session description: ' + error.toString()));
|
|
125
|
+
//pc.setRemoteDescription(desc)
|
|
126
|
+
console.log(desc)
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function setClientCandidate(){
|
|
131
|
+
const candidate = document.getElementById('client-candidate').value
|
|
132
|
+
const cds = JSON.parse(candidate)
|
|
133
|
+
cds.forEach(element => {
|
|
134
|
+
pc.addIceCandidate(element)
|
|
135
|
+
.then(() => {
|
|
136
|
+
console.log('addIceCandidate success', candidate)
|
|
137
|
+
})
|
|
138
|
+
.catch(function (err) {
|
|
139
|
+
console.error('Error adding candidate:' + err)
|
|
140
|
+
});
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
//client set local/remote by once, server set local/remote by twice
|
|
145
|
+
function setAnswer(){
|
|
146
|
+
const desc = document.getElementById('answer').value
|
|
147
|
+
if( !desc ){
|
|
148
|
+
alert('Please enter answer')
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
//pc.remoteDescription
|
|
152
|
+
pc.setRemoteDescription(JSON.parse(desc), function () {
|
|
153
|
+
console.log('!!!!!!setRemoteDescription ok');
|
|
154
|
+
}, (error) => console.log('Failed to set session description: ' + error.toString()));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
var srcVideo
|
|
158
|
+
var stream;
|
|
159
|
+
var pc;
|
|
160
|
+
var cds = []
|
|
161
|
+
|
|
162
|
+
function createOffer() {
|
|
163
|
+
cds = []
|
|
164
|
+
var offerOptions = {
|
|
165
|
+
offerToReceiveAudio: 1,
|
|
166
|
+
offerToReceiveVideo: 1
|
|
167
|
+
};
|
|
168
|
+
pc.createOffer(
|
|
169
|
+
(desc) => {
|
|
170
|
+
console.log( desc )
|
|
171
|
+
document.getElementById('offer').value = JSON.stringify(desc, null, 2 );
|
|
172
|
+
pc.setLocalDescription(desc, function () {
|
|
173
|
+
console.log("!!!!!!SetLocalSuccess ok");
|
|
174
|
+
}, (err) => {
|
|
175
|
+
console.error("SetLocalFailed", err);
|
|
176
|
+
});
|
|
177
|
+
},
|
|
178
|
+
(error) => console.log('Failed to create session description: '
|
|
179
|
+
+ error.toString()),
|
|
180
|
+
offerOptions);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function fillLocalAndRemote() {
|
|
184
|
+
createOffer()
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function initPC(){
|
|
188
|
+
const configuration = {
|
|
189
|
+
iceServers: [
|
|
190
|
+
//stun协议服务器。反馈外网信息
|
|
191
|
+
{ urls: 'stun:stun.l.google.com:19302' },
|
|
192
|
+
/*
|
|
193
|
+
{
|
|
194
|
+
urls: 'turn:yourturnserver.com:3478',
|
|
195
|
+
username: 'yourusername',
|
|
196
|
+
credential: 'yourpassword'
|
|
197
|
+
}*/
|
|
198
|
+
]
|
|
199
|
+
};
|
|
200
|
+
pc = new RTCPeerConnection(configuration);
|
|
201
|
+
//console.log('Created local peer connection object pc');
|
|
202
|
+
pc.onicecandidate = function (e) {
|
|
203
|
+
//addIceCandidate
|
|
204
|
+
/*
|
|
205
|
+
// 首先发送ice-candidate的是客户端?
|
|
206
|
+
*/
|
|
207
|
+
//socket.emit('webrtc ice-candidate', { host: hostId, candidate: (event.candidate) });
|
|
208
|
+
console.log('onicecandidate', e.candidate)
|
|
209
|
+
cds.push( e.candidate )
|
|
210
|
+
document.getElementById('candidate').value = JSON.stringify(cds, null, 2);
|
|
211
|
+
};
|
|
212
|
+
pc.oniceconnectionstatechange = function (e) {
|
|
213
|
+
//onIceStateChange(pc, e);
|
|
214
|
+
console.log('ICE state change event: ', e);
|
|
215
|
+
return;
|
|
216
|
+
//
|
|
217
|
+
e.target
|
|
218
|
+
e.currentTarget
|
|
219
|
+
const currentState = e.target.iceConnectionState;
|
|
220
|
+
console.log('ICE 连接状态变化:', currentState);
|
|
221
|
+
|
|
222
|
+
// 根据不同状态处理
|
|
223
|
+
switch (currentState) {
|
|
224
|
+
case 'new':
|
|
225
|
+
// 初始状态:连接尚未开始建立
|
|
226
|
+
console.log('ICE 连接已创建,尚未开始连接');
|
|
227
|
+
break;
|
|
228
|
+
case 'checking':
|
|
229
|
+
// 正在检查连接:ICE 正在尝试不同的候选地址(如本地地址、STUN 反射地址、TURN 中继地址)
|
|
230
|
+
console.log('ICE 正在检查连接候选地址...');
|
|
231
|
+
break;
|
|
232
|
+
case 'connected':
|
|
233
|
+
// 部分连接成功:至少有一个 P2P 连接已建立(可能仍在检查其他候选以优化连接)
|
|
234
|
+
console.log('ICE 已建立部分连接,通信可正常进行');
|
|
235
|
+
break;
|
|
236
|
+
case 'completed':
|
|
237
|
+
// 完全连接成功:所有 ICE 候选检查完成,最佳 P2P 连接已确定
|
|
238
|
+
console.log('ICE 连接完全建立,已确定最佳通信路径');
|
|
239
|
+
break;
|
|
240
|
+
case 'failed':
|
|
241
|
+
// 连接失败:所有 ICE 候选检查都失败,P2P 连接无法建立(需考虑用 TURN 中继或提示用户)
|
|
242
|
+
console.error('ICE 连接失败,无法建立 P2P 通信');
|
|
243
|
+
// 可选:触发重试逻辑或提示用户
|
|
244
|
+
retryConnection();
|
|
245
|
+
break;
|
|
246
|
+
case 'disconnected':
|
|
247
|
+
// 连接断开:之前建立的连接丢失(如网络波动、对方离线)
|
|
248
|
+
console.warn('ICE 连接已断开,尝试重连...');
|
|
249
|
+
// 可选:尝试重新收集 ICE 候选并重连
|
|
250
|
+
//peerConnection.restartIce();
|
|
251
|
+
console.error('ICE 连接失败,尝试重启...');
|
|
252
|
+
// 重启 ICE 流程(会重新收集候选并尝试连接)
|
|
253
|
+
peerConnection.restartIce()
|
|
254
|
+
.then(() => console.log('ICE 重启成功,正在重新连接...'))
|
|
255
|
+
.catch(err => console.error('ICE 重启失败:', err));
|
|
256
|
+
break;
|
|
257
|
+
case 'closed':
|
|
258
|
+
// 连接已关闭:主动调用 peerConnection.close() 后触发
|
|
259
|
+
console.log('ICE 连接已主动关闭');
|
|
260
|
+
// 可选:释放资源、清理 UI
|
|
261
|
+
cleanupConnection();
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
stream.getTracks().forEach(
|
|
266
|
+
function (track) {
|
|
267
|
+
pc.addTrack(
|
|
268
|
+
track,
|
|
269
|
+
stream
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function initVideo() {
|
|
276
|
+
srcVideo = document.getElementById('srcVideo');
|
|
277
|
+
if (srcVideo.captureStream) {
|
|
278
|
+
// 从video里获取流?媒体流
|
|
279
|
+
stream = srcVideo.captureStream();
|
|
280
|
+
console.log('Captured stream from srcVideo with captureStream',
|
|
281
|
+
stream);
|
|
282
|
+
//call();
|
|
283
|
+
} else if (srcVideo.mozCaptureStream) {
|
|
284
|
+
stream = srcVideo.mozCaptureStream();
|
|
285
|
+
console.log('Captured stream from srcVideo with mozCaptureStream()',
|
|
286
|
+
stream);
|
|
287
|
+
//call();
|
|
288
|
+
} else {
|
|
289
|
+
console.error('captureStream() not supported');
|
|
290
|
+
}
|
|
291
|
+
var videoTracks = stream.getVideoTracks();
|
|
292
|
+
var audioTracks = stream.getAudioTracks();
|
|
293
|
+
if (videoTracks.length > 0) {
|
|
294
|
+
console.log('Using video device: ' + videoTracks[0].label);
|
|
295
|
+
}
|
|
296
|
+
if (audioTracks.length > 0) {
|
|
297
|
+
console.log('Using audio device: ' + audioTracks[0].label);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
window.onload = function() {
|
|
302
|
+
initVideo()
|
|
303
|
+
initPC()
|
|
304
|
+
/*
|
|
305
|
+
产生offer,粘帖过去, client获得answer,粘帖过来
|
|
306
|
+
*/
|
|
307
|
+
};
|
|
308
|
+
</script>
|
|
309
|
+
|
|
310
|
+
</body>
|
|
311
|
+
|
|
312
|
+
</html>
|