zhyz-cloudrender-v5 1.0.0
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/README.md +54 -0
- package/adapter.js +3364 -0
- package/cloudRender.es.js +24523 -0
- package/cloudRender.js +24529 -0
- package/cloudRender.umd.js +24531 -0
- package/p2p.js +1426 -0
- package/package.json +11 -0
- package/webRtcPlayer.js +575 -0
package/p2p.js
ADDED
|
@@ -0,0 +1,1426 @@
|
|
|
1
|
+
/* eslint-disable no-prototype-builtins */
|
|
2
|
+
/* eslint-disable no-undef */
|
|
3
|
+
/* eslint-disable no-mixed-spaces-and-tabs */
|
|
4
|
+
/* eslint-disable no-unused-vars */
|
|
5
|
+
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
6
|
+
|
|
7
|
+
const webRtcPlayer = require('./webRtcPlayer');
|
|
8
|
+
let className = '';
|
|
9
|
+
let roomId = '';
|
|
10
|
+
let receivedBytesMeasurement = '';
|
|
11
|
+
let receivedBytes = 0;
|
|
12
|
+
let color = 'red';
|
|
13
|
+
// Window events for a gamepad connecting
|
|
14
|
+
let haveEvents = 'GamepadEvent' in window;
|
|
15
|
+
let playerElement = null;
|
|
16
|
+
let videoElement = null;
|
|
17
|
+
let haveWebkitEvents = 'WebKitGamepadEvent' in window;
|
|
18
|
+
let controllers = {};
|
|
19
|
+
let rAF = window.mozRequestAnimationFrame ||
|
|
20
|
+
window.webkitRequestAnimationFrame ||
|
|
21
|
+
window.requestAnimationFrame;
|
|
22
|
+
let kbEvent = document.createEvent("KeyboardEvent");
|
|
23
|
+
let initMethod = typeof kbEvent.initKeyboardEvent !== 'undefined' ? "initKeyboardEvent" : "initKeyEvent";
|
|
24
|
+
|
|
25
|
+
let webRtcPlayerObj = null;
|
|
26
|
+
let webRtcDataChannelObj = null;
|
|
27
|
+
let print_stats = false;
|
|
28
|
+
let print_inputs = true;
|
|
29
|
+
let connect_on_load = true;
|
|
30
|
+
|
|
31
|
+
import store, {
|
|
32
|
+
SET_WEBRTC_OBJ
|
|
33
|
+
} from './store'
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
//let webRtcDataChannel_pc = null;
|
|
38
|
+
let is_reconnection = false;
|
|
39
|
+
let ws;
|
|
40
|
+
const WS_OPEN_STATE = 1;
|
|
41
|
+
|
|
42
|
+
let qualityControlOwnershipCheckBox;
|
|
43
|
+
let matchViewportResolution;
|
|
44
|
+
// TODO: Remove this - workaround because of bug causing UE to crash when switching resolutions too quickly
|
|
45
|
+
let lastTimeResized = new Date().getTime();
|
|
46
|
+
let resizeTimeout;
|
|
47
|
+
|
|
48
|
+
let onDataChannelConnected;
|
|
49
|
+
let responseEventListeners = new Map();
|
|
50
|
+
|
|
51
|
+
// A freeze frame is a still JPEG image shown instead of the video.
|
|
52
|
+
let freezeFrame = {
|
|
53
|
+
receiving: false,
|
|
54
|
+
size: 0,
|
|
55
|
+
jpeg: undefined,
|
|
56
|
+
height: 0,
|
|
57
|
+
width: 0,
|
|
58
|
+
valid: false
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Optionally detect if the user is not interacting (AFK) and disconnect them.
|
|
62
|
+
let afk = {
|
|
63
|
+
enabled: false, // Set to true to enable the AFK system.
|
|
64
|
+
warnTimeout: 120, // The time to elapse before warning the user they are inactive.
|
|
65
|
+
closeTimeout: 10, // The time after the warning when we disconnect the user.
|
|
66
|
+
|
|
67
|
+
active: false, // Whether the AFK system is currently looking for inactivity.
|
|
68
|
+
overlay: undefined, // The UI overlay warning the user that they are inactive.
|
|
69
|
+
warnTimer: undefined, // The timer which waits to show the inactivity warning overlay.
|
|
70
|
+
countdown: 0, // The inactivity warning overlay has a countdown to show time until disconnect.
|
|
71
|
+
countdownTimer: undefined, // The timer used to tick the seconds shown on the inactivity warning overlay.
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// If the user focuses on a UE4 input widget then we show them a button to open
|
|
75
|
+
// the on-screen keyboard. JavaScript security means we can only show the
|
|
76
|
+
// on-screen keyboard in response to a user interaction.
|
|
77
|
+
let editTextButton = undefined;
|
|
78
|
+
|
|
79
|
+
// A hidden input text box which is used only for focusing and opening the
|
|
80
|
+
// on-screen keyboard.
|
|
81
|
+
let hiddenInput = undefined;
|
|
82
|
+
|
|
83
|
+
let t0 = Date.now();
|
|
84
|
+
|
|
85
|
+
let params = {
|
|
86
|
+
roomname: '',
|
|
87
|
+
videousername: '',
|
|
88
|
+
rtc_ip: '',
|
|
89
|
+
rtc_port: '',
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
function gamepadConnectHandler(e) {
|
|
93
|
+
gamepad = e.gamepad;
|
|
94
|
+
controllers[gamepad.index] = {};
|
|
95
|
+
controllers[gamepad.index].currentState = gamepad;
|
|
96
|
+
controllers[gamepad.index].prevState = gamepad;
|
|
97
|
+
rAF(updateStatus);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function gamepadDisconnectHandler(e) {
|
|
101
|
+
delete controllers[e.gamepad.index];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function setupHtmlEvents() {
|
|
105
|
+
//Window events
|
|
106
|
+
window.addEventListener('orientationchange', onOrientationChange);
|
|
107
|
+
|
|
108
|
+
//Gamepad events
|
|
109
|
+
if (haveEvents) {
|
|
110
|
+
window.addEventListener("gamepadconnected", gamepadConnectHandler);
|
|
111
|
+
window.addEventListener("gamepaddisconnected", gamepadDisconnectHandler);
|
|
112
|
+
} else if (haveWebkitEvents) {
|
|
113
|
+
window.addEventListener("webkitgamepadconnected", gamepadConnectHandler);
|
|
114
|
+
window.addEventListener("webkitgamepaddisconnected", gamepadDisconnectHandler);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
//HTML elements controls
|
|
118
|
+
let overlayButton = document.getElementById('overlayButton');
|
|
119
|
+
overlayButton && overlayButton.addEventListener('click', onExpandOverlay_Click);
|
|
120
|
+
|
|
121
|
+
let resizeCheckBox = document.getElementById('enlarge-display-to-fill-window-tgl');
|
|
122
|
+
if (resizeCheckBox !== null) {
|
|
123
|
+
resizeCheckBox.onchange = function(event) {
|
|
124
|
+
// resizePlayerStyle();
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
qualityControlOwnershipCheckBox = document.getElementById('quality-control-ownership-tgl');
|
|
129
|
+
if (qualityControlOwnershipCheckBox !== null) {
|
|
130
|
+
qualityControlOwnershipCheckBox.onchange = function(event) {
|
|
131
|
+
requestQualityControl();
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let encoderParamsSubmit = document.getElementById('encoder-params-submit');
|
|
136
|
+
if (encoderParamsSubmit !== null) {
|
|
137
|
+
encoderParamsSubmit.onclick = function(event) {
|
|
138
|
+
let rateControl = document.getElementById('encoder-rate-control').value;
|
|
139
|
+
let targetBitrate = document.getElementById('encoder-target-bitrate-text').value * 1000;
|
|
140
|
+
let maxBitrate = document.getElementById('encoder-max-bitrate-text').value * 1000;
|
|
141
|
+
let minQP = document.getElementById('encoder-min-qp-text').value;
|
|
142
|
+
let maxQP = document.getElementById('encoder-max-qp-text').value;
|
|
143
|
+
let fillerData = document.getElementById('encoder-filler-data-tgl').checked ? 1 : 0;
|
|
144
|
+
let multipass = document.getElementById('encoder-multipass').value;
|
|
145
|
+
|
|
146
|
+
emitUIInteraction({ Console: 'PixelStreaming.Encoder.RateControl ' + rateControl });
|
|
147
|
+
emitUIInteraction({ Console: 'PixelStreaming.Encoder.TargetBitrate ' + targetBitrate > 0 ? targetBitrate : -1 });
|
|
148
|
+
emitUIInteraction({ Console: 'PixelStreaming.Encoder.MaxBitrateVBR ' + maxBitrate > 0 ? maxBitrate : -1 });
|
|
149
|
+
emitUIInteraction({ Console: 'PixelStreaming.Encoder.MinQP ' + minQP });
|
|
150
|
+
emitUIInteraction({ Console: 'PixelStreaming.Encoder.MaxQP ' + maxQP });
|
|
151
|
+
emitUIInteraction({ Console: 'PixelStreaming.Encoder.EnableFillerData ' + fillerData });
|
|
152
|
+
emitUIInteraction({ Console: 'PixelStreaming.Encoder.Multipass ' + multipass });
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let webrtcParamsSubmit = document.getElementById('webrtc-params-submit');
|
|
157
|
+
if (webrtcParamsSubmit !== null) {
|
|
158
|
+
webrtcParamsSubmit.onclick = function(event) {
|
|
159
|
+
let degradationPref = document.getElementById('webrtc-degradation-pref').value;
|
|
160
|
+
let maxFPS = document.getElementById('webrtc-max-fps-text').value;
|
|
161
|
+
let minBitrate = document.getElementById('webrtc-min-bitrate-text').value * 1000;
|
|
162
|
+
let maxBitrate = document.getElementById('webrtc-max-bitrate-text').value * 1000;
|
|
163
|
+
let lowQP = document.getElementById('webrtc-low-qp-text').value;
|
|
164
|
+
let highQP = document.getElementById('webrtc-high-qp-text').value;
|
|
165
|
+
|
|
166
|
+
emitUIInteraction({ Console: 'PixelStreaming.WebRTC.DegradationPreference ' + degradationPref });
|
|
167
|
+
emitUIInteraction({ Console: 'PixelStreaming.WebRTC.MaxFps ' + maxFPS });
|
|
168
|
+
emitUIInteraction({ Console: 'PixelStreaming.WebRTC.MinBitrate ' + minBitrate });
|
|
169
|
+
emitUIInteraction({ Console: 'PixelStreaming.WebRTC.MaxBitrate ' + maxBitrate });
|
|
170
|
+
emitUIInteraction({ Console: 'PixelStreaming.WebRTC.LowQpThreshold ' + lowQP });
|
|
171
|
+
emitUIInteraction({ Console: 'PixelStreaming.WebRTC.HighQpThreshold ' + highQP });
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
let showFPSButton = document.getElementById('show-fps-button');
|
|
176
|
+
if (showFPSButton !== null) {
|
|
177
|
+
showFPSButton.onclick = function (event) {
|
|
178
|
+
let consoleDescriptor = {
|
|
179
|
+
Console: 'stat fps'
|
|
180
|
+
};
|
|
181
|
+
emitUIInteraction(consoleDescriptor);
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
let matchViewportResolutionCheckBox = document.getElementById('match-viewport-res-tgl');
|
|
186
|
+
if (matchViewportResolutionCheckBox !== null) {
|
|
187
|
+
matchViewportResolutionCheckBox.onchange = function (event) {
|
|
188
|
+
matchViewportResolution = matchViewportResolutionCheckBox.checked;
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
let statsCheckBox = document.getElementById('show-stats-tgl');
|
|
193
|
+
if (statsCheckBox !== null) {
|
|
194
|
+
statsCheckBox.onchange = function(event) {
|
|
195
|
+
let stats = document.getElementById('statsContainer');
|
|
196
|
+
stats.style.display = event.target.checked ? "block" : "none";
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
let kickButton = document.getElementById('kick-other-players-button');
|
|
201
|
+
if (kickButton) {
|
|
202
|
+
kickButton.onclick = function (event) {
|
|
203
|
+
ws.send(JSON.stringify({
|
|
204
|
+
type: 'kick'
|
|
205
|
+
}));
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
let latencyButton = document.getElementById('test-latency-button');
|
|
210
|
+
if (latencyButton) {
|
|
211
|
+
latencyButton.onclick = () => {
|
|
212
|
+
sendStartLatencyTest();
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function sendStartLatencyTest() {
|
|
218
|
+
// We need WebRTC to be active to do a latency test.
|
|
219
|
+
if (!webRtcPlayerObj) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
let onTestStarted = function(StartTimeMs) {
|
|
224
|
+
let descriptor = {
|
|
225
|
+
StartTime: StartTimeMs
|
|
226
|
+
};
|
|
227
|
+
emitDescriptor(MessageType.LatencyTest, descriptor);
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
webRtcPlayerObj.startLatencyTest(onTestStarted);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function setOverlay() {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function showConnectOverlay() {
|
|
238
|
+
connect();
|
|
239
|
+
startAfkWarningTimer();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function showTextOverlay(text) {
|
|
243
|
+
let textOverlay = document.createElement('div');
|
|
244
|
+
textOverlay.id = 'messageOverlay';
|
|
245
|
+
textOverlay.innerHTML = text ? text : '';
|
|
246
|
+
setOverlay('textDisplayState', textOverlay);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function playVideoStream() {
|
|
250
|
+
if (webRtcPlayerObj && webRtcPlayerObj.video) {
|
|
251
|
+
|
|
252
|
+
webRtcPlayerObj.video.play().catch(function(onRejectedReason){
|
|
253
|
+
console.error(onRejectedReason);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
requestInitialSettings();
|
|
257
|
+
requestQualityControl();
|
|
258
|
+
hideOverlay();
|
|
259
|
+
} else {
|
|
260
|
+
console.error("Could not player video stream because webRtcPlayerObj.video was not valid.")
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
function updateAfkOverlayText() {
|
|
267
|
+
afk.overlay.innerHTML = '<center>No activity detected<br>Disconnecting in ' + afk.countdown + ' seconds<br>Click to continue<br></center>';
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function showAfkOverlay() {
|
|
271
|
+
// Pause the timer while the user is looking at the inactivity warning overlay.
|
|
272
|
+
stopAfkWarningTimer();
|
|
273
|
+
|
|
274
|
+
// Show the inactivity warning overlay.
|
|
275
|
+
afk.overlay = document.createElement('div');
|
|
276
|
+
afk.overlay.id = 'afkOverlay';
|
|
277
|
+
setOverlay('clickableState', afk.overlay, event => {
|
|
278
|
+
// The user clicked so start the timer again and carry on.
|
|
279
|
+
hideOverlay();
|
|
280
|
+
clearInterval(afk.countdownTimer);
|
|
281
|
+
startAfkWarningTimer();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
afk.countdown = afk.closeTimeout;
|
|
285
|
+
updateAfkOverlayText();
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
if (inputOptions.controlScheme == ControlSchemeType.LockedMouse) {
|
|
289
|
+
document.exitPointerLock();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
afk.countdownTimer = setInterval(function() {
|
|
294
|
+
afk.countdown--;
|
|
295
|
+
if (afk.countdown == 0) {
|
|
296
|
+
// The user failed to click so disconnect them.
|
|
297
|
+
hideOverlay();
|
|
298
|
+
ws.close();
|
|
299
|
+
} else {
|
|
300
|
+
// Update the countdown message.
|
|
301
|
+
updateAfkOverlayText();
|
|
302
|
+
}
|
|
303
|
+
}, 1000);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function hideOverlay() {
|
|
307
|
+
setOverlay('hiddenState');
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Start a timer which when elapsed will warn the user they are inactive.
|
|
311
|
+
function startAfkWarningTimer() {
|
|
312
|
+
afk.active = afk.enabled;
|
|
313
|
+
resetAfkWarningTimer();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Stop the timer which when elapsed will warn the user they are inactive.
|
|
317
|
+
function stopAfkWarningTimer() {
|
|
318
|
+
afk.active = false;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// If the user interacts then reset the warning timer.
|
|
322
|
+
function resetAfkWarningTimer() {
|
|
323
|
+
if (afk.active) {
|
|
324
|
+
clearTimeout(afk.warnTimer);
|
|
325
|
+
afk.warnTimer = setTimeout(function () {
|
|
326
|
+
showAfkOverlay();
|
|
327
|
+
}, afk.warnTimeout * 1000);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function createWebRtcOffer() {
|
|
332
|
+
if (webRtcPlayerObj ) {
|
|
333
|
+
showTextOverlay('Starting connection to server, please wait');
|
|
334
|
+
webRtcPlayerObj.createOffer();
|
|
335
|
+
// webRtcDataChannelObj.createOffer();
|
|
336
|
+
} else {
|
|
337
|
+
showTextOverlay('Unable to setup video');
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
功能: 获取Offer SDP 描述符的
|
|
346
|
+
|
|
347
|
+
*/
|
|
348
|
+
function getOffer(desc)
|
|
349
|
+
{
|
|
350
|
+
//设置Offer
|
|
351
|
+
webRtcDataChannelObj.setLocalDescription(desc);
|
|
352
|
+
|
|
353
|
+
if (ws && ws.readyState === WS_OPEN_STATE)
|
|
354
|
+
{
|
|
355
|
+
let offersdp = JSON.stringify({
|
|
356
|
+
msg_id: 208,
|
|
357
|
+
data: {
|
|
358
|
+
rtc_type:1,
|
|
359
|
+
offer : desc.sdp
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
ws.send(offersdp);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function handleOfferError(err)
|
|
368
|
+
{
|
|
369
|
+
console.log('Failed ot carete offer:', err);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
function createWebRtcDataChannelOffer()
|
|
374
|
+
{
|
|
375
|
+
if ( webRtcDataChannelObj) {
|
|
376
|
+
showTextOverlay('Starting connection to server, please wait');
|
|
377
|
+
let datachannel = webRtcDataChannelObj.createDataChannel('rtc', {ordered: true});
|
|
378
|
+
// Inform browser we would like binary data as an ArrayBuffer (FF chooses Blob by default!)
|
|
379
|
+
datachannel.binaryType = "arraybuffer";
|
|
380
|
+
datachannel.onopen = function (e) {
|
|
381
|
+
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
datachannel.onclose = function (e) {
|
|
385
|
+
console.log(`data channel closed`);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
datachannel.onmessage = function (e) {
|
|
389
|
+
console.log(`Got message `, e.data);
|
|
390
|
+
|
|
391
|
+
}
|
|
392
|
+
webRtcDataChannelObj.datachannel = datachannel;
|
|
393
|
+
|
|
394
|
+
webRtcDataChannelObj.createOffer()
|
|
395
|
+
.then(getOffer)
|
|
396
|
+
.catch(handleOfferError);
|
|
397
|
+
// webRtcDataChannelObj.createOffer() .then(async function (offerStr){
|
|
398
|
+
// webRtcDataChannelObj.setLocalDescription(offerStr);
|
|
399
|
+
// if (ws && ws.readyState === WS_OPEN_STATE)
|
|
400
|
+
// {
|
|
401
|
+
// console.log('DataChannel cs --> offer : = ', offerStr);
|
|
402
|
+
// let offersdp = JSON.stringify({
|
|
403
|
+
// msg_id: 208,
|
|
404
|
+
// data: {
|
|
405
|
+
// rtc_type:0,
|
|
406
|
+
// offer : offerStr.sdp
|
|
407
|
+
// }
|
|
408
|
+
// });
|
|
409
|
+
// console.log(`DataChannel -> SS: offer:\n${offersdp}`);
|
|
410
|
+
//
|
|
411
|
+
// ws.send(offersdp);
|
|
412
|
+
// }
|
|
413
|
+
// }, function(){console.warn("Couldn't create offer") ;});
|
|
414
|
+
// .catch(handleOfferError);
|
|
415
|
+
|
|
416
|
+
// pc.createOffer(self.sdpConstraints).then(function (offer) {
|
|
417
|
+
|
|
418
|
+
// // Munging is where we modifying the sdp string to set parameters that are not exposed to the browser's WebRTC API
|
|
419
|
+
// mungeSDPOffer(offer);
|
|
420
|
+
|
|
421
|
+
// // Set our munged SDP on the local peer connection so it is "set" and will be send across
|
|
422
|
+
// pc.setLocalDescription(offer);
|
|
423
|
+
// if (self.onWebRtcDataChannelOffer) {
|
|
424
|
+
// console.log('rtctype == 1-');
|
|
425
|
+
// self.onWebRtcDataChannelOffer(1, offer);
|
|
426
|
+
// }
|
|
427
|
+
// else
|
|
428
|
+
// {
|
|
429
|
+
// console.warn('not find DataChannel Offer callback send msg function ');
|
|
430
|
+
// }
|
|
431
|
+
// },
|
|
432
|
+
// function () { console.warn("Couldn't create offer") });
|
|
433
|
+
//webRtcDataChannelObj.createOffer();
|
|
434
|
+
} else {
|
|
435
|
+
console.log('WebRTC DataChannel not setup, cannot create offer');
|
|
436
|
+
//showTextOverlay('Unable to setup video');
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
function arrayBufferToString(buffer, encoding = 'gb2312') {
|
|
442
|
+
const decoder = new TextDecoder(encoding);
|
|
443
|
+
return decoder.decode(buffer);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function buf2hex(buffer) { // buffer is an ArrayBuffer
|
|
447
|
+
return [...new Uint8Array(buffer)]
|
|
448
|
+
.map(x => x.toString(2).padStart(1, '0'))
|
|
449
|
+
.join(' ');
|
|
450
|
+
}
|
|
451
|
+
function bufhex(buffer) { // buffer is an ArrayBuffer
|
|
452
|
+
return [...new Uint8Array(buffer)]
|
|
453
|
+
.map(x => x.toString(16).padStart(2, '0'))
|
|
454
|
+
.join('');
|
|
455
|
+
}
|
|
456
|
+
function xsendInputData(data) {
|
|
457
|
+
// if (webRtcPlayerObj) {
|
|
458
|
+
// resetAfkWarningTimer();
|
|
459
|
+
// webRtcPlayerObj.send(data);
|
|
460
|
+
// }
|
|
461
|
+
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function sendInputData(data) {
|
|
465
|
+
//
|
|
466
|
+
//if (webRtcDataChannelObj && webRtcDataChannelObj.datachannel.readyState == 'open') {
|
|
467
|
+
// // resetAfkWarningTimer();
|
|
468
|
+
// webRtcDataChannelObj.datachannel.send(data);
|
|
469
|
+
// // console.log('send input data =', data);
|
|
470
|
+
// }
|
|
471
|
+
// else
|
|
472
|
+
// {
|
|
473
|
+
//
|
|
474
|
+
// console.warn('send message failed !!! webRtcDataChannelObj.readyState =', webRtcDataChannelObj.readyState);
|
|
475
|
+
// }
|
|
476
|
+
// return;
|
|
477
|
+
if (webRtcPlayerObj) {
|
|
478
|
+
// resetAfkWarningTimer();
|
|
479
|
+
webRtcPlayerObj.send(data);
|
|
480
|
+
//console.log('hex = ', bufhex(data));
|
|
481
|
+
// if (ws && ws.readyState === WS_OPEN_STATE)
|
|
482
|
+
// {
|
|
483
|
+
//
|
|
484
|
+
// // let textDecoder = new TextDecoder("utf-8");
|
|
485
|
+
// // let str = textDecoder.decode(data);
|
|
486
|
+
//
|
|
487
|
+
// //console.log('CS--> data channel : = ', str);
|
|
488
|
+
// //arrayBufferToString(data)
|
|
489
|
+
// let offersdp = JSON.stringify({
|
|
490
|
+
// msg_id: 210,
|
|
491
|
+
// datachannel: data
|
|
492
|
+
// });
|
|
493
|
+
// // console.log(`-> SS: offer:\n${offersdp}`);
|
|
494
|
+
//
|
|
495
|
+
//
|
|
496
|
+
//
|
|
497
|
+
// ws.send(offersdp);
|
|
498
|
+
//
|
|
499
|
+
// }
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function addResponseEventListener(name, listener) {
|
|
504
|
+
responseEventListeners.set(name, listener);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function removeResponseEventListener(name) {
|
|
508
|
+
responseEventListeners.remove(name);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Must be kept in sync with PixelStreamingProtocol::EToPlayerMsg C++ enum.
|
|
512
|
+
const ToClientMessageType = {
|
|
513
|
+
QualityControlOwnership: 0,
|
|
514
|
+
Response: 1,
|
|
515
|
+
Command: 2,
|
|
516
|
+
FreezeFrame: 3,
|
|
517
|
+
UnfreezeFrame: 4,
|
|
518
|
+
VideoEncoderAvgQP: 5,
|
|
519
|
+
LatencyTest: 6,
|
|
520
|
+
InitialSettings: 7
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
let VideoEncoderQP = "N/A";
|
|
524
|
+
function getQueryVariable(variable)
|
|
525
|
+
{
|
|
526
|
+
|
|
527
|
+
return params[variable];
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function setupWebRtcPlayer(htmlElement, config) {
|
|
531
|
+
|
|
532
|
+
webRtcPlayerObj = new webRtcPlayer(config);
|
|
533
|
+
webRtcPlayerObj.video.className = className;
|
|
534
|
+
htmlElement.appendChild(webRtcPlayerObj.video);
|
|
535
|
+
|
|
536
|
+
webRtcPlayerObj.onWebRtcOffer = function(webrtc_type, offerStr) {
|
|
537
|
+
if (ws && ws.readyState === WS_OPEN_STATE)
|
|
538
|
+
{
|
|
539
|
+
var room_name = getQueryVariable('roomname');
|
|
540
|
+
var video_user_name = getQueryVariable('videousername');
|
|
541
|
+
|
|
542
|
+
let offersdp = JSON.stringify({
|
|
543
|
+
msg_id: 208,
|
|
544
|
+
data: {
|
|
545
|
+
rtc_type:webrtc_type,
|
|
546
|
+
offer : offerStr.sdp
|
|
547
|
+
}
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
ws.send(offersdp);
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
webRtcPlayerObj.onWebRtcCandidate = function(webrtc_type, iceCandidate) {
|
|
558
|
+
if (ws && ws.readyState === WS_OPEN_STATE) {
|
|
559
|
+
ws.send(JSON.stringify({
|
|
560
|
+
/* type: 'iceCandidate',*/
|
|
561
|
+
/*candidate: candidate*/
|
|
562
|
+
msg_id: 208,
|
|
563
|
+
data: {
|
|
564
|
+
rtc_type:webrtc_type,
|
|
565
|
+
type : 'candidate',
|
|
566
|
+
label : iceCandidate.sdpMLineIndex,
|
|
567
|
+
id : iceCandidate.sdpMid,
|
|
568
|
+
candidate : iceCandidate.candidate
|
|
569
|
+
}
|
|
570
|
+
}));
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
webRtcPlayerObj.onVideoInitialised = function() {
|
|
575
|
+
if (ws && ws.readyState === WS_OPEN_STATE) {
|
|
576
|
+
playVideoStream();
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
// webRtcPlayerObj.onDataChannelConnected = function() {
|
|
581
|
+
// if (ws && ws.readyState === WS_OPEN_STATE) {
|
|
582
|
+
// showTextOverlay('WebRTC connected, waiting for video');
|
|
583
|
+
|
|
584
|
+
// if (webRtcPlayerObj.video && webRtcPlayerObj.video.srcObject && webRtcPlayerObj.onVideoInitialised) {
|
|
585
|
+
// webRtcPlayerObj.onVideoInitialised();
|
|
586
|
+
// }
|
|
587
|
+
// }
|
|
588
|
+
// };
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
function processFreezeFrameMessage(view) {
|
|
593
|
+
// Reset freeze frame if we got a freeze frame message and we are not "receiving" yet.
|
|
594
|
+
if (!freezeFrame.receiving) {
|
|
595
|
+
freezeFrame.receiving = true;
|
|
596
|
+
freezeFrame.valid = false;
|
|
597
|
+
freezeFrame.size = 0;
|
|
598
|
+
freezeFrame.jpeg = undefined;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Extract total size of freeze frame (across all chunks)
|
|
602
|
+
freezeFrame.size = (new DataView(view.slice(1, 5).buffer)).getInt32(0, true);
|
|
603
|
+
|
|
604
|
+
// Get the jpeg part of the payload
|
|
605
|
+
let jpegBytes = view.slice(1 + 4);
|
|
606
|
+
|
|
607
|
+
// Append to existing jpeg that holds the freeze frame
|
|
608
|
+
if (freezeFrame.jpeg) {
|
|
609
|
+
let jpeg = new Uint8Array(freezeFrame.jpeg.length + jpegBytes.length);
|
|
610
|
+
jpeg.set(freezeFrame.jpeg, 0);
|
|
611
|
+
jpeg.set(jpegBytes, freezeFrame.jpeg.length);
|
|
612
|
+
freezeFrame.jpeg = jpeg;
|
|
613
|
+
}
|
|
614
|
+
// No existing freeze frame jpeg, make one
|
|
615
|
+
else {
|
|
616
|
+
freezeFrame.jpeg = jpegBytes;
|
|
617
|
+
freezeFrame.receiving = true;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// Uncomment for debug
|
|
621
|
+
//console.log(`Received freeze frame chunk: ${freezeFrame.jpeg.length}/${freezeFrame.size}`);
|
|
622
|
+
|
|
623
|
+
// Finished receiving freeze frame, we can show it now
|
|
624
|
+
if (freezeFrame.jpeg.length === freezeFrame.size) {
|
|
625
|
+
freezeFrame.receiving = false;
|
|
626
|
+
freezeFrame.valid = true;
|
|
627
|
+
showFreezeFrame();
|
|
628
|
+
}
|
|
629
|
+
// We received more data than the freeze frame payload message indicate (this is an error)
|
|
630
|
+
else if (freezeFrame.jpeg.length > freezeFrame.size) {
|
|
631
|
+
console.error(`received bigger freeze frame than advertised: ${freezeFrame.jpeg.length}/${freezeFrame.size}`);
|
|
632
|
+
freezeFrame.jpeg = undefined;
|
|
633
|
+
freezeFrame.receiving = false;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// webRtcPlayerObj.onDataChannelMessage = function(data) {
|
|
638
|
+
// let view = new Uint8Array(data);
|
|
639
|
+
|
|
640
|
+
// if (view[0] === ToClientMessageType.QualityControlOwnership) {
|
|
641
|
+
// let ownership = view[1] === 0 ? false : true;
|
|
642
|
+
// console.log("Received quality controller message, will control quality: " + ownership);
|
|
643
|
+
// // If we own the quality control, we can't relenquish it. We only loose
|
|
644
|
+
// // quality control when another peer asks for it
|
|
645
|
+
// if (qualityControlOwnershipCheckBox !== null) {
|
|
646
|
+
// qualityControlOwnershipCheckBox.disabled = ownership;
|
|
647
|
+
// qualityControlOwnershipCheckBox.checked = ownership;
|
|
648
|
+
// }
|
|
649
|
+
// } else if (view[0] === ToClientMessageType.Response) {
|
|
650
|
+
// let response = new TextDecoder("utf-16").decode(data.slice(1));
|
|
651
|
+
// for (let listener of responseEventListeners.values()) {
|
|
652
|
+
// listener(response);
|
|
653
|
+
// }
|
|
654
|
+
// } else if (view[0] === ToClientMessageType.Command) {
|
|
655
|
+
// let commandAsString = new TextDecoder("utf-16").decode(data.slice(1));
|
|
656
|
+
// console.log(commandAsString);
|
|
657
|
+
// let command = JSON.parse(commandAsString);
|
|
658
|
+
// if (command.command === 'onScreenKeyboard') {
|
|
659
|
+
// showOnScreenKeyboard(command);
|
|
660
|
+
// }
|
|
661
|
+
// } else if (view[0] === ToClientMessageType.FreezeFrame) {
|
|
662
|
+
// processFreezeFrameMessage(view);
|
|
663
|
+
// } else if (view[0] === ToClientMessageType.UnfreezeFrame) {
|
|
664
|
+
// invalidateFreezeFrameOverlay();
|
|
665
|
+
// } else if (view[0] === ToClientMessageType.VideoEncoderAvgQP) {
|
|
666
|
+
// VideoEncoderQP = new TextDecoder("utf-16").decode(data.slice(1));
|
|
667
|
+
// //console.log(`received VideoEncoderAvgQP ${VideoEncoderQP}`);
|
|
668
|
+
// } else if (view[0] == ToClientMessageType.LatencyTest) {
|
|
669
|
+
// let latencyTimingsAsString = new TextDecoder("utf-16").decode(data.slice(1));
|
|
670
|
+
// console.log("Got latency timings from UE.")
|
|
671
|
+
// console.log(latencyTimingsAsString);
|
|
672
|
+
// let latencyTimingsFromUE = JSON.parse(latencyTimingsAsString);
|
|
673
|
+
// if (webRtcPlayerObj) {
|
|
674
|
+
// webRtcPlayerObj.latencyTestTimings.SetUETimings(latencyTimingsFromUE);
|
|
675
|
+
// }
|
|
676
|
+
// } else if (view[0] == ToClientMessageType.InitialSettings) {
|
|
677
|
+
// let settingsString = new TextDecoder("utf-16").decode(data.slice(1));
|
|
678
|
+
// let settingsJSON = JSON.parse(settingsString);
|
|
679
|
+
|
|
680
|
+
// // reminder bitrates are sent in bps but displayed in kbps
|
|
681
|
+
|
|
682
|
+
// if (settingsJSON.Encoder) {
|
|
683
|
+
// document.getElementById('encoder-rate-control').value = settingsJSON.Encoder.RateControl;
|
|
684
|
+
// document.getElementById('encoder-target-bitrate-text').value = settingsJSON.Encoder.TargetBitrate > 0 ? settingsJSON.Encoder.TargetBitrate / 1000 : settingsJSON.Encoder.TargetBitrate;
|
|
685
|
+
// document.getElementById('encoder-max-bitrate-text').value = settingsJSON.Encoder.MaxBitrate > 0 ? settingsJSON.Encoder.MaxBitrate / 1000 : settingsJSON.Encoder.MaxBitrate;
|
|
686
|
+
// document.getElementById('encoder-min-qp-text').value = settingsJSON.Encoder.MinQP;
|
|
687
|
+
// document.getElementById('encoder-max-qp-text').value = settingsJSON.Encoder.MaxQP;
|
|
688
|
+
// document.getElementById('encoder-filler-data-tgl').checked = settingsJSON.Encoder.FillerData == 1;
|
|
689
|
+
// document.getElementById('encoder-multipass').value = settingsJSON.Encoder.MultiPass;
|
|
690
|
+
// }
|
|
691
|
+
// if (settingsJSON.WebRTC) {
|
|
692
|
+
// document.getElementById('webrtc-degradation-pref').value = settingsJSON.WebRTC.DegradationPref;
|
|
693
|
+
// document.getElementById("webrtc-max-fps-text").value = settingsJSON.WebRTC.MaxFPS;
|
|
694
|
+
// document.getElementById("webrtc-min-bitrate-text").value = settingsJSON.WebRTC.MinBitrate / 1000;
|
|
695
|
+
// document.getElementById("webrtc-max-bitrate-text").value = settingsJSON.WebRTC.MaxBitrate / 1000;
|
|
696
|
+
// document.getElementById("webrtc-low-qp-text").value = settingsJSON.WebRTC.LowQP;
|
|
697
|
+
// document.getElementById("webrtc-high-qp-text").value = settingsJSON.WebRTC.HighQP;
|
|
698
|
+
// }
|
|
699
|
+
// } else {
|
|
700
|
+
// console.error(`unrecognized data received, packet ID ${view[0]}`);
|
|
701
|
+
// }
|
|
702
|
+
// };
|
|
703
|
+
|
|
704
|
+
videoElement = webRtcPlayerObj.video;
|
|
705
|
+
store.commit(SET_WEBRTC_OBJ, {
|
|
706
|
+
[roomId]: webRtcPlayerObj
|
|
707
|
+
});
|
|
708
|
+
// On a touch device we will need special ways to show the on-screen keyboard.
|
|
709
|
+
if ('ontouchstart' in document.documentElement) {
|
|
710
|
+
createOnScreenKeyboardHelpers(htmlElement);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
createWebRtcOffer();
|
|
714
|
+
|
|
715
|
+
return webRtcPlayerObj.video;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
function setupWebRtcDataChannel(config)
|
|
720
|
+
{
|
|
721
|
+
// if (!webRtcPlayerObj)
|
|
722
|
+
// {
|
|
723
|
+
|
|
724
|
+
// console.warn('webrtcPlayer Obj == nullptr');
|
|
725
|
+
// return;
|
|
726
|
+
// }
|
|
727
|
+
webRtcDataChannelObj = new RTCPeerConnection(null);
|
|
728
|
+
webRtcDataChannelObj.addEventListener('', () => {
|
|
729
|
+
|
|
730
|
+
switch (webRtcDataChannelObj.iceConnectionState) {
|
|
731
|
+
case 'checking':
|
|
732
|
+
//this.emit('@connectionstatechange', 'connecting');
|
|
733
|
+
|
|
734
|
+
break;
|
|
735
|
+
case 'connected':
|
|
736
|
+
case 'completed':
|
|
737
|
+
//this.emit('@connectionstatechange', 'connected');
|
|
738
|
+
break;
|
|
739
|
+
case 'failed':
|
|
740
|
+
// this.emit('@connectionstatechange', 'failed');
|
|
741
|
+
break;
|
|
742
|
+
case 'disconnected':
|
|
743
|
+
// this.emit('@connectionstatechange', 'disconnected');
|
|
744
|
+
break;
|
|
745
|
+
case 'closed':
|
|
746
|
+
// this.emit('@connectionstatechange', 'closed');
|
|
747
|
+
break;
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
webRtcDataChannelObj.addEventListener('icegatheringstatechange', (state) => {
|
|
753
|
+
|
|
754
|
+
switch (webRtcDataChannelObj.iceConnectionState) {
|
|
755
|
+
case 'checking':
|
|
756
|
+
//this.emit('@connectionstatechange', 'connecting');
|
|
757
|
+
|
|
758
|
+
break;
|
|
759
|
+
case 'connected':
|
|
760
|
+
case 'completed':
|
|
761
|
+
//this.emit('@connectionstatechange', 'connected');
|
|
762
|
+
break;
|
|
763
|
+
case 'failed':
|
|
764
|
+
// this.emit('@connectionstatechange', 'failed');
|
|
765
|
+
break;
|
|
766
|
+
case 'disconnected':
|
|
767
|
+
// this.emit('@connectionstatechange', 'disconnected');
|
|
768
|
+
break;
|
|
769
|
+
case 'closed':
|
|
770
|
+
// this.emit('@connectionstatechange', 'closed');
|
|
771
|
+
break;
|
|
772
|
+
}
|
|
773
|
+
});
|
|
774
|
+
webRtcDataChannelObj.addEventListener('onicecandidate', (e)=>{
|
|
775
|
+
if (ws && ws.readyState === WS_OPEN_STATE) {
|
|
776
|
+
ws.send(JSON.stringify({
|
|
777
|
+
/* type: 'iceCandidate',*/
|
|
778
|
+
/*candidate: candidate*/
|
|
779
|
+
msg_id: 208,
|
|
780
|
+
data: {
|
|
781
|
+
rtc_type:1,
|
|
782
|
+
type : 'candidate',
|
|
783
|
+
label : e.sdpMLineIndex,
|
|
784
|
+
id : e.sdpMid,
|
|
785
|
+
candidate : e.candidate
|
|
786
|
+
}
|
|
787
|
+
}));
|
|
788
|
+
}
|
|
789
|
+
});
|
|
790
|
+
// webRtcDataChannelObj = new webRtcDataChannel(config);
|
|
791
|
+
// webRtcDataChannelObj.onWebRtcDataChannelOffer = function(webrtc_type, offerStr)
|
|
792
|
+
//{
|
|
793
|
+
// if (ws && ws.readyState === WS_OPEN_STATE)
|
|
794
|
+
// {
|
|
795
|
+
// var room_name = getQueryVariable('roomname');
|
|
796
|
+
// var video_user_name = getQueryVariable('videousername');
|
|
797
|
+
// var codecs = getQueryVariable('codec');;
|
|
798
|
+
//
|
|
799
|
+
// console.log('datachannel cs --> offer : = ', offerStr);
|
|
800
|
+
// let offersdp = JSON.stringify({
|
|
801
|
+
// msg_id: 208,
|
|
802
|
+
// data: {
|
|
803
|
+
// rtc_type: webrtc_type,
|
|
804
|
+
// offer : offerStr.sdp
|
|
805
|
+
// }
|
|
806
|
+
// });
|
|
807
|
+
// console.log(`-> SS: offer:\n${offersdp}`);
|
|
808
|
+
//
|
|
809
|
+
//
|
|
810
|
+
//
|
|
811
|
+
//
|
|
812
|
+
// ws.send(offersdp);
|
|
813
|
+
// }
|
|
814
|
+
//};
|
|
815
|
+
|
|
816
|
+
// webRtcDataChannelObj.onWebRtcDataChannelOCandidate = function(webrtc_type, iceCandidate) {
|
|
817
|
+
// if (ws && ws.readyState === WS_OPEN_STATE) {
|
|
818
|
+
// console.log(`datachannel -> SS: iceCandidate\n${JSON.stringify(iceCandidate, undefined, 4)}`);
|
|
819
|
+
// ws.send(JSON.stringify({
|
|
820
|
+
// /* type: 'iceCandidate',*/
|
|
821
|
+
// /*candidate: candidate*/
|
|
822
|
+
// msg_id: 208,
|
|
823
|
+
// data: {
|
|
824
|
+
// rtc_type:webrtc_type,
|
|
825
|
+
// type : 'candidate',
|
|
826
|
+
// label : iceCandidate.sdpMLineIndex,
|
|
827
|
+
// id : iceCandidate.sdpMid,
|
|
828
|
+
// candidate : iceCandidate.candidate
|
|
829
|
+
// }
|
|
830
|
+
// }));
|
|
831
|
+
// }
|
|
832
|
+
// };
|
|
833
|
+
|
|
834
|
+
// webRtcDataChannelObj.onVideoDataChannelOInitialised = function() {
|
|
835
|
+
// if (ws && ws.readyState === WS_OPEN_STATE) {
|
|
836
|
+
// if (shouldShowPlayOverlay) {
|
|
837
|
+
// showPlayOverlay();
|
|
838
|
+
// resizePlayerStyle();
|
|
839
|
+
// }
|
|
840
|
+
// else {
|
|
841
|
+
// resizePlayerStyle();
|
|
842
|
+
// playVideoStream();
|
|
843
|
+
// }
|
|
844
|
+
// }
|
|
845
|
+
// };
|
|
846
|
+
//
|
|
847
|
+
// webRtcDataChannelObj.onDataChannelDataChannelOConnected = function() {
|
|
848
|
+
// if (ws && ws.readyState === WS_OPEN_STATE)
|
|
849
|
+
// {
|
|
850
|
+
// showTextOverlay('WebRTC connected, waiting for video');
|
|
851
|
+
//
|
|
852
|
+
// if (webRtcPlayerObj.video && webRtcPlayerObj.video.srcObject && webRtcPlayerObj.onVideoInitialised) {
|
|
853
|
+
// webRtcPlayerObj.onVideoInitialised();
|
|
854
|
+
// }
|
|
855
|
+
// }
|
|
856
|
+
// };
|
|
857
|
+
// createWebRtcDataChannelOffer();
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
function onWebRtcAnswer(webRTCData) {
|
|
863
|
+
webRtcPlayerObj.receiveAnswer(webRTCData);
|
|
864
|
+
|
|
865
|
+
let printInterval = 5 * 60 * 1000; /*Print every 5 minutes*/
|
|
866
|
+
let nextPrintDuration = printInterval;
|
|
867
|
+
|
|
868
|
+
webRtcPlayerObj.onAggregatedStats = (aggregatedStats) => {
|
|
869
|
+
let numberFormat = new Intl.NumberFormat(window.navigator.language, {
|
|
870
|
+
maximumFractionDigits: 0
|
|
871
|
+
});
|
|
872
|
+
let timeFormat = new Intl.NumberFormat(window.navigator.language, {
|
|
873
|
+
maximumFractionDigits: 0,
|
|
874
|
+
minimumIntegerDigits: 2
|
|
875
|
+
});
|
|
876
|
+
|
|
877
|
+
// Calculate duration of run
|
|
878
|
+
let runTime = (aggregatedStats.timestamp - aggregatedStats.timestampStart) / 1000;
|
|
879
|
+
let timeValues = [];
|
|
880
|
+
let timeDurations = [60, 60];
|
|
881
|
+
for (let timeIndex = 0; timeIndex < timeDurations.length; timeIndex++) {
|
|
882
|
+
timeValues.push(runTime % timeDurations[timeIndex]);
|
|
883
|
+
runTime = runTime / timeDurations[timeIndex];
|
|
884
|
+
}
|
|
885
|
+
timeValues.push(runTime);
|
|
886
|
+
|
|
887
|
+
let runTimeSeconds = timeValues[0];
|
|
888
|
+
let runTimeMinutes = Math.floor(timeValues[1]);
|
|
889
|
+
let runTimeHours = Math.floor([timeValues[2]]);
|
|
890
|
+
|
|
891
|
+
receivedBytesMeasurement = 'B';
|
|
892
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
893
|
+
receivedBytes = aggregatedStats.hasOwnProperty('bytesReceived') ? aggregatedStats.bytesReceived : 0;
|
|
894
|
+
let dataMeasurements = ['kB', 'MB', 'GB'];
|
|
895
|
+
for (let index = 0; index < dataMeasurements.length; index++) {
|
|
896
|
+
if (receivedBytes < 100 * 1000)
|
|
897
|
+
break;
|
|
898
|
+
receivedBytes = receivedBytes / 1000;
|
|
899
|
+
receivedBytesMeasurement = dataMeasurements[index];
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
const orangeQP = 26;
|
|
903
|
+
const redQP = 35;
|
|
904
|
+
|
|
905
|
+
if (print_stats) {
|
|
906
|
+
if (aggregatedStats.timestampStart) {
|
|
907
|
+
if ((aggregatedStats.timestamp - aggregatedStats.timestampStart) > nextPrintDuration) {
|
|
908
|
+
if (ws && ws.readyState === WS_OPEN_STATE) {
|
|
909
|
+
ws.send(JSON.stringify({
|
|
910
|
+
type: 'stats',
|
|
911
|
+
data: aggregatedStats
|
|
912
|
+
}));
|
|
913
|
+
}
|
|
914
|
+
nextPrintDuration += printInterval;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
|
|
920
|
+
webRtcPlayerObj.aggregateStats(1 * 1000 /*Check every 1 second*/ );
|
|
921
|
+
|
|
922
|
+
webRtcPlayerObj.latencyTestTimings.OnAllLatencyTimingsReady = function(timings) {
|
|
923
|
+
|
|
924
|
+
if (!timings.BrowserReceiptTimeMs) {
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
let latencyExcludingDecode = timings.BrowserReceiptTimeMs - timings.TestStartTimeMs;
|
|
929
|
+
let uePixelStreamLatency = timings.UEPreEncodeTimeMs == 0 || timings.UEPreCaptureTimeMs == 0 ? "???" : timings.UEPostEncodeTimeMs - timings.UEPreCaptureTimeMs;
|
|
930
|
+
let captureLatency = timings.UEPostCaptureTimeMs - timings.UEPreCaptureTimeMs;
|
|
931
|
+
let encodeLatency = timings.UEPostEncodeTimeMs - timings.UEPreEncodeTimeMs;
|
|
932
|
+
let ueLatency = timings.UETransmissionTimeMs - timings.UEReceiptTimeMs;
|
|
933
|
+
let networkLatency = latencyExcludingDecode - ueLatency;
|
|
934
|
+
let browserSendLatency = latencyExcludingDecode - networkLatency - ueLatency;
|
|
935
|
+
|
|
936
|
+
//these ones depend on FrameDisplayDeltaTimeMs
|
|
937
|
+
let endToEndLatency = null;
|
|
938
|
+
let browserSideLatency = null;
|
|
939
|
+
|
|
940
|
+
if (timings.FrameDisplayDeltaTimeMs && timings.BrowserReceiptTimeMs) {
|
|
941
|
+
endToEndLatency = timings.FrameDisplayDeltaTimeMs + latencyExcludingDecode;
|
|
942
|
+
browserSideLatency = endToEndLatency - networkLatency - ueLatency;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
function onWebRtcDataChannelAnswer(webRtcDataChannelData)
|
|
950
|
+
{
|
|
951
|
+
if (webRtcDataChannelObj)
|
|
952
|
+
{
|
|
953
|
+
///console.log(answer);
|
|
954
|
+
// var answerDesc = new RTCSessionDescription(webRtcDataChannelData);
|
|
955
|
+
webRtcDataChannelObj.setRemoteDescription(webRtcDataChannelData);
|
|
956
|
+
|
|
957
|
+
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
function onWebRtcIce(iceCandidate) {
|
|
962
|
+
if (webRtcPlayerObj)
|
|
963
|
+
webRtcPlayerObj.handleCandidateFromServer(iceCandidate);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
function onWebRtcDataChannelIce(iceCandidate)
|
|
967
|
+
{
|
|
968
|
+
if (webRtcDataChannelObj)
|
|
969
|
+
{
|
|
970
|
+
|
|
971
|
+
let candidate = new RTCIceCandidate(iceCandidate);
|
|
972
|
+
webRtcDataChannelObj.addIceCandidate(candidate);
|
|
973
|
+
// webRtcDataChannelObj.handleCandidateFromServer(iceCandidate);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
let styleWidth;
|
|
978
|
+
let styleHeight;
|
|
979
|
+
let styleTop;
|
|
980
|
+
let styleLeft;
|
|
981
|
+
let styleCursor = 'default';
|
|
982
|
+
let styleAdditional;
|
|
983
|
+
|
|
984
|
+
const ControlSchemeType = {
|
|
985
|
+
// A mouse can lock inside the WebRTC player so the user can simply move the
|
|
986
|
+
// mouse to control the orientation of the camera. The user presses the
|
|
987
|
+
// Escape key to unlock the mouse.
|
|
988
|
+
LockedMouse: 0,
|
|
989
|
+
|
|
990
|
+
// A mouse can hover over the WebRTC player so the user needs to click and
|
|
991
|
+
// drag to control the orientation of the camera.
|
|
992
|
+
HoveringMouse: 1
|
|
993
|
+
};
|
|
994
|
+
|
|
995
|
+
let inputOptions = {
|
|
996
|
+
// The control scheme controls the behaviour of the mouse when it interacts
|
|
997
|
+
// with the WebRTC player.
|
|
998
|
+
controlScheme: ControlSchemeType.LockedMouse,
|
|
999
|
+
|
|
1000
|
+
// Browser keys are those which are typically used by the browser UI. We
|
|
1001
|
+
// usually want to suppress these to allow, for example, UE4 to show shader
|
|
1002
|
+
// complexity with the F5 key without the web page refreshing.
|
|
1003
|
+
suppressBrowserKeys: true,
|
|
1004
|
+
|
|
1005
|
+
// UE4 has a faketouches option which fakes a single finger touch when the
|
|
1006
|
+
// user drags with their mouse. We may perform the reverse; a single finger
|
|
1007
|
+
// touch may be converted into a mouse drag UE4 side. This allows a
|
|
1008
|
+
// non-touch application to be controlled partially via a touch device.
|
|
1009
|
+
fakeMouseWithTouches: false
|
|
1010
|
+
};
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
// Fix for bug in iOS where windowsize is not correct at instance or orientation change
|
|
1014
|
+
// https://github.com/dimsemenov/PhotoSwipe/issues/1315
|
|
1015
|
+
let _orientationChangeTimeout;
|
|
1016
|
+
|
|
1017
|
+
function onOrientationChange(event) {
|
|
1018
|
+
clearTimeout(_orientationChangeTimeout);
|
|
1019
|
+
_orientationChangeTimeout = setTimeout(function() {
|
|
1020
|
+
// resizePlayerStyle();
|
|
1021
|
+
}, 500);
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// Must be kept in sync with PixelStreamingProtocol::EToUE4Msg C++ enum.
|
|
1025
|
+
const MessageType = {
|
|
1026
|
+
|
|
1027
|
+
/**********************************************************************/
|
|
1028
|
+
|
|
1029
|
+
/*
|
|
1030
|
+
* Control Messages. Range = 0..49.
|
|
1031
|
+
*/
|
|
1032
|
+
IFrameRequest: 0,
|
|
1033
|
+
RequestQualityControl: 1,
|
|
1034
|
+
MaxFpsRequest: 2,
|
|
1035
|
+
AverageBitrateRequest: 3,
|
|
1036
|
+
StartStreaming: 4,
|
|
1037
|
+
StopStreaming: 5,
|
|
1038
|
+
LatencyTest: 6,
|
|
1039
|
+
RequestInitialSettings: 7,
|
|
1040
|
+
|
|
1041
|
+
/**********************************************************************/
|
|
1042
|
+
|
|
1043
|
+
/*
|
|
1044
|
+
* Input Messages. Range = 50..89.
|
|
1045
|
+
*/
|
|
1046
|
+
|
|
1047
|
+
// Generic Input Messages. Range = 50..59.
|
|
1048
|
+
UIInteraction: 50,
|
|
1049
|
+
Command: 51,
|
|
1050
|
+
|
|
1051
|
+
// Keyboard Input Message. Range = 60..69.
|
|
1052
|
+
KeyDown: 60,
|
|
1053
|
+
KeyUp: 61,
|
|
1054
|
+
KeyPress: 62,
|
|
1055
|
+
|
|
1056
|
+
// Mouse Input Messages. Range = 70..79.
|
|
1057
|
+
MouseEnter: 70,
|
|
1058
|
+
MouseLeave: 71,
|
|
1059
|
+
MouseDown: 72,
|
|
1060
|
+
MouseUp: 73,
|
|
1061
|
+
MouseMove: 74,
|
|
1062
|
+
MouseWheel: 75,
|
|
1063
|
+
|
|
1064
|
+
// Touch Input Messages. Range = 80..89.
|
|
1065
|
+
TouchStart: 80,
|
|
1066
|
+
TouchEnd: 81,
|
|
1067
|
+
TouchMove: 82,
|
|
1068
|
+
|
|
1069
|
+
// Gamepad Input Messages. Range = 90..99
|
|
1070
|
+
GamepadButtonPressed: 90,
|
|
1071
|
+
GamepadButtonReleased: 91,
|
|
1072
|
+
GamepadAnalog: 92
|
|
1073
|
+
|
|
1074
|
+
/**************************************************************************/
|
|
1075
|
+
};
|
|
1076
|
+
|
|
1077
|
+
// A generic message has a type and a descriptor.
|
|
1078
|
+
function emitDescriptor(messageType, descriptor) {
|
|
1079
|
+
// Convert the dscriptor object into a JSON string.
|
|
1080
|
+
let descriptorAsString = JSON.stringify(descriptor);
|
|
1081
|
+
|
|
1082
|
+
// Add the UTF-16 JSON string to the array byte buffer, going two bytes at
|
|
1083
|
+
// a time.
|
|
1084
|
+
let data = new DataView(new ArrayBuffer(1 + 2 + 2 * descriptorAsString.length));
|
|
1085
|
+
let byteIdx = 0;
|
|
1086
|
+
data.setUint8(byteIdx, messageType);
|
|
1087
|
+
byteIdx++;
|
|
1088
|
+
data.setUint16(byteIdx, descriptorAsString.length, true);
|
|
1089
|
+
byteIdx += 2;
|
|
1090
|
+
for (let i = 0; i < descriptorAsString.length; i++) {
|
|
1091
|
+
data.setUint16(byteIdx, descriptorAsString.charCodeAt(i), true);
|
|
1092
|
+
byteIdx += 2;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
//let str = data.getString(0, data.byteLength, "utf-8");
|
|
1096
|
+
// console.log('str ===== ', str);
|
|
1097
|
+
sendInputData(data.buffer);
|
|
1098
|
+
// sendInputData({Type : });
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
// A UI interation will occur when the user presses a button powered by
|
|
1102
|
+
// JavaScript as opposed to pressing a button which is part of the pixel
|
|
1103
|
+
// streamed UI from the UE4 client.
|
|
1104
|
+
function emitUIInteraction(descriptor) {
|
|
1105
|
+
emitDescriptor(MessageType.UIInteraction, descriptor);
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
// A build-in command can be sent to UE4 client. The commands are defined by a
|
|
1109
|
+
// JSON descriptor and will be executed automatically.
|
|
1110
|
+
// The currently supported commands are:
|
|
1111
|
+
//
|
|
1112
|
+
// 1. A command to run any console command:
|
|
1113
|
+
// "{ ConsoleCommand: <string> }"
|
|
1114
|
+
//
|
|
1115
|
+
// 2. A command to change the resolution to the given width and height.
|
|
1116
|
+
// "{ Resolution.Width: <value>, Resolution.Height: <value> } }"
|
|
1117
|
+
//
|
|
1118
|
+
function emitCommand(descriptor) {
|
|
1119
|
+
emitDescriptor(MessageType.Command, descriptor);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
function requestInitialSettings() {
|
|
1123
|
+
sendInputData(new Uint8Array([MessageType.RequestInitialSettings]).buffer);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
function requestQualityControl() {
|
|
1127
|
+
sendInputData(new Uint8Array([MessageType.RequestQualityControl]).buffer);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
let playerElementClientRect = undefined;
|
|
1131
|
+
let normalizeAndQuantizeUnsigned = undefined;
|
|
1132
|
+
let normalizeAndQuantizeSigned = undefined;
|
|
1133
|
+
|
|
1134
|
+
function setupNormalizeAndQuantize() {
|
|
1135
|
+
|
|
1136
|
+
if (playerElement && videoElement.length > 0) {
|
|
1137
|
+
let playerAspectRatio = playerElement.clientHeight / playerElement.clientWidth;
|
|
1138
|
+
let videoAspectRatio = videoElement[0].videoHeight / videoElement[0].videoWidth;
|
|
1139
|
+
// console.log('videoElement[0].videoHeight = ' + videoElement[0].videoHeight + ', videoElement[0].videoWidth = ' + videoElement[0].videoWidth);
|
|
1140
|
+
// console.log('playerAspectRatio =', playerAspectRatio);
|
|
1141
|
+
// console.log('videoAspectRatio =', videoAspectRatio);
|
|
1142
|
+
// Unsigned XY positions are the ratio (0.0..1.0) along a viewport axis,
|
|
1143
|
+
// quantized into an uint16 (0..65536).
|
|
1144
|
+
// Signed XY deltas are the ratio (-1.0..1.0) along a viewport axis,
|
|
1145
|
+
// quantized into an int16 (-32767..32767).
|
|
1146
|
+
// This allows the browser viewport and client viewport to have a different
|
|
1147
|
+
// size.
|
|
1148
|
+
// Hack: Currently we set an out-of-range position to an extreme (65535)
|
|
1149
|
+
// as we can't yet accurately detect mouse enter and leave events
|
|
1150
|
+
// precisely inside a video with an aspect ratio which causes mattes.
|
|
1151
|
+
if (playerAspectRatio > videoAspectRatio)
|
|
1152
|
+
{
|
|
1153
|
+
|
|
1154
|
+
let ratio = playerAspectRatio / videoAspectRatio;
|
|
1155
|
+
// console.log('ratio = ', ratio);
|
|
1156
|
+
// Unsigned.
|
|
1157
|
+
normalizeAndQuantizeUnsigned = (x, y) => {
|
|
1158
|
+
let normalizedX = x / playerElement.clientWidth;
|
|
1159
|
+
let normalizedY = ratio * (y / playerElement.clientHeight - 0.5) + 0.5;
|
|
1160
|
+
// console.log('normalizedX = ' + normalizedX + ', normalizedY = '+ normalizedY);
|
|
1161
|
+
if (normalizedX < 0.0 || normalizedX > 1.0 || normalizedY < 0.0 || normalizedY > 1.0)
|
|
1162
|
+
{
|
|
1163
|
+
return {
|
|
1164
|
+
inRange: false,
|
|
1165
|
+
x: 65535,
|
|
1166
|
+
y: 65535
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
else
|
|
1170
|
+
{
|
|
1171
|
+
return {
|
|
1172
|
+
inRange: true,
|
|
1173
|
+
x: normalizedX * 65536,
|
|
1174
|
+
y: normalizedY * 65536
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
};
|
|
1178
|
+
unquantizeAndDenormalizeUnsigned = (x, y) => {
|
|
1179
|
+
let normalizedX = x / 65536;
|
|
1180
|
+
let normalizedY = (y / 65536 - 0.5) / ratio + 0.5;
|
|
1181
|
+
return {
|
|
1182
|
+
x: normalizedX * playerElement.clientWidth,
|
|
1183
|
+
y: normalizedY * playerElement.clientHeight
|
|
1184
|
+
};
|
|
1185
|
+
};
|
|
1186
|
+
// Signed.
|
|
1187
|
+
normalizeAndQuantizeSigned = (x, y) => {
|
|
1188
|
+
let normalizedX = x / (0.5 * playerElement.clientWidth);
|
|
1189
|
+
let normalizedY = (ratio * y) / (0.5 * playerElement.clientHeight);
|
|
1190
|
+
return {
|
|
1191
|
+
x: normalizedX * 32767,
|
|
1192
|
+
y: normalizedY * 32767
|
|
1193
|
+
};
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
else
|
|
1197
|
+
{
|
|
1198
|
+
|
|
1199
|
+
let ratio = videoAspectRatio / playerAspectRatio;
|
|
1200
|
+
// Unsigned.
|
|
1201
|
+
normalizeAndQuantizeUnsigned = (x, y) => {
|
|
1202
|
+
let normalizedX = ratio * (x / playerElement.clientWidth - 0.5) + 0.5;
|
|
1203
|
+
let normalizedY = y / playerElement.clientHeight;
|
|
1204
|
+
if (normalizedX < 0.0 || normalizedX > 1.0 || normalizedY < 0.0 || normalizedY > 1.0) {
|
|
1205
|
+
return {
|
|
1206
|
+
inRange: false,
|
|
1207
|
+
x: 65535,
|
|
1208
|
+
y: 65535
|
|
1209
|
+
};
|
|
1210
|
+
} else {
|
|
1211
|
+
return {
|
|
1212
|
+
inRange: true,
|
|
1213
|
+
x: normalizedX * 65536,
|
|
1214
|
+
y: normalizedY * 65536
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
};
|
|
1218
|
+
// eslint-disable-next-line no-undef
|
|
1219
|
+
unquantizeAndDenormalizeUnsigned = (x, y) => {
|
|
1220
|
+
let normalizedX = (x / 65536 - 0.5) / ratio + 0.5;
|
|
1221
|
+
let normalizedY = y / 65536;
|
|
1222
|
+
return {
|
|
1223
|
+
x: normalizedX * playerElement.clientWidth,
|
|
1224
|
+
y: normalizedY * playerElement.clientHeight
|
|
1225
|
+
};
|
|
1226
|
+
};
|
|
1227
|
+
// Signed.
|
|
1228
|
+
normalizeAndQuantizeSigned = (x, y) => {
|
|
1229
|
+
let normalizedX = (ratio * x) / (0.5 * playerElement.clientWidth);
|
|
1230
|
+
let normalizedY = y / (0.5 * playerElement.clientHeight);
|
|
1231
|
+
return {
|
|
1232
|
+
x: normalizedX * 32767,
|
|
1233
|
+
y: normalizedY * 32767
|
|
1234
|
+
};
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
function createOnScreenKeyboardHelpers(htmlElement) {
|
|
1241
|
+
if (document.getElementById('hiddenInput') === null) {
|
|
1242
|
+
hiddenInput = document.createElement('input');
|
|
1243
|
+
hiddenInput.id = 'hiddenInput';
|
|
1244
|
+
hiddenInput.maxLength = 0;
|
|
1245
|
+
htmlElement.appendChild(hiddenInput);
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
if (document.getElementById('editTextButton') === null) {
|
|
1249
|
+
editTextButton = document.createElement('button');
|
|
1250
|
+
editTextButton.id = 'editTextButton';
|
|
1251
|
+
editTextButton.innerHTML = 'edit text';
|
|
1252
|
+
htmlElement.appendChild(editTextButton);
|
|
1253
|
+
|
|
1254
|
+
// Hide the 'edit text' button.
|
|
1255
|
+
editTextButton.classList.add('hiddenState');
|
|
1256
|
+
|
|
1257
|
+
editTextButton.addEventListener('click', function() {
|
|
1258
|
+
// Show the on-screen keyboard.
|
|
1259
|
+
hiddenInput.focus();
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
|
|
1265
|
+
|
|
1266
|
+
|
|
1267
|
+
|
|
1268
|
+
function onExpandOverlay_Click( /* e */ ) {
|
|
1269
|
+
let overlay = document.getElementById('overlay');
|
|
1270
|
+
overlay.classList.toggle("overlay-shown");
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
function start() {
|
|
1274
|
+
// update "quality status" to "disconnected" state
|
|
1275
|
+
connect();
|
|
1276
|
+
updateKickButton(0);
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
function updateKickButton(playersCount) {
|
|
1280
|
+
let kickButton = document.getElementById('kick-other-players-button');
|
|
1281
|
+
if (kickButton)
|
|
1282
|
+
kickButton.value = `Kick (${playersCount})`;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
function connect() {
|
|
1286
|
+
"use strict";
|
|
1287
|
+
|
|
1288
|
+
window.WebSocket = window.WebSocket || window.MozWebSocket;
|
|
1289
|
+
|
|
1290
|
+
if (!window.WebSocket) {
|
|
1291
|
+
alert('Your browser doesn\'t support WebSocket');
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
//window.location.href.replace('http://', 'ws://').replace('https://', 'wss://')
|
|
1296
|
+
var rtc_ip = getQueryVariable('rtc_ip');
|
|
1297
|
+
var rtc_port = getQueryVariable('rtc_port');
|
|
1298
|
+
var video_user_name = getQueryVariable('videousername');
|
|
1299
|
+
var ws_url = 'ws://'+rtc_ip+':'+rtc_port +'/?peerId='+video_user_name;
|
|
1300
|
+
|
|
1301
|
+
ws = new WebSocket(ws_url);
|
|
1302
|
+
|
|
1303
|
+
ws.onmessage = function(event) {
|
|
1304
|
+
|
|
1305
|
+
let msg = JSON.parse(event.data);
|
|
1306
|
+
/*
|
|
1307
|
+
if (msg.type === 'config') {
|
|
1308
|
+
onConfig(msg);
|
|
1309
|
+
} else if (msg.type === 'playerCount') {
|
|
1310
|
+
updateKickButton(msg.count - 1);
|
|
1311
|
+
} else
|
|
1312
|
+
*/
|
|
1313
|
+
if (msg.msg_id === 1075)
|
|
1314
|
+
// eslint-disable-next-line no-mixed-spaces-and-tabs
|
|
1315
|
+
{
|
|
1316
|
+
// console.log(msg.data.sdp);
|
|
1317
|
+
onWebRtcAnswer(msg.data);
|
|
1318
|
+
/*
|
|
1319
|
+
} else if (msg.type === 'iceCandidate') {
|
|
1320
|
+
onWebRtcIce(msg.candidate);
|
|
1321
|
+
*/
|
|
1322
|
+
}
|
|
1323
|
+
else if (msg.msg_id === 211)
|
|
1324
|
+
{
|
|
1325
|
+
console.log('')
|
|
1326
|
+
}
|
|
1327
|
+
else if (msg.msg_id === 500)
|
|
1328
|
+
{
|
|
1329
|
+
if (msg.data.type === 'answer')
|
|
1330
|
+
{
|
|
1331
|
+
var answerDesc = new RTCSessionDescription({type: 'answer', sdp: msg.data.sdp});
|
|
1332
|
+
if (msg.data.rtc_type === 0)
|
|
1333
|
+
{
|
|
1334
|
+
onWebRtcAnswer(answerDesc);
|
|
1335
|
+
}
|
|
1336
|
+
else
|
|
1337
|
+
{
|
|
1338
|
+
onWebRtcDataChannelAnswer(answerDesc);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
1342
|
+
else if (msg.data.hasOwnProperty('candidate'))
|
|
1343
|
+
{
|
|
1344
|
+
//let candidate = new RTCIceCandidate({type: 'candidate', sdp: msg.data.candidate});
|
|
1345
|
+
//var candidate = new RTCIceCandidate({
|
|
1346
|
+
// sdpMLineIndex :0,
|
|
1347
|
+
// candidate: msg.data.candidate
|
|
1348
|
+
//});
|
|
1349
|
+
|
|
1350
|
+
if (msg.data.rtc_type === 0)
|
|
1351
|
+
{
|
|
1352
|
+
onWebRtcIce({sdpMid:msg.data.id, sdpMLineIndex :msg.data.label, candidate:msg.data.candidate});
|
|
1353
|
+
}
|
|
1354
|
+
else
|
|
1355
|
+
{
|
|
1356
|
+
onWebRtcDataChannelIce({sdpMid:msg.data.id, sdpMLineIndex :msg.data.label, candidate:msg.data.candidate});
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
else
|
|
1361
|
+
{
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
};
|
|
1365
|
+
|
|
1366
|
+
ws.onerror = function(event) {
|
|
1367
|
+
console.log(`WS error: ${JSON.stringify(event)}`);
|
|
1368
|
+
};
|
|
1369
|
+
|
|
1370
|
+
ws.onclose = function(event) {
|
|
1371
|
+
console.log(`WS closed: ${JSON.stringify(event.code)} - ${event.reason}`);
|
|
1372
|
+
ws = undefined;
|
|
1373
|
+
is_reconnection = true;
|
|
1374
|
+
|
|
1375
|
+
// destroy `webRtcPlayerObj` if any
|
|
1376
|
+
if (webRtcPlayerObj) {
|
|
1377
|
+
playerElement.removeChild(webRtcPlayerObj.video);
|
|
1378
|
+
webRtcPlayerObj.close();
|
|
1379
|
+
webRtcPlayerObj = undefined;
|
|
1380
|
+
}
|
|
1381
|
+
if (webRtcDataChannelObj)
|
|
1382
|
+
{
|
|
1383
|
+
webRtcDataChannelObj.close();
|
|
1384
|
+
webRtcDataChannelObj = null;
|
|
1385
|
+
}
|
|
1386
|
+
// if (webRtcDataChannelObj)
|
|
1387
|
+
{
|
|
1388
|
+
// webRtcDataChannelObj.close();
|
|
1389
|
+
// webRtcDataChannelObj = undefined;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
showTextOverlay(`Disconnected: ${event.reason}`);
|
|
1393
|
+
start()
|
|
1394
|
+
};
|
|
1395
|
+
ws.onopen = function(event)
|
|
1396
|
+
{
|
|
1397
|
+
var room_name = getQueryVariable('roomname');
|
|
1398
|
+
var video_user_name = getQueryVariable('videousername');
|
|
1399
|
+
let offersdp = JSON.stringify({
|
|
1400
|
+
msg_id: 202,
|
|
1401
|
+
data: {
|
|
1402
|
+
user_name : video_user_name.toString(),
|
|
1403
|
+
room_name : room_name.toString()
|
|
1404
|
+
}
|
|
1405
|
+
});
|
|
1406
|
+
|
|
1407
|
+
ws.send(offersdp);
|
|
1408
|
+
onConfig('');
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
// Config data received from WebRTC sender via the Cirrus web server
|
|
1413
|
+
function onConfig(config) {
|
|
1414
|
+
setupWebRtcPlayer(playerElement, config);
|
|
1415
|
+
//setupWebRtcDataChannel(config);
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
export const load = async (ele, id, obj, styleName) => {
|
|
1419
|
+
roomId = id;
|
|
1420
|
+
playerElement = ele;
|
|
1421
|
+
params = obj;
|
|
1422
|
+
// eslint-disable-next-line no-self-assign
|
|
1423
|
+
className = styleName;
|
|
1424
|
+
await start();
|
|
1425
|
+
return videoElement;
|
|
1426
|
+
}
|