diff --git a/WebServers/SignallingWebServer/Public/player.css b/WebServers/SignallingWebServer/Public/player.css index 630a05d..552fd1c 100644 --- a/WebServers/SignallingWebServer/Public/player.css +++ b/WebServers/SignallingWebServer/Public/player.css @@ -1,377 +1,378 @@ /*Copyright Epic Games, Inc. All Rights Reserved.*/ :root { - /*Using colour scheme https://color.adobe.com/TD-Colors---Option-3-color-theme-10394433/*/ - --colour1: #000000; - --colour2: #FFFFFF; - --colour3: #0585fe; - --colour4: #35b350; - --colour5: #ffab00; - --colour6: #1e1d22; - --colour7: #3c3b40; + /*Using colour scheme https://color.adobe.com/TD-Colors---Option-3-color-theme-10394433/*/ + --colour1: #000000; + --colour2: #ffffff; + --colour3: #0585fe; + --colour4: #35b350; + --colour5: #ffab00; + --colour6: #1e1d22; + --colour7: #3c3b40; } body { - margin: 0px; - background-color: black; - font-family: 'Montserrat', sans-serif; + margin: 0px; + background-color: black; + font-family: "Montserrat", sans-serif; } #playerUI { - width: 100%; - height: 100%; + width: 100%; + height: 100%; } canvas { - image-rendering: crisp-edges; - position: absolute; + image-rendering: crisp-edges; + position: absolute; } video { - position: absolute; - width: 100%; - height: 100%; + position: absolute; + width: 100%; + height: 100%; } #player { - width: 100%; - height: 100%; - position: absolute; - background-color: #000; + width: 100%; + height: 100%; + position: absolute; + background-color: #000; } #videoPlayOverlay { - position: absolute; - font-size: 1.8em; - width: 100%; - height: 100%; - color: var(--colour2) + position: absolute; + font-size: 1.8em; + width: 100%; + height: 100%; + color: var(--colour2); } /* State for element to be clickable */ .clickableState { - align-items: center; - justify-content: center; - display: flex; - cursor: pointer; + align-items: center; + justify-content: center; + display: flex; + cursor: pointer; } /* State for element to show text, this is for informational use*/ .textDisplayState { - align-items: center; - justify-content: center; - display: flex; - cursor: pointer; + align-items: center; + justify-content: center; + display: flex; + cursor: pointer; } /* State to hide overlay, WebRTC communication is in progress and or is playing */ .hiddenState { - display: none; + display: none; } #playButton { - font-family: 'Inter', sans-serif; - display: flex; - flex-direction: column; - gap: 8px; - z-index: 30; - background: #262626; - width: 494px; - height: 282px; - border: 1px solid #404040; - border-radius: 32px; - align-items: center; - justify-content: center; - + font-family: "Inter", sans-serif; + display: flex; + flex-direction: column; + gap: 8px; + z-index: 30; + background: #262626; + width: 494px; + height: 282px; + border: 1px solid #404040; + border-radius: 32px; + align-items: center; + justify-content: center; } .caption { - font-style: normal; - font-weight: 400; - font-size: 22px; - line-height: 130%; - /* identical to box height, or 29px */ + font-style: normal; + font-weight: 400; + font-size: 22px; + line-height: 130%; + /* identical to box height, or 29px */ - text-align: center; + text-align: center; - /* Landing/White */ - margin: 0; - color: #EBEBEB; + /* Landing/White */ + margin: 0; + color: #ebebeb; } .caption1 { - margin: 0; - font-style: normal; - font-weight: 400; - font-size: 14px; - line-height: 130%; - /* or 18px */ + margin: 0; + font-style: normal; + font-weight: 400; + font-size: 14px; + line-height: 130%; + /* or 18px */ - text-align: center; + text-align: center; - /* Landing/LightGray */ - - color: #888888; + /* Landing/LightGray */ + color: #888888; } .play-btn { - margin-top: 17px; - background: #454545; - border-radius: 50%; - outline: none; - border: none; - cursor: pointer; - width: 106px; - height: 106px; + margin-top: 17px; + background: #454545; + border-radius: 50%; + outline: none; + border: none; + cursor: pointer; + width: 106px; + height: 106px; } img#playButton { - max-width: 241px; - width: 10%; + max-width: 241px; + width: 10%; } #freezeFrameOverlay { - background-color: transparent; + background-color: transparent; } .freezeframeBackground { - background-color: #000 !important; + background-color: #000 !important; } #overlay { - width: 100%; - height: 100%; - z-index: 20; - position: absolute; - color: var(--colour2); - pointer-events: none; - overflow: hidden; + width: 100%; + height: 100%; + z-index: 20; + position: absolute; + color: var(--colour2); + pointer-events: none; + overflow: hidden; } #overlay button { - background-color: var(--colour7); - border: 1px solid var(--colour7); - color: var(--colour2); - position: relative; - width: 3rem; - height: 3rem; - padding: 0.5rem; - text-align: center; + background-color: var(--colour7); + border: 1px solid var(--colour7); + color: var(--colour2); + position: relative; + width: 3rem; + height: 3rem; + padding: 0.5rem; + text-align: center; } #fullscreen-btn { - padding: 0.6rem !important; + padding: 0.6rem !important; } #overlay button:hover { - background-color: var(--colour3); - border: 3px solid var(--colour3); - transition: 0.25s ease; - padding-left: 0.55rem; - padding-top: 0.55rem; + background-color: var(--colour3); + border: 3px solid var(--colour3); + transition: 0.25s ease; + padding-left: 0.55rem; + padding-top: 0.55rem; } #overlay button:active { - border: 3px solid var(--colour3); - background-color: var(--colour7); - padding-left: 0.55rem; - padding-top: 0.55rem; + border: 3px solid var(--colour3); + background-color: var(--colour7); + padding-left: 0.55rem; + padding-top: 0.55rem; } #overlay img { - width: 100%; - height: 100%; + width: 100%; + height: 100%; } .tooltip .tooltiptext { - visibility: hidden; - width: auto; - color: var(--colour2); - text-align: center; - border-radius: 15px; - padding: 0px 10px; - font-family: 'Montserrat', sans-serif; - font-size: 0.75rem; - letter-spacing: 0.75px; - /* Position the tooltip */ - position: absolute; - top: 0; - transform: translateY(25%); - left: 125%; - z-index: 20; + visibility: hidden; + width: auto; + color: var(--colour2); + text-align: center; + border-radius: 15px; + padding: 0px 10px; + font-family: "Montserrat", sans-serif; + font-size: 0.75rem; + letter-spacing: 0.75px; + /* Position the tooltip */ + position: absolute; + top: 0; + transform: translateY(25%); + left: 125%; + z-index: 20; } .tooltip:hover .tooltiptext { - visibility: visible; - background-color: var(--colour7); + visibility: visible; + background-color: var(--colour7); } #connection .tooltiptext { - top: 125%; - transform: translateX(-25%); - left: 0; - z-index: 20; - padding: 5px 10px; + top: 125%; + transform: translateX(-25%); + left: 0; + z-index: 20; + padding: 5px 10px; } #settings-panel .tooltiptext { - display: block; - top: 125%; - transform: translateX(-50%); - left: 0; - z-index: 20; - padding: 5px 10px; - border: 3px solid var(--colour5); - width: max-content; + display: block; + top: 125%; + transform: translateX(-50%); + left: 0; + z-index: 20; + padding: 5px 10px; + border: 3px solid var(--colour5); + width: max-content; } #controls { - position: absolute; - top: 2%; - left: 1%; - font-family: 'Michroma', sans-serif; - pointer-events: all; - display: block; + position: absolute; + top: 2%; + left: 1%; + font-family: "Michroma", sans-serif; + pointer-events: all; + display: block; + visibility: hidden; } -#controls>* { - margin-bottom: 0.5rem; - border-radius: 50%; - display: block; - height: 2rem; - line-height: 1.75rem; - padding: 0.5rem; +#controls > * { + margin-bottom: 0.5rem; + border-radius: 50%; + display: block; + height: 2rem; + line-height: 1.75rem; + padding: 0.5rem; } #controls #additionalinfo { - text-align: center; - font-family: 'Montserrat', sans-serif; + text-align: center; + font-family: "Montserrat", sans-serif; } #unrealengine { - position: absolute; - bottom: 5%; - right: 10%; - font-family: 'Michroma', sans-serif; - pointer-events: all; - width: min-content; + visibility: hidden; + position: absolute; + bottom: 5%; + right: 10%; + font-family: "Michroma", sans-serif; + pointer-events: all; + width: min-content; } #unrealengine p { - visibility: hidden; - width: 15rem; + visibility: hidden; + width: 15rem; } #connection { - position: absolute; - bottom: 5%; - left: 10%; - font-family: 'Michroma', sans-serif; - height: 3rem; - width: 3rem; - pointer-events: all; + visibility: hidden; + position: absolute; + bottom: 5%; + left: 10%; + font-family: "Michroma", sans-serif; + height: 3rem; + width: 3rem; + pointer-events: all; } .noselect { - -webkit-touch-callout: none; - /* iOS Safari */ - -webkit-user-select: none; - /* Safari */ - -khtml-user-select: none; - /* Konqueror HTML */ - -moz-user-select: none; - /* Old versions of Firefox */ - -ms-user-select: none; - /* Internet Explorer/Edge */ - user-select: none; - /* Non-prefixed version, currently + -webkit-touch-callout: none; + /* iOS Safari */ + -webkit-user-select: none; + /* Safari */ + -khtml-user-select: none; + /* Konqueror HTML */ + -moz-user-select: none; + /* Old versions of Firefox */ + -ms-user-select: none; + /* Internet Explorer/Edge */ + user-select: none; + /* Non-prefixed version, currently supported by Chrome, Edge, Opera and Firefox */ } .panel-wrap { - position: fixed; - top: 0; - bottom: 0; - right: 0; - height: 100%; - min-width: 20vw; - transform: translateX(100%); - transition: .3s ease-out; - pointer-events: all; - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); - overflow-y: auto; - overflow-x: hidden; - background-color: rgba(30, 29, 34, 0.5) + position: fixed; + top: 0; + bottom: 0; + right: 0; + height: 100%; + min-width: 20vw; + transform: translateX(100%); + transition: 0.3s ease-out; + pointer-events: all; + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + overflow-y: auto; + overflow-x: hidden; + background-color: rgba(30, 29, 34, 0.5); } .panel-wrap-visible { - transform: translateX(0%); + transform: translateX(0%); } .panel { - color: #eee; - overflow-y: auto; - padding: 1em; + color: #eee; + overflow-y: auto; + padding: 1em; } #heading { - display: inline-block; - font-size: 2em; - margin-block-start: 0.67em; - margin-block-end: 0.67em; - margin-inline-start: 0px; - margin-inline-end: 0px; - position: relative; - padding: 0 0 0 2rem; + display: inline-block; + font-size: 2em; + margin-block-start: 0.67em; + margin-block-end: 0.67em; + margin-inline-start: 0px; + margin-inline-end: 0px; + position: relative; + padding: 0 0 0 2rem; } #close { - margin: 0.5rem; - padding-top: 0.5rem; - padding-bottom: 0.5rem; - padding-right: 0.5rem; - font-size: 2em; - float: right; + margin: 0.5rem; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-right: 0.5rem; + font-size: 2em; + float: right; } #close:after { - padding-left: 0.5rem; - display: inline-block; - content: "\00d7"; - /* This will render the 'X' */ + padding-left: 0.5rem; + display: inline-block; + content: "\00d7"; + /* This will render the 'X' */ } #close:hover { - color: var(--colour3); - transition: ease 0.3s; + color: var(--colour3); + transition: ease 0.3s; } #content { - margin: 2rem; + margin: 2rem; } .setting { - display: flex; - flex-direction: row; - justify-content: space-between; - padding: 0; - margin: 0.5rem 0; + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 0; + margin: 0.5rem 0; } .settings-text { - margin-right: 2rem; - display: flex; + margin-right: 2rem; + display: flex; } /*** Toggle Switch styles ***/ .tgl-switch { - vertical-align: middle; - display: inline-block; + vertical-align: middle; + display: inline-block; } .tgl-switch .tgl { - display: none; + display: none; } .tgl, @@ -380,9 +381,9 @@ img#playButton { .tgl *, .tgl *:after, .tgl *:before, -.tgl+.tgl-slider { - -webkit-box-sizing: border-box; - box-sizing: border-box; +.tgl + .tgl-slider { + -webkit-box-sizing: border-box; + box-sizing: border-box; } .tgl::-moz-selection, @@ -391,8 +392,8 @@ img#playButton { .tgl *::-moz-selection, .tgl *:after::-moz-selection, .tgl *:before::-moz-selection, -.tgl+.tgl-slider::-moz-selection { - background: none; +.tgl + .tgl-slider::-moz-selection { + background: none; } .tgl::selection, @@ -401,245 +402,244 @@ img#playButton { .tgl *::selection, .tgl *:after::selection, .tgl *:before::selection, -.tgl+.tgl-slider::selection { - background: none; +.tgl + .tgl-slider::selection { + background: none; } -.tgl+.tgl-slider { - outline: 0; - display: block; - width: 40px; - height: 18px; - position: relative; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; +.tgl + .tgl-slider { + outline: 0; + display: block; + width: 40px; + height: 18px; + position: relative; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } -.tgl+.tgl-slider:after, -.tgl+.tgl-slider:before { - position: relative; - display: block; - content: ""; - width: 50%; - height: 100%; +.tgl + .tgl-slider:after, +.tgl + .tgl-slider:before { + position: relative; + display: block; + content: ""; + width: 50%; + height: 100%; } -.tgl+.tgl-slider:after { - left: 0; +.tgl + .tgl-slider:after { + left: 0; } -.tgl+.tgl-slider:before { - display: none; +.tgl + .tgl-slider:before { + display: none; } -.tgl-flat+.tgl-slider { - padding: 2px; - -webkit-transition: all .2s ease; - transition: all .2s ease; - background: var(--colour6); - border: 3px solid var(--colour7); - border-radius: 2em; +.tgl-flat + .tgl-slider { + padding: 2px; + -webkit-transition: all 0.2s ease; + transition: all 0.2s ease; + background: var(--colour6); + border: 3px solid var(--colour7); + border-radius: 2em; } -.tgl-flat+.tgl-slider:after { - -webkit-transition: all .2s ease; - transition: all .2s ease; - background: var(--colour7); - content: ""; - border-radius: 1em; +.tgl-flat + .tgl-slider:after { + -webkit-transition: all 0.2s ease; + transition: all 0.2s ease; + background: var(--colour7); + content: ""; + border-radius: 1em; } -.tgl-flat:checked+.tgl-slider { - border: 3px solid var(--colour3); +.tgl-flat:checked + .tgl-slider { + border: 3px solid var(--colour3); } -.tgl-flat:checked+.tgl-slider:after { - left: 50%; - background: var(--colour3); +.tgl-flat:checked + .tgl-slider:after { + left: 50%; + background: var(--colour3); } .subtitle-text { - margin: 0 0 0 1rem; - color: var(--colour5); - position: relative; + margin: 0 0 0 1rem; + color: var(--colour5); + position: relative; } .form-group { - padding-top: 4px; - display: grid; - grid-template-columns: 50% 50%; - row-gap: 4px; - padding-right: 10px; - padding-left: 10px; + padding-top: 4px; + display: grid; + grid-template-columns: 50% 50%; + row-gap: 4px; + padding-right: 10px; + padding-left: 10px; } .form-group label { - color: var(--colour2); - vertical-align: middle; - font-weight: normal; + color: var(--colour2); + vertical-align: middle; + font-weight: normal; } #stats { - margin-left: 1rem; + margin-left: 1rem; } #LatencyStats { - margin-left: 1rem; + margin-left: 1rem; } #hiddenInput { - position: absolute; - left: -10%; - /* Although invisible, push off-screen to prevent user interaction. */ - width: 0px; - opacity: 0; + position: absolute; + left: -10%; + /* Although invisible, push off-screen to prevent user interaction. */ + width: 0px; + opacity: 0; } #editTextButton { - position: absolute; - height: 40px; - width: 40px; + position: absolute; + height: 40px; + width: 40px; } .form-group label { - margin-right: 2rem; - min-width: 75%; + margin-right: 2rem; + min-width: 75%; } input { - text-align: right; + text-align: right; } .warning { - box-sizing: border-box; - position: relative; - transform: scale(var(--ggs, 1)); - width: 20px; - height: 20px; - border: 2px solid; - border-radius: 40px; - display: none; + box-sizing: border-box; + position: relative; + transform: scale(var(--ggs, 1)); + width: 20px; + height: 20px; + border: 2px solid; + border-radius: 40px; + display: none; } .warning::after, .warning::before { - content: ""; - display: block; - box-sizing: border-box; - position: absolute; - border-radius: 3px; - width: 2px; - background: currentColor; - left: 7px + content: ""; + display: block; + box-sizing: border-box; + position: absolute; + border-radius: 3px; + width: 2px; + background: currentColor; + left: 7px; } .warning::after { - top: 2px; - height: 8px + top: 2px; + height: 8px; } .warning::before { - height: 2px; - bottom: 2px + height: 2px; + bottom: 2px; } /* Flat buttons */ input[type="button"] { - background-color: transparent; - color: var(--colour2); - font-family: 'Montserrat'; - border: 3px solid var(--colour3); - border-radius: 1rem; - font-size: 0.75rem; - padding-left: 0.5rem; - padding-right: 0.5rem; + background-color: transparent; + color: var(--colour2); + font-family: "Montserrat"; + border: 3px solid var(--colour3); + border-radius: 1rem; + font-size: 0.75rem; + padding-left: 0.5rem; + padding-right: 0.5rem; } input[type="button"]:hover { - background-color: var(--colour3); - transition: ease 0.3s; + background-color: var(--colour3); + transition: ease 0.3s; } input[type="button"]:active { - background-color: transparent; + background-color: transparent; } #encoder-params-submit, #webrtc-params-submit { - text-align: center; + text-align: center; } select, input[type="number"] { - background-color: var(--colour7); - color: var(--colour2); - border: 1px solid var(--colour6); - padding: 0.25rem; - font-family: 'Montserrat'; - border-radius: 0.25rem; + background-color: var(--colour7); + color: var(--colour2); + border: 1px solid var(--colour6); + padding: 0.25rem; + font-family: "Montserrat"; + border-radius: 0.25rem; } -input[type=number]::-webkit-inner-spin-button { - margin-left: 0.5rem; +input[type="number"]::-webkit-inner-spin-button { + margin-left: 0.5rem; } input[type="number"]:disabled { - padding-right: 0.5rem; - -moz-appearance: textfield; + padding-right: 0.5rem; + -moz-appearance: textfield; } -input[type=number]:disabled::-webkit-inner-spin-button { - display: none; - +input[type="number"]:disabled::-webkit-inner-spin-button { + display: none; } #settingsBtn, #statsBtn { - cursor: pointer; + cursor: pointer; } #streamingVideo { - pointer-events: all; + pointer-events: all; } embed { - border: none; - width: 100%; - height: 100%; + border: none; + width: 100%; + height: 100%; } g { - fill: var(--colour2); + fill: var(--colour2); } object { - pointer-events: none; + pointer-events: none; } #connectionStrength { - fill: var(--colour7); + fill: var(--colour7); } #minimize { - display: none; + display: none; } #afkOverlay { - z-index: 999; - background-color: rgba(30, 29, 34, 0.5); - display: inline-block; - height: 100vh; - width: 100vw; - line-height: 100vh; - text-align: center; - overflow: hidden; + z-index: 999; + background-color: rgba(30, 29, 34, 0.5); + display: inline-block; + height: 100vh; + width: 100vw; + line-height: 100vh; + text-align: center; + overflow: hidden; } #afkOverlay center { - display: inline-block; - line-height: 1.5; - height: 100vh; -} \ No newline at end of file + display: inline-block; + line-height: 1.5; + height: 100vh; +} diff --git a/WebServers/SignallingWebServer/package-lock.json b/WebServers/SignallingWebServer/package-lock.json index 2bee72e..c736670 100644 --- a/WebServers/SignallingWebServer/package-lock.json +++ b/WebServers/SignallingWebServer/package-lock.json @@ -12,8 +12,9 @@ "express": "^4.16.2", "express-session": "^1.15.6", "helmet": "^3.21.3", - "passport": "^0.6.0", + "passport": "^0.4.0", "passport-local": "^1.0.0", + "run-script-os": "^1.1.6", "ws": "^7.1.2", "y18n": "^5.0.5", "yargs": "^15.3.0" @@ -676,13 +677,12 @@ } }, "node_modules/passport": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz", - "integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz", + "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==", "dependencies": { "passport-strategy": "1.x.x", - "pause": "0.0.1", - "utils-merge": "^1.0.1" + "pause": "0.0.1" }, "engines": { "node": ">= 0.4.0" @@ -796,6 +796,15 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, + "node_modules/run-script-os": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/run-script-os/-/run-script-os-1.1.6.tgz", + "integrity": "sha512-ql6P2LzhBTTDfzKts+Qo4H94VUKpxKDFz6QxxwaUZN0mwvi7L3lpOI7BqPCq7lgDh3XLl0dpeXwfcVIitlrYrw==", + "bin": { + "run-os": "index.js", + "run-script-os": "index.js" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -1526,9 +1535,9 @@ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, "passport": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz", - "integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz", + "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==", "requires": { "passport-strategy": "1.x.x", "pause": "0.0.1" @@ -1612,6 +1621,11 @@ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, + "run-script-os": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/run-script-os/-/run-script-os-1.1.6.tgz", + "integrity": "sha512-ql6P2LzhBTTDfzKts+Qo4H94VUKpxKDFz6QxxwaUZN0mwvi7L3lpOI7BqPCq7lgDh3XLl0dpeXwfcVIitlrYrw==" + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", diff --git a/WebServers/SignallingWebServer/scripts/app.js b/WebServers/SignallingWebServer/scripts/app.js index d8f2c02..6981c8a 100644 --- a/WebServers/SignallingWebServer/scripts/app.js +++ b/WebServers/SignallingWebServer/scripts/app.js @@ -5,39 +5,44 @@ * TODO: Move these to seperate files once we introduce a bundler */ class TwoWayMap { - constructor(map = {}) { - this.map = map; - this.reverseMap = new Map(); - for (const key in map) { - const value = map[key]; - this.reverseMap[value] = key; - } + constructor(map = {}) { + this.map = map; + this.reverseMap = new Map(); + for (const key in map) { + const value = map[key]; + this.reverseMap[value] = key; } + } - getFromKey(key) { return this.map[key]; } - getFromValue(value) { return this.reverseMap[value]; } + getFromKey(key) { + return this.map[key]; + } + getFromValue(value) { + return this.reverseMap[value]; + } - add(key, value) { - this.map[key] = value; - this.reverseMap[value] = key; - } + add(key, value) { + this.map[key] = value; + this.reverseMap[value] = key; + } - remove(key, value) { - delete this.map[key]; - delete this.reverseMap[value]; - } + remove(key, value) { + delete this.map[key]; + delete this.reverseMap[value]; + } } /** * Frontend logic */ // Window events for a gamepad connecting -let haveEvents = 'GamepadEvent' in window; -let haveWebkitEvents = 'WebKitGamepadEvent' in window; +let haveEvents = "GamepadEvent" in window; +let haveWebkitEvents = "WebKitGamepadEvent" in window; let controllers = {}; -let rAF = window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || - window.requestAnimationFrame; +let rAF = + window.mozRequestAnimationFrame || + window.webkitRequestAnimationFrame || + window.requestAnimationFrame; let webRtcPlayerObj = null; let print_stats = false; @@ -65,36 +70,36 @@ let isFullscreen = false; let isMuted = false; // A freeze frame is a still JPEG image shown instead of the video. let freezeFrame = { - receiving: false, - size: 0, - jpeg: undefined, - height: 0, - width: 0, - valid: false + receiving: false, + size: 0, + jpeg: undefined, + height: 0, + width: 0, + valid: false, }; let file = { - mimetype: "", - extension: "", - receiving: false, - size: 0, - data: [], - valid: false, - timestampStart: undefined + mimetype: "", + extension: "", + receiving: false, + size: 0, + data: [], + valid: false, + timestampStart: undefined, }; // Optionally detect if the user is not interacting (AFK) and disconnect them. let afk = { - enabled: false, // Set to true to enable the AFK system. - warnTimeout: 120, // The time to elapse before warning the user they are inactive. - closeTimeout: 10, // The time after the warning when we disconnect the user. + enabled: false, // Set to true to enable the AFK system. + warnTimeout: 120, // The time to elapse before warning the user they are inactive. + closeTimeout: 10, // The time after the warning when we disconnect the user. - active: false, // Whether the AFK system is currently looking for inactivity. - overlay: undefined, // The UI overlay warning the user that they are inactive. - warnTimer: undefined, // The timer which waits to show the inactivity warning overlay. - countdown: 0, // The inactivity warning overlay has a countdown to show time until disconnect. - countdownTimer: undefined, // The timer used to tick the seconds shown on the inactivity warning overlay. -} + active: false, // Whether the AFK system is currently looking for inactivity. + overlay: undefined, // The UI overlay warning the user that they are inactive. + warnTimer: undefined, // The timer which waits to show the inactivity warning overlay. + countdown: 0, // The inactivity warning overlay has a countdown to show time until disconnect. + countdownTimer: undefined, // The timer used to tick the seconds shown on the inactivity warning overlay. +}; // If the user focuses on a UE input widget then we show them a button to open // the on-screen keyboard. JavaScript security means we can only show the @@ -116,1696 +121,2152 @@ let toStreamerMessages = new TwoWayMap(); let fromStreamerMessages = new TwoWayMap(); const MessageDirection = { - // A message sent to the streamer. eg Key presses - // ie player -> streamer - ToStreamer: 0, + // A message sent to the streamer. eg Key presses + // ie player -> streamer + ToStreamer: 0, - // A message recevied from the streamer. eg Freeze frames - // ie streamer -> player - FromStreamer: 1 + // A message recevied from the streamer. eg Freeze frames + // ie streamer -> player + FromStreamer: 1, }; let toStreamerHandlers = new Map(); // toStreamerHandlers[message](args..) let fromStreamerHandlers = new Map(); // fromStreamerHandlers[message](args..) function populateDefaultProtocol() { - /* - * Control Messages. Range = 0..49. - */ - toStreamerMessages.add("IFrameRequest", { - "id": 0, - "byteLength": 0, - "structure": [] - }); - toStreamerMessages.add("RequestQualityControl", { - "id": 1, - "byteLength": 0, - "structure": [] - }); - toStreamerMessages.add("FpsRequest", { - "id": 2, - "byteLength": 0, - "structure": [] - }); - toStreamerMessages.add("AverageBitrateRequest", { - "id": 3, - "byteLength": 0, - "structure": [] - }); - toStreamerMessages.add("StartStreaming", { - "id": 4, - "byteLength": 0, - "structure": [] - }); - toStreamerMessages.add("StopStreaming", { - "id": 5, - "byteLength": 0, - "structure": [] - }); - toStreamerMessages.add("LatencyTest", { - "id": 6, - "byteLength": 0, - "structure": [] - }); - toStreamerMessages.add("RequestInitialSettings", { - "id": 7, - "byteLength": 0, - "structure": [] - }); - toStreamerMessages.add("TestEcho", { - "id": 8, - "byteLength": 0, - "structure": [] - }); - /* - * Input Messages. Range = 50..89. - */ - // Generic Input Messages. Range = 50..59. - toStreamerMessages.add("UIInteraction", { - "id": 50, - "byteLength": 0, - "structure": [] - }); - toStreamerMessages.add("Command", { - "id": 51, - "byteLength": 0, - "structure": [] - }); - // Keyboard Input Message. Range = 60..69. - toStreamerMessages.add("KeyDown", { - "id": 60, - "byteLength": 2, - // keyCode isRepeat - "structure": ["uint8", "uint8"] - }); - toStreamerMessages.add("KeyUp", { - "id": 61, - "byteLength": 1, - // keyCode - "structure": ["uint8"] - }); - toStreamerMessages.add("KeyPress", { - "id": 62, - "byteLength": 2, - // charcode - "structure": ["uint16"] - }); - // Mouse Input Messages. Range = 70..79. - toStreamerMessages.add("MouseEnter", { - "id": 70, - "byteLength": 0, - "structure": [] - }); - toStreamerMessages.add("MouseLeave", { - "id": 71, - "byteLength": 0, - "structure": [] - }); - toStreamerMessages.add("MouseDown", { - "id": 72, - "byteLength": 5, - // button x y - "structure": ["uint8", "uint16", "uint16"] - }); - toStreamerMessages.add("MouseUp", { - "id": 73, - "byteLength": 5, - // button x y - "structure": ["uint8", "uint16", "uint16"] - }); - toStreamerMessages.add("MouseMove", { - "id": 74, - "byteLength": 8, - // x y deltaX deltaY - "structure": ["uint16", "uint16", "int16", "int16"] - }); - toStreamerMessages.add("MouseWheel", { - "id": 75, - "byteLength": 6, - // delta x y - "structure": ["int16", "uint16", "uint16"] - }); - toStreamerMessages.add("MouseDouble", { - "id": 76, - "byteLength": 5, - // button x y - "structure": ["uint8", "uint16", "uint16"] - }); - // Touch Input Messages. Range = 80..89. - toStreamerMessages.add("TouchStart", { - "id": 80, - "byteLength": 8, - // numtouches(1) x y idx force valid - "structure": ["uint8", "uint16", "uint16", "uint8", "uint8", "uint8"] - }); - toStreamerMessages.add("TouchEnd", { - "id": 81, - "byteLength": 8, - // numtouches(1) x y idx force valid - "structure": ["uint8", "uint16", "uint16", "uint8", "uint8", "uint8"] - }); - toStreamerMessages.add("TouchMove", { - "id": 82, - "byteLength": 8, - // numtouches(1) x y idx force valid - "structure": ["uint8", "uint16", "uint16", "uint8", "uint8", "uint8"] - }); - // Gamepad Input Messages. Range = 90..99 - toStreamerMessages.add("GamepadButtonPressed", { - "id": 90, - "byteLength": 3, - // ctrlerId button isRepeat - "structure": ["uint8", "uint8", "uint8"] - }); - toStreamerMessages.add("GamepadButtonReleased", { - "id": 91, - "byteLength": 3, - // ctrlerId button isRepeat(0) - "structure": ["uint8", "uint8", "uint8"] - }); - toStreamerMessages.add("GamepadAnalog", { - "id": 92, - "byteLength": 10, - // ctrlerId button analogValue - "structure": ["uint8", "uint8", "double"] - }); + /* + * Control Messages. Range = 0..49. + */ + toStreamerMessages.add("IFrameRequest", { + id: 0, + byteLength: 0, + structure: [], + }); + toStreamerMessages.add("RequestQualityControl", { + id: 1, + byteLength: 0, + structure: [], + }); + toStreamerMessages.add("FpsRequest", { + id: 2, + byteLength: 0, + structure: [], + }); + toStreamerMessages.add("AverageBitrateRequest", { + id: 3, + byteLength: 0, + structure: [], + }); + toStreamerMessages.add("StartStreaming", { + id: 4, + byteLength: 0, + structure: [], + }); + toStreamerMessages.add("StopStreaming", { + id: 5, + byteLength: 0, + structure: [], + }); + toStreamerMessages.add("LatencyTest", { + id: 6, + byteLength: 0, + structure: [], + }); + toStreamerMessages.add("RequestInitialSettings", { + id: 7, + byteLength: 0, + structure: [], + }); + toStreamerMessages.add("TestEcho", { + id: 8, + byteLength: 0, + structure: [], + }); + /* + * Input Messages. Range = 50..89. + */ + // Generic Input Messages. Range = 50..59. + toStreamerMessages.add("UIInteraction", { + id: 50, + byteLength: 0, + structure: [], + }); + toStreamerMessages.add("Command", { + id: 51, + byteLength: 0, + structure: [], + }); + // Keyboard Input Message. Range = 60..69. + toStreamerMessages.add("KeyDown", { + id: 60, + byteLength: 2, + // keyCode isRepeat + structure: ["uint8", "uint8"], + }); + toStreamerMessages.add("KeyUp", { + id: 61, + byteLength: 1, + // keyCode + structure: ["uint8"], + }); + toStreamerMessages.add("KeyPress", { + id: 62, + byteLength: 2, + // charcode + structure: ["uint16"], + }); + // Mouse Input Messages. Range = 70..79. + toStreamerMessages.add("MouseEnter", { + id: 70, + byteLength: 0, + structure: [], + }); + toStreamerMessages.add("MouseLeave", { + id: 71, + byteLength: 0, + structure: [], + }); + toStreamerMessages.add("MouseDown", { + id: 72, + byteLength: 5, + // button x y + structure: ["uint8", "uint16", "uint16"], + }); + toStreamerMessages.add("MouseUp", { + id: 73, + byteLength: 5, + // button x y + structure: ["uint8", "uint16", "uint16"], + }); + toStreamerMessages.add("MouseMove", { + id: 74, + byteLength: 8, + // x y deltaX deltaY + structure: ["uint16", "uint16", "int16", "int16"], + }); + toStreamerMessages.add("MouseWheel", { + id: 75, + byteLength: 6, + // delta x y + structure: ["int16", "uint16", "uint16"], + }); + toStreamerMessages.add("MouseDouble", { + id: 76, + byteLength: 5, + // button x y + structure: ["uint8", "uint16", "uint16"], + }); + // Touch Input Messages. Range = 80..89. + toStreamerMessages.add("TouchStart", { + id: 80, + byteLength: 8, + // numtouches(1) x y idx force valid + structure: ["uint8", "uint16", "uint16", "uint8", "uint8", "uint8"], + }); + toStreamerMessages.add("TouchEnd", { + id: 81, + byteLength: 8, + // numtouches(1) x y idx force valid + structure: ["uint8", "uint16", "uint16", "uint8", "uint8", "uint8"], + }); + toStreamerMessages.add("TouchMove", { + id: 82, + byteLength: 8, + // numtouches(1) x y idx force valid + structure: ["uint8", "uint16", "uint16", "uint8", "uint8", "uint8"], + }); + // Gamepad Input Messages. Range = 90..99 + toStreamerMessages.add("GamepadButtonPressed", { + id: 90, + byteLength: 3, + // ctrlerId button isRepeat + structure: ["uint8", "uint8", "uint8"], + }); + toStreamerMessages.add("GamepadButtonReleased", { + id: 91, + byteLength: 3, + // ctrlerId button isRepeat(0) + structure: ["uint8", "uint8", "uint8"], + }); + toStreamerMessages.add("GamepadAnalog", { + id: 92, + byteLength: 10, + // ctrlerId button analogValue + structure: ["uint8", "uint8", "double"], + }); - fromStreamerMessages.add("QualityControlOwnership", 0); - fromStreamerMessages.add("Response", 1); - fromStreamerMessages.add("Command", 2); - fromStreamerMessages.add("FreezeFrame", 3); - fromStreamerMessages.add("UnfreezeFrame", 4); - fromStreamerMessages.add("VideoEncoderAvgQP", 5); - fromStreamerMessages.add("LatencyTest", 6); - fromStreamerMessages.add("InitialSettings", 7); - fromStreamerMessages.add("FileExtension", 8); - fromStreamerMessages.add("FileMimeType", 9); - fromStreamerMessages.add("FileContents", 10); - fromStreamerMessages.add("TestEcho", 11); - fromStreamerMessages.add("InputControlOwnership", 12); - fromStreamerMessages.add("Protocol", 255); + fromStreamerMessages.add("QualityControlOwnership", 0); + fromStreamerMessages.add("Response", 1); + fromStreamerMessages.add("Command", 2); + fromStreamerMessages.add("FreezeFrame", 3); + fromStreamerMessages.add("UnfreezeFrame", 4); + fromStreamerMessages.add("VideoEncoderAvgQP", 5); + fromStreamerMessages.add("LatencyTest", 6); + fromStreamerMessages.add("InitialSettings", 7); + fromStreamerMessages.add("FileExtension", 8); + fromStreamerMessages.add("FileMimeType", 9); + fromStreamerMessages.add("FileContents", 10); + fromStreamerMessages.add("TestEcho", 11); + fromStreamerMessages.add("InputControlOwnership", 12); + fromStreamerMessages.add("Protocol", 255); } function registerMessageHandlers() { - registerMessageHandler(MessageDirection.FromStreamer, "QualityControlOwnership", onQualityControlOwnership); - registerMessageHandler(MessageDirection.FromStreamer, "Response", onResponse); - registerMessageHandler(MessageDirection.FromStreamer, "Command", onCommand); - registerMessageHandler(MessageDirection.FromStreamer, "FreezeFrame", onFreezeFrameMessage); - registerMessageHandler(MessageDirection.FromStreamer, "UnfreezeFrame", invalidateFreezeFrameOverlay); - registerMessageHandler(MessageDirection.FromStreamer, "VideoEncoderAvgQP", onVideoEncoderAvgQP); - registerMessageHandler(MessageDirection.FromStreamer, "LatencyTest", onLatencyTestMessage); - registerMessageHandler(MessageDirection.FromStreamer, "InitialSettings", onInitialSettings); - registerMessageHandler(MessageDirection.FromStreamer, "FileExtension", onFileExtension); - registerMessageHandler(MessageDirection.FromStreamer, "FileMimeType", onFileMimeType); - registerMessageHandler(MessageDirection.FromStreamer, "FileContents", onFileContents); - registerMessageHandler(MessageDirection.FromStreamer, "TestEcho", () => {/* Do nothing */ }); - registerMessageHandler(MessageDirection.FromStreamer, "InputControlOwnership", onInputControlOwnership); - registerMessageHandler(MessageDirection.FromStreamer, "Protocol", onProtocolMessage); + registerMessageHandler( + MessageDirection.FromStreamer, + "QualityControlOwnership", + onQualityControlOwnership + ); + registerMessageHandler(MessageDirection.FromStreamer, "Response", onResponse); + registerMessageHandler(MessageDirection.FromStreamer, "Command", onCommand); + registerMessageHandler( + MessageDirection.FromStreamer, + "FreezeFrame", + onFreezeFrameMessage + ); + registerMessageHandler( + MessageDirection.FromStreamer, + "UnfreezeFrame", + invalidateFreezeFrameOverlay + ); + registerMessageHandler( + MessageDirection.FromStreamer, + "VideoEncoderAvgQP", + onVideoEncoderAvgQP + ); + registerMessageHandler( + MessageDirection.FromStreamer, + "LatencyTest", + onLatencyTestMessage + ); + registerMessageHandler( + MessageDirection.FromStreamer, + "InitialSettings", + onInitialSettings + ); + registerMessageHandler( + MessageDirection.FromStreamer, + "FileExtension", + onFileExtension + ); + registerMessageHandler( + MessageDirection.FromStreamer, + "FileMimeType", + onFileMimeType + ); + registerMessageHandler( + MessageDirection.FromStreamer, + "FileContents", + onFileContents + ); + registerMessageHandler(MessageDirection.FromStreamer, "TestEcho", () => { + /* Do nothing */ + }); + registerMessageHandler( + MessageDirection.FromStreamer, + "InputControlOwnership", + onInputControlOwnership + ); + registerMessageHandler( + MessageDirection.FromStreamer, + "Protocol", + onProtocolMessage + ); - registerMessageHandler(MessageDirection.ToStreamer, "IFrameRequest", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "RequestQualityControl", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "FpsRequest", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "AverageBitrateRequest", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "StartStreaming", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "StopStreaming", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "LatencyTest", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "RequestInitialSettings", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "TestEcho", () => { /* Do nothing */ }); - registerMessageHandler(MessageDirection.ToStreamer, "UIInteraction", emitUIInteraction); - registerMessageHandler(MessageDirection.ToStreamer, "Command", emitCommand); - registerMessageHandler(MessageDirection.ToStreamer, "KeyDown", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "KeyUp", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "KeyPress", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "MouseEnter", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "MouseLeave", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "MouseDown", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "MouseUp", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "MouseMove", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "MouseWheel", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "MouseDouble", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "TouchStart", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "TouchEnd", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "TouchMove", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "GamepadButtonPressed", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "GamepadButtonReleased", sendMessageToStreamer); - registerMessageHandler(MessageDirection.ToStreamer, "GamepadAnalog", sendMessageToStreamer); + registerMessageHandler( + MessageDirection.ToStreamer, + "IFrameRequest", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "RequestQualityControl", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "FpsRequest", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "AverageBitrateRequest", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "StartStreaming", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "StopStreaming", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "LatencyTest", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "RequestInitialSettings", + sendMessageToStreamer + ); + registerMessageHandler(MessageDirection.ToStreamer, "TestEcho", () => { + /* Do nothing */ + }); + registerMessageHandler( + MessageDirection.ToStreamer, + "UIInteraction", + emitUIInteraction + ); + registerMessageHandler(MessageDirection.ToStreamer, "Command", emitCommand); + registerMessageHandler( + MessageDirection.ToStreamer, + "KeyDown", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "KeyUp", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "KeyPress", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "MouseEnter", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "MouseLeave", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "MouseDown", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "MouseUp", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "MouseMove", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "MouseWheel", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "MouseDouble", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "TouchStart", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "TouchEnd", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "TouchMove", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "GamepadButtonPressed", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "GamepadButtonReleased", + sendMessageToStreamer + ); + registerMessageHandler( + MessageDirection.ToStreamer, + "GamepadAnalog", + sendMessageToStreamer + ); } function registerMessageHandler(messageDirection, messageType, messageHandler) { - switch (messageDirection) { - case MessageDirection.ToStreamer: - toStreamerHandlers[messageType] = messageHandler; - break; - case MessageDirection.FromStreamer: - fromStreamerHandlers[messageType] = messageHandler; - break; - default: - console.log(`Unknown message direction ${messageDirection}`); - } + switch (messageDirection) { + case MessageDirection.ToStreamer: + toStreamerHandlers[messageType] = messageHandler; + break; + case MessageDirection.FromStreamer: + fromStreamerHandlers[messageType] = messageHandler; + break; + default: + console.log(`Unknown message direction ${messageDirection}`); + } } function onQualityControlOwnership(data) { - let view = new Uint8Array(data); - let ownership = view[1] === 0 ? false : true; - console.log("Received quality controller message, will control quality: " + ownership); - qualityController = ownership; - // If we own the quality control, we can't relinquish it. We only lose - // quality control when another peer asks for it - if (qualityControlOwnershipCheckBox !== null) { - qualityControlOwnershipCheckBox.disabled = ownership; - qualityControlOwnershipCheckBox.checked = ownership; - } + let view = new Uint8Array(data); + let ownership = view[1] === 0 ? false : true; + console.log( + "Received quality controller message, will control quality: " + ownership + ); + qualityController = ownership; + // If we own the quality control, we can't relinquish it. We only lose + // quality control when another peer asks for it + if (qualityControlOwnershipCheckBox !== null) { + qualityControlOwnershipCheckBox.disabled = ownership; + qualityControlOwnershipCheckBox.checked = ownership; + } } function onResponse(data) { - let response = new TextDecoder("utf-16").decode(data.slice(1)); - for (let listener of responseEventListeners.values()) { - listener(response); - } + let response = new TextDecoder("utf-16").decode(data.slice(1)); + for (let listener of responseEventListeners.values()) { + listener(response); + } } function onCommand(data) { - let commandAsString = new TextDecoder("utf-16").decode(data.slice(1)); - console.log(commandAsString); - let command = JSON.parse(commandAsString); - if (command.command === 'onScreenKeyboard') { - showOnScreenKeyboard(command); - } + let commandAsString = new TextDecoder("utf-16").decode(data.slice(1)); + console.log(commandAsString); + let command = JSON.parse(commandAsString); + if (command.command === "onScreenKeyboard") { + showOnScreenKeyboard(command); + } } function onFreezeFrameMessage(data) { - let view = new Uint8Array(data); - processFreezeFrameMessage(view); + let view = new Uint8Array(data); + processFreezeFrameMessage(view); } function onVideoEncoderAvgQP(data) { - VideoEncoderQP = new TextDecoder("utf-16").decode(data.slice(1)); + VideoEncoderQP = new TextDecoder("utf-16").decode(data.slice(1)); } function onLatencyTestMessage(data) { - let latencyTimingsAsString = new TextDecoder("utf-16").decode(data.slice(1)); - console.log("Got latency timings from UE."); - console.log(latencyTimingsAsString); - let latencyTimingsFromUE = JSON.parse(latencyTimingsAsString); - if (webRtcPlayerObj) { - webRtcPlayerObj.latencyTestTimings.SetUETimings(latencyTimingsFromUE); - } + let latencyTimingsAsString = new TextDecoder("utf-16").decode(data.slice(1)); + console.log("Got latency timings from UE."); + console.log(latencyTimingsAsString); + let latencyTimingsFromUE = JSON.parse(latencyTimingsAsString); + if (webRtcPlayerObj) { + webRtcPlayerObj.latencyTestTimings.SetUETimings(latencyTimingsFromUE); + } } function onInitialSettings(data) { - let settingsString = new TextDecoder("utf-16").decode(data.slice(1)); - let settingsJSON = JSON.parse(settingsString); + let settingsString = new TextDecoder("utf-16").decode(data.slice(1)); + let settingsJSON = JSON.parse(settingsString); - if (settingsJSON.PixelStreaming) { - let allowConsoleCommands = settingsJSON.PixelStreaming.AllowPixelStreamingCommands; - if (allowConsoleCommands === false) { - console.warn("-AllowPixelStreamingCommands=false, sending arbitray console commands from browser to UE is disabled."); - } - let disableLatencyTest = settingsJSON.PixelStreaming.DisableLatencyTest; - if (disableLatencyTest) { - document.getElementById("test-latency-button").disabled = true; - document.getElementById("test-latency-button").title = "Disabled by -PixelStreamingDisableLatencyTester=true"; - console.warn("-PixelStreamingDisableLatencyTester=true, requesting latency report from the the browser to UE is disabled."); - } + if (settingsJSON.PixelStreaming) { + let allowConsoleCommands = + settingsJSON.PixelStreaming.AllowPixelStreamingCommands; + if (allowConsoleCommands === false) { + console.warn( + "-AllowPixelStreamingCommands=false, sending arbitray console commands from browser to UE is disabled." + ); } - if (settingsJSON.Encoder) { - document.getElementById('encoder-min-qp-text').value = settingsJSON.Encoder.MinQP; - document.getElementById('encoder-max-qp-text').value = settingsJSON.Encoder.MaxQP; - } - if (settingsJSON.WebRTC) { - document.getElementById("webrtc-fps-text").value = settingsJSON.WebRTC.FPS; - // reminder bitrates are sent in bps but displayed in kbps - document.getElementById("webrtc-min-bitrate-text").value = settingsJSON.WebRTC.MinBitrate / 1000; - document.getElementById("webrtc-max-bitrate-text").value = settingsJSON.WebRTC.MaxBitrate / 1000; + let disableLatencyTest = settingsJSON.PixelStreaming.DisableLatencyTest; + if (disableLatencyTest) { + document.getElementById("test-latency-button").disabled = true; + document.getElementById("test-latency-button").title = + "Disabled by -PixelStreamingDisableLatencyTester=true"; + console.warn( + "-PixelStreamingDisableLatencyTester=true, requesting latency report from the the browser to UE is disabled." + ); } + } + if (settingsJSON.Encoder) { + document.getElementById("encoder-min-qp-text").value = + settingsJSON.Encoder.MinQP; + document.getElementById("encoder-max-qp-text").value = + settingsJSON.Encoder.MaxQP; + } + if (settingsJSON.WebRTC) { + document.getElementById("webrtc-fps-text").value = settingsJSON.WebRTC.FPS; + // reminder bitrates are sent in bps but displayed in kbps + document.getElementById("webrtc-min-bitrate-text").value = + settingsJSON.WebRTC.MinBitrate / 1000; + document.getElementById("webrtc-max-bitrate-text").value = + settingsJSON.WebRTC.MaxBitrate / 1000; + } } function onFileExtension(data) { - let view = new Uint8Array(data); - processFileExtension(view); + let view = new Uint8Array(data); + processFileExtension(view); } function onFileMimeType(data) { - let view = new Uint8Array(data); - processFileMimeType(view); + let view = new Uint8Array(data); + processFileMimeType(view); } function onFileContents(data) { - let view = new Uint8Array(data); - processFileContents(view); + let view = new Uint8Array(data); + processFileContents(view); } function onInputControlOwnership(data) { - let view = new Uint8Array(data); - let ownership = view[1] === 0 ? false : true; - console.log("Received input controller message - will your input control the stream: " + ownership); - inputController = ownership; + let view = new Uint8Array(data); + let ownership = view[1] === 0 ? false : true; + console.log( + "Received input controller message - will your input control the stream: " + + ownership + ); + inputController = ownership; } function onProtocolMessage(data) { - try { - let protocolString = new TextDecoder("utf-16").decode(data.slice(1)); - let protocolJSON = JSON.parse(protocolString); - if (!protocolJSON.hasOwnProperty("Direction")) { - throw new Error('Malformed protocol received. Ensure the protocol message contains a direction'); - } - let direction = protocolJSON.Direction; - delete protocolJSON.Direction; - console.log(`Received new ${direction == MessageDirection.FromStreamer ? "FromStreamer" : "ToStreamer"} protocol. Updating existing protocol...`); - Object.keys(protocolJSON).forEach((messageType) => { - let message = protocolJSON[messageType]; - switch (direction) { - case MessageDirection.ToStreamer: - // Check that the message contains all the relevant params - if (!message.hasOwnProperty("id") || !message.hasOwnProperty("byteLength")) { - console.error(`ToStreamer->${messageType} protocol definition was malformed as it didn't contain at least an id and a byteLength\n - Definition was: ${JSON.stringify(message, null, 2)}`); - // return in a forEach is equivalent to a continue in a normal for loop - return; - } - if (message.byteLength > 0 && !message.hasOwnProperty("structure")) { - // If we specify a bytelength, will must have a corresponding structure - console.error(`ToStreamer->${messageType} protocol definition was malformed as it specified a byteLength but no accompanying structure`); - // return in a forEach is equivalent to a continue in a normal for loop - return; - } - - if (toStreamerHandlers[messageType]) { - // If we've registered a handler for this message type we can add it to our supported messages. ie registerMessageHandler(...) - toStreamerMessages.add(messageType, message); - } else { - console.error(`There was no registered handler for "${messageType}" - try adding one using registerMessageHandler(MessageDirection.ToStreamer, "${messageType}", myHandler)`); - } - break; - case MessageDirection.FromStreamer: - // Check that the message contains all the relevant params - if (!message.hasOwnProperty("id")) { - console.error(`FromStreamer->${messageType} protocol definition was malformed as it didn't contain at least an id\n - Definition was: ${JSON.stringify(message, null, 2)}`); - // return in a forEach is equivalent to a continue in a normal for loop - return; - } - if (fromStreamerHandlers[messageType]) { - // If we've registered a handler for this message type. ie registerMessageHandler(...) - fromStreamerMessages.add(messageType, message.id); - } else { - console.error(`There was no registered handler for "${message}" - try adding one using registerMessageHandler(MessageDirection.FromStreamer, "${messageType}", myHandler)`); - } - break; - default: - throw new Error(`Unknown direction: ${direction}`); - } - }); - - // Once the protocol has been received, we can send our control messages - requestInitialSettings(); - requestQualityControl(); - } catch (e) { - console.log(e); + try { + let protocolString = new TextDecoder("utf-16").decode(data.slice(1)); + let protocolJSON = JSON.parse(protocolString); + if (!protocolJSON.hasOwnProperty("Direction")) { + throw new Error( + "Malformed protocol received. Ensure the protocol message contains a direction" + ); } + let direction = protocolJSON.Direction; + delete protocolJSON.Direction; + console.log( + `Received new ${ + direction == MessageDirection.FromStreamer + ? "FromStreamer" + : "ToStreamer" + } protocol. Updating existing protocol...` + ); + Object.keys(protocolJSON).forEach((messageType) => { + let message = protocolJSON[messageType]; + switch (direction) { + case MessageDirection.ToStreamer: + // Check that the message contains all the relevant params + if ( + !message.hasOwnProperty("id") || + !message.hasOwnProperty("byteLength") + ) { + console.error(`ToStreamer->${messageType} protocol definition was malformed as it didn't contain at least an id and a byteLength\n + Definition was: ${JSON.stringify( + message, + null, + 2 + )}`); + // return in a forEach is equivalent to a continue in a normal for loop + return; + } + if (message.byteLength > 0 && !message.hasOwnProperty("structure")) { + // If we specify a bytelength, will must have a corresponding structure + console.error( + `ToStreamer->${messageType} protocol definition was malformed as it specified a byteLength but no accompanying structure` + ); + // return in a forEach is equivalent to a continue in a normal for loop + return; + } + + if (toStreamerHandlers[messageType]) { + // If we've registered a handler for this message type we can add it to our supported messages. ie registerMessageHandler(...) + toStreamerMessages.add(messageType, message); + } else { + console.error( + `There was no registered handler for "${messageType}" - try adding one using registerMessageHandler(MessageDirection.ToStreamer, "${messageType}", myHandler)` + ); + } + break; + case MessageDirection.FromStreamer: + // Check that the message contains all the relevant params + if (!message.hasOwnProperty("id")) { + console.error(`FromStreamer->${messageType} protocol definition was malformed as it didn't contain at least an id\n + Definition was: ${JSON.stringify(message, null, 2)}`); + // return in a forEach is equivalent to a continue in a normal for loop + return; + } + if (fromStreamerHandlers[messageType]) { + // If we've registered a handler for this message type. ie registerMessageHandler(...) + fromStreamerMessages.add(messageType, message.id); + } else { + console.error( + `There was no registered handler for "${message}" - try adding one using registerMessageHandler(MessageDirection.FromStreamer, "${messageType}", myHandler)` + ); + } + break; + default: + throw new Error(`Unknown direction: ${direction}`); + } + }); + + // Once the protocol has been received, we can send our control messages + requestInitialSettings(); + requestQualityControl(); + } catch (e) { + console.log(e); + } } // https://w3c.github.io/gamepad/#remapping const gamepadLayout = { - // Buttons - RightClusterBottomButton: 0, - RightClusterRightButton: 1, - RightClusterLeftButton: 2, - RightClusterTopButton: 3, - LeftShoulder: 4, - RightShoulder: 5, - LeftTrigger: 6, - RightTrigger: 7, - SelectOrBack: 8, - StartOrForward: 9, - LeftAnalogPress: 10, - RightAnalogPress: 11, - LeftClusterTopButton: 12, - LeftClusterBottomButton: 13, - LeftClusterLeftButton: 14, - LeftClusterRightButton: 15, - CentreButton: 16, - // Axes - LeftStickHorizontal: 0, - LeftStickVertical: 1, - RightStickHorizontal: 2, - RightStickVertical: 3 + // Buttons + RightClusterBottomButton: 0, + RightClusterRightButton: 1, + RightClusterLeftButton: 2, + RightClusterTopButton: 3, + LeftShoulder: 4, + RightShoulder: 5, + LeftTrigger: 6, + RightTrigger: 7, + SelectOrBack: 8, + StartOrForward: 9, + LeftAnalogPress: 10, + RightAnalogPress: 11, + LeftClusterTopButton: 12, + LeftClusterBottomButton: 13, + LeftClusterLeftButton: 14, + LeftClusterRightButton: 15, + CentreButton: 16, + // Axes + LeftStickHorizontal: 0, + LeftStickVertical: 1, + RightStickHorizontal: 2, + RightStickVertical: 3, }; function scanGamepads() { - let gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []); - for (let i = 0; i < gamepads.length; i++) { - if (gamepads[i] && (gamepads[i].index in controllers)) { - controllers[gamepads[i].index].currentState = gamepads[i]; - } + let gamepads = navigator.getGamepads + ? navigator.getGamepads() + : navigator.webkitGetGamepads + ? navigator.webkitGetGamepads() + : []; + for (let i = 0; i < gamepads.length; i++) { + if (gamepads[i] && gamepads[i].index in controllers) { + controllers[gamepads[i].index].currentState = gamepads[i]; } + } } function updateStatus() { - scanGamepads(); - // Iterate over multiple controllers in the case the mutiple gamepads are connected - for (let j in controllers) { - let controller = controllers[j]; - let currentState = controller.currentState; - let prevState = controller.prevState; - // Iterate over buttons - for (let i = 0; i < currentState.buttons.length; i++) { - let currButton = currentState.buttons[i]; - let prevButton = prevState.buttons[i]; - if (currButton.pressed) { - // press - if (i == gamepadLayout.LeftTrigger) { - // UEs left analog has a button index of 5 - toStreamerHandlers.GamepadAnalog("GamepadAnalog", [j, 5, currButton.value]); - } else if (i == gamepadLayout.RightTrigger) { - // UEs right analog has a button index of 6 - toStreamerHandlers.GamepadAnalog("GamepadAnalog", [j, 6, currButton.value]); - } else { - toStreamerHandlers.GamepadButtonPressed("GamepadButtonPressed", [j, i, prevButton.pressed]); - } - } else if (!currButton.pressed && prevButton.pressed) { - // release - if (i == gamepadLayout.LeftTrigger) { - // UEs left analog has a button index of 5 - toStreamerHandlers.GamepadAnalog("GamepadAnalog", [j, 5, 0]); - } else if (i == gamepadLayout.RightTrigger) { - // UEs right analog has a button index of 6 - toStreamerHandlers.GamepadAnalog("GamepadAnalog", [j, 6, 0]); - } else { - toStreamerHandlers.GamepadButtonReleased("GamepadButtonReleased", [j, i]); - } - } + scanGamepads(); + // Iterate over multiple controllers in the case the mutiple gamepads are connected + for (let j in controllers) { + let controller = controllers[j]; + let currentState = controller.currentState; + let prevState = controller.prevState; + // Iterate over buttons + for (let i = 0; i < currentState.buttons.length; i++) { + let currButton = currentState.buttons[i]; + let prevButton = prevState.buttons[i]; + if (currButton.pressed) { + // press + if (i == gamepadLayout.LeftTrigger) { + // UEs left analog has a button index of 5 + toStreamerHandlers.GamepadAnalog("GamepadAnalog", [ + j, + 5, + currButton.value, + ]); + } else if (i == gamepadLayout.RightTrigger) { + // UEs right analog has a button index of 6 + toStreamerHandlers.GamepadAnalog("GamepadAnalog", [ + j, + 6, + currButton.value, + ]); + } else { + toStreamerHandlers.GamepadButtonPressed("GamepadButtonPressed", [ + j, + i, + prevButton.pressed, + ]); } - // Iterate over gamepad axes (we will increment in lots of 2 as there is 2 axes per stick) - for (let i = 0; i < currentState.axes.length; i += 2) { - // Horizontal axes are even numbered - let x = parseFloat(currentState.axes[i].toFixed(4)); - - // Vertical axes are odd numbered - // https://w3c.github.io/gamepad/#remapping Gamepad browser side standard mapping has positive down, negative up. This is downright disgusting. So we fix it. - let y = -parseFloat(currentState.axes[i + 1].toFixed(4)); - - // UE's analog axes follow the same order as the browsers, but start at index 1 so we will offset as such - toStreamerHandlers.GamepadAnalog("GamepadAnalog", [j, i + 1, x]); // Horizontal axes, only offset by 1 - toStreamerHandlers.GamepadAnalog("GamepadAnalog", [j, i + 2, y]); // Vertical axes, offset by two (1 to match UEs axes convention and then another 1 for the vertical axes) + } else if (!currButton.pressed && prevButton.pressed) { + // release + if (i == gamepadLayout.LeftTrigger) { + // UEs left analog has a button index of 5 + toStreamerHandlers.GamepadAnalog("GamepadAnalog", [j, 5, 0]); + } else if (i == gamepadLayout.RightTrigger) { + // UEs right analog has a button index of 6 + toStreamerHandlers.GamepadAnalog("GamepadAnalog", [j, 6, 0]); + } else { + toStreamerHandlers.GamepadButtonReleased("GamepadButtonReleased", [ + j, + i, + ]); } - controllers[j].prevState = currentState; + } } - rAF(updateStatus); + // Iterate over gamepad axes (we will increment in lots of 2 as there is 2 axes per stick) + for (let i = 0; i < currentState.axes.length; i += 2) { + // Horizontal axes are even numbered + let x = parseFloat(currentState.axes[i].toFixed(4)); + + // Vertical axes are odd numbered + // https://w3c.github.io/gamepad/#remapping Gamepad browser side standard mapping has positive down, negative up. This is downright disgusting. So we fix it. + let y = -parseFloat(currentState.axes[i + 1].toFixed(4)); + + // UE's analog axes follow the same order as the browsers, but start at index 1 so we will offset as such + toStreamerHandlers.GamepadAnalog("GamepadAnalog", [j, i + 1, x]); // Horizontal axes, only offset by 1 + toStreamerHandlers.GamepadAnalog("GamepadAnalog", [j, i + 2, y]); // Vertical axes, offset by two (1 to match UEs axes convention and then another 1 for the vertical axes) + } + controllers[j].prevState = currentState; + } + rAF(updateStatus); } function gamepadConnectHandler(e) { - console.log("Gamepad connect handler"); - gamepad = e.gamepad; - controllers[gamepad.index] = {}; - controllers[gamepad.index].currentState = gamepad; - controllers[gamepad.index].prevState = gamepad; - console.log("Gamepad: " + gamepad.id + " connected"); - rAF(updateStatus); + console.log("Gamepad connect handler"); + gamepad = e.gamepad; + controllers[gamepad.index] = {}; + controllers[gamepad.index].currentState = gamepad; + controllers[gamepad.index].prevState = gamepad; + console.log("Gamepad: " + gamepad.id + " connected"); + rAF(updateStatus); } function gamepadDisconnectHandler(e) { - console.log("Gamepad disconnect handler"); - console.log("Gamepad: " + e.gamepad.id + " disconnected"); - delete controllers[e.gamepad.index]; + console.log("Gamepad disconnect handler"); + console.log("Gamepad: " + e.gamepad.id + " disconnected"); + delete controllers[e.gamepad.index]; } - function fullscreen() { - // if already full screen; exit - // else go fullscreen - if ( - document.fullscreenElement || - document.webkitFullscreenElement || - document.mozFullScreenElement || - document.msFullscreenElement - ) { - if (document.exitFullscreen) { - document.exitFullscreen(); - } else if (document.mozCancelFullScreen) { - document.mozCancelFullScreen(); - } else if (document.webkitExitFullscreen) { - document.webkitExitFullscreen(); - } else if (document.msExitFullscreen) { - document.msExitFullscreen(); - } - } else { - let element; - //HTML elements controls - if (!(document.fullscreenEnabled || document.webkitFullscreenEnabled)) { - // Chrome and FireFox on iOS can only fullscreen a