// Copyright Epic Games, Inc. All Rights Reserved.
let webRtcPlayerObj = null;
let is_reconnection = false;
let connect_on_load = false;
let ws;
const WS_OPEN_STATE = 1;
// TODO: Remove this - workaround because of bug causing UE to crash when switching resolutions too quickly
let lastTimeResized = new Date().getTime();
let resizeTimeout;
let onDataChannelConnected;
let responseEventListeners = new Map();
let shouldShowPlayOverlay = true;
// A hidden input text box which is used only for focusing and opening the
// on-screen keyboard.
let hiddenInput = undefined;
let t0 = Date.now();
function log(str) {
console.log(`${Math.floor(Date.now() - t0)}: ` + str);
}
function setOverlay(htmlClass, htmlElement, onClickFunction) {
let videoPlayOverlay = document.getElementById('videoPlayOverlay');
if (!videoPlayOverlay) {
let playerDiv = document.getElementById('player');
videoPlayOverlay = document.createElement('div');
videoPlayOverlay.id = 'videoPlayOverlay';
playerDiv.appendChild(videoPlayOverlay);
}
// Remove existing html child elements so we can add the new one
while (videoPlayOverlay.lastChild) {
videoPlayOverlay.removeChild(videoPlayOverlay.lastChild);
}
if (htmlElement)
videoPlayOverlay.appendChild(htmlElement);
if (onClickFunction) {
videoPlayOverlay.addEventListener('click', function onOverlayClick(event) {
onClickFunction(event);
videoPlayOverlay.removeEventListener('click', onOverlayClick);
});
}
// Remove existing html classes so we can set the new one
let cl = videoPlayOverlay.classList;
for (let i = cl.length - 1; i >= 0; i--) {
cl.remove(cl[i]);
}
videoPlayOverlay.classList.add(htmlClass);
}
function showConnectOverlay() {
let startText = document.createElement('div');
startText.id = 'playButton';
startText.innerHTML = 'Click to start';
setOverlay('clickableState', startText, event => {
connect();
});
}
function playVideoStream() {
if (webRtcPlayerObj && webRtcPlayerObj.video) {
webRtcPlayerObj.video.play().catch(function(onRejectedReason){
console.error(onRejectedReason);
console.log("Browser does not support autoplaying video without interaction - to resolve this we are going to show the play button overlay.")
shouldShowPlayOverlay = false;
});
requestInitialSettings();
requestQualityControl();
hideOverlay();
} else {
console.error("Could not player video stream because webRtcPlayerObj.video was not valid.")
}
}
function updateAfkOverlayText() {
afk.overlay.innerHTML = '
No activity detected
Disconnecting in ' + afk.countdown + ' seconds
Click to continue
';
}
function hideOverlay() {
setOverlay('hiddenState');
}
function createWebRtcOffer() {
if (webRtcPlayerObj) {
console.log('Creating offer');
webRtcPlayerObj.createOffer();
} else {
console.log('WebRTC player not setup, cannot create offer');
}
}
function sendInputData(data) {
if (webRtcPlayerObj) {
webRtcPlayerObj.send(data);
}
}
function addResponseEventListener(name, listener) {
responseEventListeners.set(name, listener);
}
function removeResponseEventListener(name) {
responseEventListeners.remove(name);
}
// Must be kept in sync with PixelStreamingProtocol::EToPlayerMsg C++ enum.
const ToClientMessageType = {
QualityControlOwnership: 0,
Response: 1,
Command: 2,
FreezeFrame: 3,
UnfreezeFrame: 4,
VideoEncoderAvgQP: 5,
LatencyTest: 6,
InitialSettings: 7
};
let VideoEncoderQP = "N/A";
function setupWebRtcPlayer(htmlElement, config) {
webRtcPlayerObj = new webRtcPlayer(config);
htmlElement.appendChild(webRtcPlayerObj.video);
webRtcPlayerObj.onWebRtcOffer = function(offer) {
if (ws && ws.readyState === WS_OPEN_STATE) {
let offerStr = JSON.stringify(offer);
console.log(`-> SS: offer:\n${offerStr}`);
ws.send(offerStr);
}
};
webRtcPlayerObj.onWebRtcCandidate = function(candidate) {
if (ws && ws.readyState === WS_OPEN_STATE) {
console.log(`-> SS: iceCandidate\n${JSON.stringify(candidate, undefined, 4)}`);
ws.send(JSON.stringify({
type: 'iceCandidate',
candidate: candidate
}));
}
};
webRtcPlayerObj.onVideoInitialised = function() {
if (ws && ws.readyState === WS_OPEN_STATE) {
if (shouldShowPlayOverlay) {
shouldShowPlayOverlay = false;
resizePlayerStyle();
}
else {
resizePlayerStyle();
playVideoStream();
}
}
};
webRtcPlayerObj.onDataChannelConnected = function() {
if (ws && ws.readyState === WS_OPEN_STATE) {
if (webRtcPlayerObj.video && webRtcPlayerObj.video.srcObject && webRtcPlayerObj.onVideoInitialised) {
webRtcPlayerObj.onVideoInitialised();
}
}
};
registerInputs(webRtcPlayerObj.video);
createWebRtcOffer();
return webRtcPlayerObj.video;
}
function onWebRtcAnswer(webRTCData) {
webRtcPlayerObj.receiveAnswer(webRTCData);
webRtcPlayerObj.aggregateStats(1 * 1000 );
}
function onWebRtcIce(iceCandidate) {
if (webRtcPlayerObj)
webRtcPlayerObj.handleCandidateFromServer(iceCandidate);
}
let styleWidth;
let styleHeight;
let styleTop;
let styleLeft;
let styleCursor = 'default';
let styleAdditional;
const ControlSchemeType = {
// A mouse can lock inside the WebRTC player so the user can simply move the
// mouse to control the orientation of the camera. The user presses the
// Escape key to unlock the mouse.
LockedMouse: 0,
// A mouse can hover over the WebRTC player so the user needs to click and
// drag to control the orientation of the camera.
HoveringMouse: 1
};
let inputOptions = {
// The control scheme controls the behaviour of the mouse when it interacts
// with the WebRTC player.
controlScheme: ControlSchemeType.LockedMouse,
// Browser keys are those which are typically used by the browser UI. We
// usually want to suppress these to allow, for example, UE4 to show shader
// complexity with the F5 key without the web page refreshing.
suppressBrowserKeys: true,
// UE4 has a faketouches option which fakes a single finger touch when the
// user drags with their mouse. We may perform the reverse; a single finger
// touch may be converted into a mouse drag UE4 side. This allows a
// non-touch application to be controlled partially via a touch device.
fakeMouseWithTouches: false
};
function resizePlayerStyleToFillWindow(playerElement) {
let videoElement = playerElement.getElementsByTagName("VIDEO");
// Fill the player display in window, keeping picture's aspect ratio.
let windowAspectRatio = window.innerHeight / window.innerWidth;
let playerAspectRatio = playerElement.clientHeight / playerElement.clientWidth;
// We want to keep the video ratio correct for the video stream
let videoAspectRatio = videoElement.videoHeight / videoElement.videoWidth;
if (isNaN(videoAspectRatio)) {
//Video is not initialised yet so set playerElement to size of window
styleWidth = window.innerWidth;
styleHeight = window.innerHeight;
styleTop = 0;
styleLeft = 0;
playerElement.style = "top: " + styleTop + "px; left: " + styleLeft + "px; width: " + styleWidth + "px; height: " + styleHeight + "px; cursor: " + styleCursor + "; " + styleAdditional;
} else if (windowAspectRatio < playerAspectRatio) {
// Window height is the constraining factor so to keep aspect ratio change width appropriately
styleWidth = Math.floor(window.innerHeight / videoAspectRatio);
styleHeight = window.innerHeight;
styleTop = 0;
styleLeft = Math.floor((window.innerWidth - styleWidth) * 0.5);
//Video is now 100% of the playerElement, so set the playerElement style
playerElement.style = "top: " + styleTop + "px; left: " + styleLeft + "px; width: " + styleWidth + "px; height: " + styleHeight + "px; cursor: " + styleCursor + "; " + styleAdditional;
} else {
// Window width is the constraining factor so to keep aspect ratio change height appropriately
styleWidth = window.innerWidth;
styleHeight = Math.floor(window.innerWidth * videoAspectRatio);
styleTop = Math.floor((window.innerHeight - styleHeight) * 0.5);
styleLeft = 0;
//Video is now 100% of the playerElement, so set the playerElement style
playerElement.style = "top: " + styleTop + "px; left: " + styleLeft + "px; width: " + styleWidth + "px; height: " + styleHeight + "px; cursor: " + styleCursor + "; " + styleAdditional;
}
}
function resizePlayerStyleToActualSize(playerElement) {
let videoElement = playerElement.getElementsByTagName("VIDEO");
if (videoElement.length > 0) {
// Display image in its actual size
styleWidth = videoElement[0].videoWidth;
styleHeight = videoElement[0].videoHeight;
let Top = Math.floor((window.innerHeight - styleHeight) * 0.5);
let Left = Math.floor((window.innerWidth - styleWidth) * 0.5);
styleTop = (Top > 0) ? Top : 0;
styleLeft = (Left > 0) ? Left : 0;
//Video is now 100% of the playerElement, so set the playerElement style
playerElement.style = "top: " + styleTop + "px; left: " + styleLeft + "px; width: " + styleWidth + "px; height: " + styleHeight + "px; cursor: " + styleCursor + "; " + styleAdditional;
}
}
function resizePlayerStyle(event) {
let playerElement = document.getElementById('player');
if (!playerElement)
return;
resizePlayerStyleToFillWindow(playerElement);
//resizePlayerStyleToActualSize(playerElement);
setupMouseAndFreezeFrame(playerElement)
}
function setupMouseAndFreezeFrame(playerElement) {
// Calculating and normalizing positions depends on the width and height of
// the player.
playerElementClientRect = playerElement.getBoundingClientRect();
setupNormalizeAndQuantize();
}
// Must be kept in sync with PixelStreamingProtocol::EToUE4Msg C++ enum.
const MessageType = {
/**********************************************************************/
/*
* Control Messages. Range = 0..49.
*/
IFrameRequest: 0,
RequestQualityControl: 1,
MaxFpsRequest: 2,
AverageBitrateRequest: 3,
StartStreaming: 4,
StopStreaming: 5,
LatencyTest: 6,
RequestInitialSettings: 7,
/**********************************************************************/
/*
* Input Messages. Range = 50..89.
*/
// Generic Input Messages. Range = 50..59.
UIInteraction: 50,
Command: 51,
// Keyboard Input Message. Range = 60..69.
KeyDown: 60,
KeyUp: 61,
KeyPress: 62,
// Mouse Input Messages. Range = 70..79.
MouseEnter: 70,
MouseLeave: 71,
MouseDown: 72,
MouseUp: 73,
MouseMove: 74,
MouseWheel: 75,
// Touch Input Messages. Range = 80..89.
TouchStart: 80,
TouchEnd: 81,
TouchMove: 82,
// Gamepad Input Messages. Range = 90..99
GamepadButtonPressed: 90,
GamepadButtonReleased: 91,
GamepadAnalog: 92
/**************************************************************************/
};
function requestInitialSettings() {
sendInputData(new Uint8Array([MessageType.RequestInitialSettings]).buffer);
}
function requestQualityControl() {
sendInputData(new Uint8Array([MessageType.RequestQualityControl]).buffer);
}
let playerElementClientRect = undefined;
let normalizeAndQuantizeUnsigned = undefined;
let normalizeAndQuantizeSigned = undefined;
function setupNormalizeAndQuantize() {
let playerElement = document.getElementById('player');
let videoElement = playerElement.getElementsByTagName("video");
if (playerElement && videoElement.length > 0) {
let playerAspectRatio = playerElement.clientHeight / playerElement.clientWidth;
let videoAspectRatio = videoElement[0].videoHeight / videoElement[0].videoWidth;
if (playerAspectRatio > videoAspectRatio) {
let ratio = playerAspectRatio / videoAspectRatio;
// Unsigned.
normalizeAndQuantizeUnsigned = (x, y) => {
let normalizedX = x / playerElement.clientWidth;
let normalizedY = ratio * (y / playerElement.clientHeight - 0.5) + 0.5;
if (normalizedX < 0.0 || normalizedX > 1.0 || normalizedY < 0.0 || normalizedY > 1.0) {
return {
inRange: false,
x: 65535,
y: 65535
};
} else {
return {
inRange: true,
x: normalizedX * 65536,
y: normalizedY * 65536
};
}
};
unquantizeAndDenormalizeUnsigned = (x, y) => {
let normalizedX = x / 65536;
let normalizedY = (y / 65536 - 0.5) / ratio + 0.5;
return {
x: normalizedX * playerElement.clientWidth,
y: normalizedY * playerElement.clientHeight
};
};
// Signed.
normalizeAndQuantizeSigned = (x, y) => {
let normalizedX = x / (0.5 * playerElement.clientWidth);
let normalizedY = (ratio * y) / (0.5 * playerElement.clientHeight);
return {
x: normalizedX * 32767,
y: normalizedY * 32767
};
};
} else {
let ratio = videoAspectRatio / playerAspectRatio;
// Unsigned.
normalizeAndQuantizeUnsigned = (x, y) => {
let normalizedX = ratio * (x / playerElement.clientWidth - 0.5) + 0.5;
let normalizedY = y / playerElement.clientHeight;
if (normalizedX < 0.0 || normalizedX > 1.0 || normalizedY < 0.0 || normalizedY > 1.0) {
return {
inRange: false,
x: 65535,
y: 65535
};
} else {
return {
inRange: true,
x: normalizedX * 65536,
y: normalizedY * 65536
};
}
};
unquantizeAndDenormalizeUnsigned = (x, y) => {
let normalizedX = (x / 65536 - 0.5) / ratio + 0.5;
let normalizedY = y / 65536;
return {
x: normalizedX * playerElement.clientWidth,
y: normalizedY * playerElement.clientHeight
};
};
// Signed.
normalizeAndQuantizeSigned = (x, y) => {
let normalizedX = (ratio * x) / (0.5 * playerElement.clientWidth);
let normalizedY = y / (0.5 * playerElement.clientHeight);
return {
x: normalizedX * 32767,
y: normalizedY * 32767
};
};
}
}
}
function emitMouseMove(x, y, deltaX, deltaY) {
let coord = normalizeAndQuantizeUnsigned(x, y);
let delta = normalizeAndQuantizeSigned(deltaX, deltaY);
let Data = new DataView(new ArrayBuffer(9));
Data.setUint8(0, MessageType.MouseMove);
Data.setUint16(1, coord.x, true);
Data.setUint16(3, coord.y, true);
Data.setInt16(5, delta.x, true);
Data.setInt16(7, delta.y, true);
sendInputData(Data.buffer);
}
function emitMouseDown(button, x, y) {
let coord = normalizeAndQuantizeUnsigned(x, y);
let Data = new DataView(new ArrayBuffer(6));
Data.setUint8(0, MessageType.MouseDown);
Data.setUint8(1, button);
Data.setUint16(2, coord.x, true);
Data.setUint16(4, coord.y, true);
sendInputData(Data.buffer);
}
function emitMouseUp(button, x, y) {
let coord = normalizeAndQuantizeUnsigned(x, y);
let Data = new DataView(new ArrayBuffer(6));
Data.setUint8(0, MessageType.MouseUp);
Data.setUint8(1, button);
Data.setUint16(2, coord.x, true);
Data.setUint16(4, coord.y, true);
sendInputData(Data.buffer);
}
function emitMouseWheel(delta, x, y) {
let coord = normalizeAndQuantizeUnsigned(x, y);
let Data = new DataView(new ArrayBuffer(7));
Data.setUint8(0, MessageType.MouseWheel);
Data.setInt16(1, delta, true);
Data.setUint16(3, coord.x, true);
Data.setUint16(5, coord.y, true);
sendInputData(Data.buffer);
}
// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
const MouseButton = {
MainButton: 0, // Left button.
AuxiliaryButton: 1, // Wheel button.
SecondaryButton: 2, // Right button.
FourthButton: 3, // Browser Back button.
FifthButton: 4 // Browser Forward button.
};
// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
const MouseButtonsMask = {
PrimaryButton: 1, // Left button.
SecondaryButton: 2, // Right button.
AuxiliaryButton: 4, // Wheel button.
FourthButton: 8, // Browser Back button.
FifthButton: 16 // Browser Forward button.
};
// If the user has any mouse buttons pressed then release them.
function releaseMouseButtons(buttons, x, y) {
if (buttons & MouseButtonsMask.PrimaryButton) {
emitMouseUp(MouseButton.MainButton, x, y);
}
if (buttons & MouseButtonsMask.SecondaryButton) {
emitMouseUp(MouseButton.SecondaryButton, x, y);
}
if (buttons & MouseButtonsMask.AuxiliaryButton) {
emitMouseUp(MouseButton.AuxiliaryButton, x, y);
}
if (buttons & MouseButtonsMask.FourthButton) {
emitMouseUp(MouseButton.FourthButton, x, y);
}
if (buttons & MouseButtonsMask.FifthButton) {
emitMouseUp(MouseButton.FifthButton, x, y);
}
}
// If the user has any mouse buttons pressed then press them again.
function pressMouseButtons(buttons, x, y) {
if (buttons & MouseButtonsMask.PrimaryButton) {
emitMouseDown(MouseButton.MainButton, x, y);
}
if (buttons & MouseButtonsMask.SecondaryButton) {
emitMouseDown(MouseButton.SecondaryButton, x, y);
}
if (buttons & MouseButtonsMask.AuxiliaryButton) {
emitMouseDown(MouseButton.AuxiliaryButton, x, y);
}
if (buttons & MouseButtonsMask.FourthButton) {
emitMouseDown(MouseButton.FourthButton, x, y);
}
if (buttons & MouseButtonsMask.FifthButton) {
emitMouseDown(MouseButton.FifthButton, x, y);
}
}
function registerInputs(playerElement) {
if (!playerElement)
return;
registerMouseEnterAndLeaveEvents(playerElement);
}
function registerMouseEnterAndLeaveEvents(playerElement) {
playerElement.onmouseenter = function(e) {
let Data = new DataView(new ArrayBuffer(1));
Data.setUint8(0, MessageType.MouseEnter);
sendInputData(Data.buffer);
playerElement.pressMouseButtons(e);
};
playerElement.onmouseleave = function(e) {
let Data = new DataView(new ArrayBuffer(1));
Data.setUint8(0, MessageType.MouseLeave);
sendInputData(Data.buffer);
playerElement.releaseMouseButtons(e);
};
}
// A locked mouse works by the user clicking in the browser player and the
// cursor disappears and is locked. The user moves the cursor and the camera
// moves, for example. The user presses escape to free the mouse.
function registerLockedMouseEvents(playerElement) {
let x = playerElement.width / 2;
let y = playerElement.height / 2;
playerElement.requestPointerLock = playerElement.requestPointerLock || playerElement.mozRequestPointerLock;
document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock;
playerElement.onclick = function() {
playerElement.requestPointerLock();
};
// Respond to lock state change events
document.addEventListener('pointerlockchange', lockStateChange, false);
document.addEventListener('mozpointerlockchange', lockStateChange, false);
function lockStateChange() {
if (document.pointerLockElement === playerElement ||
document.mozPointerLockElement === playerElement) {
console.log('Pointer locked');
document.addEventListener("mousemove", updatePosition, false);
} else {
console.log('The pointer lock status is now unlocked');
document.removeEventListener("mousemove", updatePosition, false);
}
}
function updatePosition(e) {
x += e.movementX;
y += e.movementY;
if (x > styleWidth) {
x -= styleWidth;
}
if (y > styleHeight) {
y -= styleHeight;
}
if (x < 0) {
x = styleWidth + x;
}
if (y < 0) {
y = styleHeight - y;
}
emitMouseMove(x, y, e.movementX, e.movementY);
}
playerElement.onmousedown = function(e) {
emitMouseDown(e.button, x, y);
};
playerElement.onmouseup = function(e) {
emitMouseUp(e.button, x, y);
};
playerElement.onmousewheel = function(e) {
emitMouseWheel(e.wheelDelta, x, y);
};
playerElement.pressMouseButtons = function(e) {
pressMouseButtons(e.buttons, x, y);
};
playerElement.releaseMouseButtons = function(e) {
releaseMouseButtons(e.buttons, x, y);
};
}
// A hovering mouse works by the user clicking the mouse button when they want
// the cursor to have an effect over the video. Otherwise the cursor just
// passes over the browser.
function registerHoveringMouseEvents(playerElement) {
styleCursor = 'none'; // We will rely on UE4 client's software cursor.
//styleCursor = 'default'; // Showing cursor
playerElement.onmousemove = function(e) {
emitMouseMove(e.offsetX, e.offsetY, e.movementX, e.movementY);
e.preventDefault();
};
playerElement.onmousedown = function(e) {
emitMouseDown(e.button, e.offsetX, e.offsetY);
e.preventDefault();
};
playerElement.onmouseup = function(e) {
emitMouseUp(e.button, e.offsetX, e.offsetY);
e.preventDefault();
};
// When the context menu is shown then it is safest to release the button
// which was pressed when the event happened. This will guarantee we will
// get at least one mouse up corresponding to a mouse down event. Otherwise
// the mouse can get stuck.
// https://github.com/facebook/react/issues/5531
playerElement.oncontextmenu = function(e) {
emitMouseUp(e.button, e.offsetX, e.offsetY);
e.preventDefault();
};
if ('onmousewheel' in playerElement) {
playerElement.onmousewheel = function(e) {
emitMouseWheel(e.wheelDelta, e.offsetX, e.offsetY);
e.preventDefault();
};
} else {
playerElement.addEventListener('DOMMouseScroll', function(e) {
emitMouseWheel(e.detail * -120, e.offsetX, e.offsetY);
e.preventDefault();
}, false);
}
playerElement.pressMouseButtons = function(e) {
pressMouseButtons(e.buttons, e.offsetX, e.offsetY);
};
playerElement.releaseMouseButtons = function(e) {
releaseMouseButtons(e.buttons, e.offsetX, e.offsetY);
};
}
// Browser keys do not have a charCode so we only need to test keyCode.
function isKeyCodeBrowserKey(keyCode) {
// Function keys or tab key.
return keyCode >= 112 && keyCode <= 123 || keyCode === 9;
}
// Must be kept in sync with JavaScriptKeyCodeToFKey C++ array. The index of the
// entry in the array is the special key code given below.
const SpecialKeyCodes = {
BackSpace: 8,
Shift: 16,
Control: 17,
Alt: 18,
RightShift: 253,
RightControl: 254,
RightAlt: 255
};
// We want to be able to differentiate between left and right versions of some
// keys.
function getKeyCode(e) {
if (e.keyCode === SpecialKeyCodes.Shift && e.code === 'ShiftRight') return SpecialKeyCodes.RightShift;
else if (e.keyCode === SpecialKeyCodes.Control && e.code === 'ControlRight') return SpecialKeyCodes.RightControl;
else if (e.keyCode === SpecialKeyCodes.Alt && e.code === 'AltRight') return SpecialKeyCodes.RightAlt;
else return e.keyCode;
}
function registerKeyboardEvents() {
document.onkeydown = function(e) {
sendInputData(new Uint8Array([MessageType.KeyDown, getKeyCode(e), e.repeat]).buffer);
// Backspace is not considered a keypress in JavaScript but we need it
// to be so characters may be deleted in a UE4 text entry field.
if (e.keyCode === SpecialKeyCodes.BackSpace) {
document.onkeypress({
charCode: SpecialKeyCodes.BackSpace
});
}
if (inputOptions.suppressBrowserKeys && isKeyCodeBrowserKey(e.keyCode)) {
e.preventDefault();
}
};
document.onkeyup = function(e) {
sendInputData(new Uint8Array([MessageType.KeyUp, getKeyCode(e)]).buffer);
if (inputOptions.suppressBrowserKeys && isKeyCodeBrowserKey(e.keyCode)) {
e.preventDefault();
}
};
document.onkeypress = function(e) {
let data = new DataView(new ArrayBuffer(3));
data.setUint8(0, MessageType.KeyPress);
data.setUint16(1, e.charCode, true);
sendInputData(data.buffer);
};
}
function start() {
showConnectOverlay();
if (webRtcPlayerObj) {
webRtcPlayerObj.setVideoEnabled(true);
}
if (!connect_on_load || is_reconnection) {
shouldShowPlayOverlay = true;
resizePlayerStyle();
} else {
connect();
}
// connect();
setTimeout(connect, 2000);
}
function connect() {
"use strict";
window.WebSocket = window.WebSocket || window.MozWebSocket;
if (!window.WebSocket) {
alert('Your browser doesn\'t support WebSocket');
return;
}
// ws = new WebSocket(window.location.href.replace('http://', 'ws://').replace('https://', 'wss://'));
// ws = new WebSocket(window.location.href.replace('http://', 'ws://').replace('https://', 'wss://'));
let connectionUrl = window.location.href.replace('http://', 'ws://').replace('https://', 'wss://').replace(/:\d+/, '');
console.log(`Creating a websocket connection to: ${connectionUrl}`);
ws = new WebSocket(connectionUrl);
ws.attemptStreamReconnection = true;
ws.onmessage = function(event) {
console.log(`<- SS: ${event.data}`);
let msg = JSON.parse(event.data);
if (msg.type === 'config') {
onConfig(msg);
} else if (msg.type === 'answer') {
onWebRtcAnswer(msg);
} else if (msg.type === 'iceCandidate') {
onWebRtcIce(msg.candidate);
} else {
console.log(`invalid SS message type: ${msg.type}`);
}
};
ws.onerror = function(event) {
console.log(`WS error: ${JSON.stringify(event)}`);
};
ws.onclose = function(event) {
console.log(`WS closed: ${JSON.stringify(event.code)} - ${event.reason}`);
ws = undefined;
is_reconnection = true;
// destroy `webRtcPlayerObj` if any
let playerDiv = document.getElementById('player');
if (webRtcPlayerObj) {
playerDiv.removeChild(webRtcPlayerObj.video);
webRtcPlayerObj.close();
webRtcPlayerObj = undefined;
}
setTimeout(start, 4000);
};
}
// Config data received from WebRTC sender via the Cirrus web server
function onConfig(config) {
let playerDiv = document.getElementById('player');
let playerElement = setupWebRtcPlayer(playerDiv, config);
resizePlayerStyle();
switch (inputOptions.controlScheme) {
case ControlSchemeType.HoveringMouse:
registerHoveringMouseEvents(playerElement);
break;
case ControlSchemeType.LockedMouse:
registerLockedMouseEvents(playerElement);
break;
default:
console.log(`ERROR: Unknown control scheme ${inputOptions.controlScheme}`);
registerLockedMouseEvents(playerElement);
break;
}
}
function load() {
registerKeyboardEvents();
start();
}