From 114d5e260e8707c68d09fe5d78d5aac824123b2f Mon Sep 17 00:00:00 2001 From: David MacPherson Date: Tue, 2 Apr 2024 09:48:33 +1000 Subject: [PATCH 01/13] Removed rain drop animation references --- examples/typescript/src/assets/css/index.css | 86 ++++++-------------- library/src/LoadingOverlay.ts | 54 ------------ library/src/SPSApplication.ts | 3 - 3 files changed, 23 insertions(+), 120 deletions(-) diff --git a/examples/typescript/src/assets/css/index.css b/examples/typescript/src/assets/css/index.css index 67dac3f2..e189d172 100644 --- a/examples/typescript/src/assets/css/index.css +++ b/examples/typescript/src/assets/css/index.css @@ -20,81 +20,41 @@ text-align: center; } -#loadingOverlayAnimation { - width: 100%; - height: 100%; - position: absolute; +/* Loading spinner */ +.loading-spinner { + display: inline-block; + position: relative; } -#dropContainer { - width: 100%; - height: 100%; - animation: rain 5s linear infinite; +.loading-spinner div { + box-sizing: border-box; + display: block; position: absolute; + margin: 12.5%; + border: 1px solid var(--color2); + border-radius: 50%; + animation: loading-spinner 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; + border-color: var(--color2) transparent transparent transparent; } -/* Rain drops */ -drop { - position: absolute; - height: 20%; - background: linear-gradient(to bottom, transparent 0%, rgba(255, 255, 255, 0.5) 50%, var(--color11) 100%); - border-bottom-left-radius: 5px; - border-bottom-right-radius: 5px; - overflow: hidden; +.loading-spinner div:nth-child(1) { + animation-delay: -0.45s; +} + +.loading-spinner div:nth-child(2) { + animation-delay: -0.3s; } -/* drop:nth-child(3n + 1) { - background: linear-gradient(to bottom, transparent 0%, rgba(255, 255, 255, 0.5) 50%, var(--color9) 100%); +.loading-spinner div:nth-child(3) { + animation-delay: -0.15s; } -drop:nth-child(3n + 2) { - background: linear-gradient(to bottom, transparent 0%, rgba(255, 255, 255, 0.5) 50%, var(--color10) 100%); -} */ -@keyframes rain { +@keyframes loading-spinner { 0% { - transform: translateY(-20%); + transform: rotate(0deg); } 100% { - transform: translateY(calc(100% + 20%)); + transform: rotate(360deg); } } - -/* Loading spinner */ -.loading-spinner { - display: inline-block; - position: relative; -} -.loading-spinner div { - box-sizing: border-box; - display: block; - position: absolute; - margin: 12.5%; - border: 1px solid var(--color2); - border-radius: 50%; - animation: loading-spinner 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; - border-color: var(--color2) transparent transparent transparent; -} -.loading-spinner div:nth-child(1) { - animation-delay: -0.45s; -} -.loading-spinner div:nth-child(2) { - animation-delay: -0.3s; -} -.loading-spinner div:nth-child(3) { - animation-delay: -0.15s; -} -@keyframes loading-spinner { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - -#drophead { - background-color: var(--color11); - position: absolute; - top: 100%; -} \ No newline at end of file diff --git a/library/src/LoadingOverlay.ts b/library/src/LoadingOverlay.ts index f0f9b5aa..86067e31 100644 --- a/library/src/LoadingOverlay.ts +++ b/library/src/LoadingOverlay.ts @@ -1,11 +1,6 @@ import { TextOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; export class LoadingOverlay extends TextOverlay { - maxDrops = 50; - maxSize = 5; - maxDuration = 5; - minDelay = -20; - rainDrops: Array = []; private static _rootElement: HTMLElement; private static _textElement: HTMLElement; @@ -66,46 +61,6 @@ export class LoadingOverlay extends TextOverlay { super(parentElem, LoadingOverlay.rootElement(), LoadingOverlay.textElement()); } - public animate() { - // Update the existing drops to have an increased speed - for (let raindrop of this.rainDrops) { - raindrop.element.setAttribute("style", "animation-duration:" + (1 + Math.random() * this.maxDuration) + "s;") - } - - let i = 0; - while (i < this.maxDrops) { - const dropContainer = document.createElement("div"); - dropContainer.id = "dropContainer"; - - const raindrop = new Raindrop(); - raindrop.size = Math.random() * this.maxSize + 0.2; - raindrop.delay = Math.random() * this.minDelay; - raindrop.duration = Math.random() * this.maxDuration; - raindrop.offsetLeft = Math.floor(Math.random() * LoadingOverlay.rootElement().clientWidth); - raindrop.element = dropContainer; - - - - const drop = document.createElement("drop"); - drop.setAttribute("style", "left: " + raindrop.offsetLeft + "px; width:" + raindrop.size + "px; overflow: visible;"); - dropContainer.setAttribute("style", "animation-delay:" + raindrop.delay + "s; animation-duration:" + (1 + raindrop.duration) + "s;"); - - const head = document.createElement("div"); - head.id = "drophead"; - raindrop.headsize = raindrop.size * 3; - head.setAttribute("style", "left: -" + raindrop.size + "px; width:" + raindrop.headsize + "px; height: " + raindrop.headsize + "px;"); - drop.appendChild(head); - - dropContainer.appendChild(drop); - LoadingOverlay.rootElement().append(dropContainer); - this.rainDrops.push(raindrop); - i++; - } - - this.maxDrops /= 1.5 - this.maxDuration /= 1.5; - } - /** * Update the text overlays inner text * @param text the update text to be inserted into the overlay @@ -122,12 +77,3 @@ export class LoadingOverlay extends TextOverlay { } } } - -class Raindrop { - size: number; - delay: number; - duration: number; - offsetLeft: number; - headsize: number; - element: HTMLElement; -} \ No newline at end of file diff --git a/library/src/SPSApplication.ts b/library/src/SPSApplication.ts index d225fa12..880e96c9 100644 --- a/library/src/SPSApplication.ts +++ b/library/src/SPSApplication.ts @@ -80,9 +80,6 @@ export class SPSApplication extends Application { this.loadingOverlay.show(); this.loadingOverlay.update(signallingResp); - // disable rain animation for now as perf is too poor on mobile devices - // this.loadingOverlay.animate(); - this.currentOverlay = this.loadingOverlay; } From ffbc2fb9199bbe434a27d20877ddfc40b19b8d58 Mon Sep 17 00:00:00 2001 From: David MacPherson Date: Tue, 2 Apr 2024 09:58:04 +1000 Subject: [PATCH 02/13] Grouped all exports and alphabetised exports --- library/src/index.ts | 114 +++++++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 43 deletions(-) diff --git a/library/src/index.ts b/library/src/index.ts index 995d9dca..0d278c0e 100644 --- a/library/src/index.ts +++ b/library/src/index.ts @@ -1,50 +1,78 @@ // Scalable Pixel Streaming Frontend exports export { SPSApplication } from "./SPSApplication"; export { LoadingOverlay } from "./LoadingOverlay"; -export { MessageSendTypes, MessageStats } from "./Messages"; -export { MessageAuthRequest, InstanceState, MessageInstanceState, MessageAuthResponseOutcomeType, MessageAuthResponse, MessageRequestInstance, SPSSignalling } from "./SignallingExtension"; +export { + MessageSendTypes, + MessageStats +} from "./Messages"; +export { + InstanceState, + MessageAuthRequest, + MessageAuthResponse, + MessageAuthResponseOutcomeType, + MessageInstanceState, + MessageRequestInstance, + SPSSignalling +} from "./SignallingExtension"; // Epic Games Pixel Streaming Frontend exports -export { WebRtcPlayerController } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { WebXRController } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { Config, ControlSchemeType, Flags, NumericParameters, TextParameters, OptionParameters, FlagsIds, NumericParametersIds, TextParametersIds, OptionParametersIds, AllSettings } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { SettingBase } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { SettingFlag } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { SettingNumber } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { SettingOption } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { SettingText } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { PixelStreaming } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { AfkLogic } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { LatencyTestResults } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { EncoderSettings, InitialSettings, WebRTCSettings } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { AggregatedStats } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { Logger } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { UnquantizedAndDenormalizeUnsigned } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { MessageSend } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { MessageRecv, MessageStreamerList } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { WebSocketController } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { SignallingProtocol } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { CandidatePairStats } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { CandidateStat } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { DataChannelStats } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { InboundAudioStats, InboundVideoStats } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; -export { OutBoundVideoStats } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; +export { + AfkLogic, + AggregatedStats, + AllSettings, + CandidatePairStats, + CandidateStat, + Config, ControlSchemeType, + DataChannelStats, + EncoderSettings, + Flags, + FlagsIds, + InboundAudioStats, + InboundVideoStats, + InitialSettings, + LatencyTestResults, + Logger, + MessageRecv, MessageStreamerList, + MessageSend, + NumericParameters, + NumericParametersIds, + OptionParameters, + OptionParametersIds, + OutBoundVideoStats, + PixelStreaming, + SettingBase, + SettingFlag, + SettingNumber, + SettingOption, + SettingText, + SignallingProtocol, + TextParameters, + TextParametersIds, + UnquantizedAndDenormalizeUnsigned, + WebRtcPlayerController, + WebRTCSettings, + WebSocketController, + WebXRController +} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; // Epic Games Pixel Streaming Frontend UI exports -export { Application, UIOptions } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { PixelStreamingApplicationStyle } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { AFKOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { ActionOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { OverlayBase } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { ConnectOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { DisconnectOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { ErrorOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { InfoOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { PlayOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { TextOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { ConfigUI } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { SettingUIBase } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { SettingUIFlag } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { SettingUINumber } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { SettingUIOption } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -export { SettingUIText } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; +export { + ActionOverlay, + AFKOverlay, + Application, + ConfigUI, + ConnectOverlay, + DisconnectOverlay, + ErrorOverlay, + InfoOverlay, + OverlayBase, + PixelStreamingApplicationStyle, + PlayOverlay, + SettingUIBase, + SettingUIFlag, + SettingUINumber, + SettingUIOption, + SettingUIText, + TextOverlay, + UIOptions +} from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; From 47232f301bc209e61241187c1a92809f4694b75f Mon Sep 17 00:00:00 2001 From: David MacPherson Date: Tue, 2 Apr 2024 10:00:17 +1000 Subject: [PATCH 03/13] Renamed _spinner to _spinnerElement --- library/src/LoadingOverlay.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/library/src/LoadingOverlay.ts b/library/src/LoadingOverlay.ts index 86067e31..5a3c0cae 100644 --- a/library/src/LoadingOverlay.ts +++ b/library/src/LoadingOverlay.ts @@ -4,7 +4,7 @@ export class LoadingOverlay extends TextOverlay { private static _rootElement: HTMLElement; private static _textElement: HTMLElement; - private static _spinner: HTMLElement; + private static _spinnerElement: HTMLElement; /** * @returns The created root element of this overlay. @@ -31,27 +31,27 @@ export class LoadingOverlay extends TextOverlay { public static spinner(): HTMLElement { - if (!LoadingOverlay._spinner) { + if (!LoadingOverlay._spinnerElement) { // build the spinner div const size = LoadingOverlay._rootElement.clientWidth * 0.03; - LoadingOverlay._spinner = document.createElement('div'); - LoadingOverlay._spinner.id = "loading-spinner" - LoadingOverlay._spinner.className = "loading-spinner"; - LoadingOverlay._spinner.setAttribute("style", "width: " + size + "px; height: " + size + "px;"); + LoadingOverlay._spinnerElement = document.createElement('div'); + LoadingOverlay._spinnerElement.id = "loading-spinner" + LoadingOverlay._spinnerElement.className = "loading-spinner"; + LoadingOverlay._spinnerElement.setAttribute("style", "width: " + size + "px; height: " + size + "px;"); const SpinnerSectionOne = document.createElement("div"); SpinnerSectionOne.setAttribute("style", "width: " + size * 0.8 + "px; height: " + size * 0.8 + "px; border-width: " + size * 0.125 + "px;"); - LoadingOverlay._spinner.appendChild(SpinnerSectionOne); + LoadingOverlay._spinnerElement.appendChild(SpinnerSectionOne); const SpinnerSectionTwo = document.createElement("div"); SpinnerSectionTwo.setAttribute("style", "width: " + size * 0.8 + "px; height: " + size * 0.8 + "px; border-width: " + size * 0.125 + "px;"); - LoadingOverlay._spinner.appendChild(SpinnerSectionTwo); + LoadingOverlay._spinnerElement.appendChild(SpinnerSectionTwo); const SpinnerSectionThree = document.createElement("div"); SpinnerSectionThree.setAttribute("style", "width: " + size * 0.8 + "px; height: " + size * 0.8 + "px; border-width: " + size * 0.125 + "px;"); - LoadingOverlay._spinner.appendChild(SpinnerSectionThree); + LoadingOverlay._spinnerElement.appendChild(SpinnerSectionThree); } - return LoadingOverlay._spinner; + return LoadingOverlay._spinnerElement; } /** * Construct a connect overlay with a connection button. From 60685f2313c78b26aa8f47869a73b743744ccab0 Mon Sep 17 00:00:00 2001 From: David MacPherson Date: Tue, 2 Apr 2024 12:07:50 +1000 Subject: [PATCH 04/13] Added comments and formatting --- library/src/LoadingOverlay.ts | 45 +++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/library/src/LoadingOverlay.ts b/library/src/LoadingOverlay.ts index 5a3c0cae..2cb2d354 100644 --- a/library/src/LoadingOverlay.ts +++ b/library/src/LoadingOverlay.ts @@ -10,11 +10,17 @@ export class LoadingOverlay extends TextOverlay { * @returns The created root element of this overlay. */ public static rootElement(): HTMLElement { + + // Check if the loading overlay element doesn't exists if (!LoadingOverlay._rootElement) { + + // Create a loading overlay div element LoadingOverlay._rootElement = document.createElement('div'); LoadingOverlay._rootElement.id = "loadingOverlay"; LoadingOverlay._rootElement.className = "textDisplayState"; } + + // Return the loading overlay root element return LoadingOverlay._rootElement; } @@ -22,42 +28,67 @@ export class LoadingOverlay extends TextOverlay { * @returns The created content element of this overlay, which contain whatever content this element contains, like text or a button. */ public static textElement(): HTMLElement { + + // Check if the text element doesn't exists if (!LoadingOverlay._textElement) { + + // Create a text div element LoadingOverlay._textElement = document.createElement('div'); LoadingOverlay._textElement.id = 'loadingOverlayText'; } + + // Return the text element return LoadingOverlay._textElement; } - + /** + * + * @returns The created a loading spinner element + */ public static spinner(): HTMLElement { if (!LoadingOverlay._spinnerElement) { - // build the spinner div + // Get the size of loading spinners root element const size = LoadingOverlay._rootElement.clientWidth * 0.03; + + // Create the loading spinner element LoadingOverlay._spinnerElement = document.createElement('div'); LoadingOverlay._spinnerElement.id = "loading-spinner" LoadingOverlay._spinnerElement.className = "loading-spinner"; LoadingOverlay._spinnerElement.setAttribute("style", "width: " + size + "px; height: " + size + "px;"); + // Create an spinner section element const SpinnerSectionOne = document.createElement("div"); SpinnerSectionOne.setAttribute("style", "width: " + size * 0.8 + "px; height: " + size * 0.8 + "px; border-width: " + size * 0.125 + "px;"); + + // Add the spinner section to spinner element LoadingOverlay._spinnerElement.appendChild(SpinnerSectionOne); + // Create an spinner section element const SpinnerSectionTwo = document.createElement("div"); SpinnerSectionTwo.setAttribute("style", "width: " + size * 0.8 + "px; height: " + size * 0.8 + "px; border-width: " + size * 0.125 + "px;"); + + // Add the spinner section to spinner element LoadingOverlay._spinnerElement.appendChild(SpinnerSectionTwo); + // Create an spinner section element const SpinnerSectionThree = document.createElement("div"); SpinnerSectionThree.setAttribute("style", "width: " + size * 0.8 + "px; height: " + size * 0.8 + "px; border-width: " + size * 0.125 + "px;"); + + // Add the spinner section to spinner element LoadingOverlay._spinnerElement.appendChild(SpinnerSectionThree); } + + // Return the spinner element return LoadingOverlay._spinnerElement; } + /** * Construct a connect overlay with a connection button. * @param parentElem the parent element this overlay will be inserted into. */ public constructor(parentElem: HTMLElement) { + + // Call the parent constructor super(parentElem, LoadingOverlay.rootElement(), LoadingOverlay.textElement()); } @@ -66,13 +97,23 @@ export class LoadingOverlay extends TextOverlay { * @param text the update text to be inserted into the overlay */ public update(text: string): void { + + // Check if the text parameter is valid if (text != null || text != undefined) { + + // Set the text element to an empty string this.textElement.innerHTML = ""; + // Create a text container element let textContainer = document.createElement("div"); + + // Set the element inner html to the text parmater textContainer.innerHTML = text; + + // Append the text container to the text element this.textElement.append(textContainer); + // Append the loading spinner to the text element this.textElement.append(LoadingOverlay.spinner()); } } From 89ee88947ca6945a6e795fc74c91249ba8de9d35 Mon Sep 17 00:00:00 2001 From: David MacPherson Date: Tue, 2 Apr 2024 12:21:09 +1000 Subject: [PATCH 05/13] Formatted and comment --- library/src/Messages.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/src/Messages.ts b/library/src/Messages.ts index 8430cb62..d496c36a 100644 --- a/library/src/Messages.ts +++ b/library/src/Messages.ts @@ -14,7 +14,7 @@ export enum MessageSendTypes { } /** - * Aggregated Stats Message Wrapper + * Aggregated Stats Message Wrapper to send stats to the signalling server */ export class MessageStats extends MessageSend { inboundVideoStats: InboundVideoStats; @@ -30,7 +30,11 @@ export class MessageStats extends MessageSend { */ constructor(aggregatedStats: AggregatedStats) { super(); + + // Set the message type as stats this.type = MessageSendTypes.STATS + + // Map the aggregated stats to the message stats properties this.inboundVideoStats = aggregatedStats.inboundVideoStats; this.inboundAudioStats = aggregatedStats.inboundAudioStats; this.candidatePair = aggregatedStats.getActiveCandidatePair(); From c09b498b99900bc2815f62b80059736cf3284d8c Mon Sep 17 00:00:00 2001 From: David MacPherson Date: Tue, 2 Apr 2024 12:54:47 +1000 Subject: [PATCH 06/13] Added commenting and refactor the instance state message --- library/src/SignallingExtension.ts | 74 ++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/library/src/SignallingExtension.ts b/library/src/SignallingExtension.ts index 6071c5b3..fd7374cc 100644 --- a/library/src/SignallingExtension.ts +++ b/library/src/SignallingExtension.ts @@ -6,14 +6,14 @@ import { } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; /** - * Auth Request Message Wrapper + * Authentication request message wrapper */ export class MessageAuthRequest extends MessageSend { token: string; provider: string; /** - * @param token - Token Provided by the Auth Provider + * @param token - Token provided by the authentication provider * @param provider - Name of the provider that is registered in the auth plugin */ constructor(token: string, provider: string) { @@ -25,17 +25,33 @@ export class MessageAuthRequest extends MessageSend { } /** - * States of the UE Instance + * States of the UE instance request */ export enum InstanceState { + + /** + * The instance is currently unallocated + */ UNALLOCATED = "UNALLOCATED", + + /** + * The instance is currently pending + */ PENDING = "PENDING", + + /** + * The instance failed to start + */ FAILED = "FAILED", + + /** + * The instance is ready + */ READY = "READY" } /** - * Instance State Message wrapper + * Instance state message wrapper */ export class MessageInstanceState extends MessageRecv { state: InstanceState; @@ -47,9 +63,25 @@ export class MessageInstanceState extends MessageRecv { * Types of Authentication reposes */ export enum MessageAuthResponseOutcomeType { + + /** + * The authentication redirected used with Oauth 2.0 + */ REDIRECT = "REDIRECT", + + /** + * The token provided is invalid + */ INVALID_TOKEN = "INVALID_TOKEN", + + /** + * The authentication was successfully authenticated + */ AUTHENTICATED = "AUTHENTICATED", + + /** + * There was an error with authentication + */ ERROR = "ERROR" } @@ -82,10 +114,15 @@ export class MessageRequestInstance extends MessageSend { */ export class SPSSignalling { + // Define the instance state changed event onInstanceStateChanged: (stateChangedMsg: string, isError: boolean) => void; + + // Define the authentication response event onAuthenticationResponse: (authRespMsg: string, isError: boolean) => void; constructor(websocketController: WebSocketController) { + + // Initialise the signalling protocol extensions this.extendSignallingProtocol(websocketController); } @@ -94,38 +131,52 @@ export class SPSSignalling { */ extendSignallingProtocol(webSocketController: WebSocketController) { - // authenticationRequired + // Add the authentication required signalling message to the signalling protocol webSocketController.signallingProtocol.addMessageHandler("authenticationRequired", (authReqPayload: string) => { Logger.Log(Logger.GetStackTrace(), "AUTHENTICATION_REQUIRED", 6); const url_string = window.location.href; const url = new URL(url_string); + + // Create a authentication request message with the token and provider if supplied from the url parameters const authRequest = new MessageAuthRequest(url.searchParams.get("code"), url.searchParams.get("provider")); + + // Send the authentication request message to the signalling server webSocketController.webSocket.send(authRequest.payload()); }); - // instanceState + // Add the instance state signalling message to the signalling protocol webSocketController.signallingProtocol.addMessageHandler("instanceState", (instanceStatePayload: string) => { Logger.Log(Logger.GetStackTrace(), "INSTANCE_STATE", 6); + + // Create a instance state message from the instance state message payload const instanceState: MessageInstanceState = JSON.parse(instanceStatePayload); + + // Call how to handle the instance state changed this.handleInstanceStateChanged(instanceState); }); - // authenticationResponse + // Add the authentication response signalling message to the signalling protocol webSocketController.signallingProtocol.addMessageHandler("authenticationResponse", (authRespPayload: string) => { Logger.Log(Logger.GetStackTrace(), "AUTHENTICATION_RESPONSE", 6); + // Create the authentication response from the authentication response payload const authenticationResponse: MessageAuthResponse = JSON.parse(authRespPayload); + // Call how to handle the authentication response this.handleAuthenticationResponse(authenticationResponse); + // Handle the type of the authentication response switch (authenticationResponse.outcome) { case MessageAuthResponseOutcomeType.REDIRECT: { + + // Redirect the location to the redirect value window.location.href = authenticationResponse.redirect; break; } case MessageAuthResponseOutcomeType.AUTHENTICATED: { Logger.Log(Logger.GetStackTrace(), "User is authenticated and now requesting an instance", 6); + // Send a instance request massage to the signalling server webSocketController.webSocket.send(new MessageRequestInstance().payload()); break; } @@ -155,7 +206,7 @@ export class SPSSignalling { let isInstancePending = false; let isError = false; - // get the response type + // Create an informative message based on the state of the instance switch (instanceState.state) { case InstanceState.UNALLOCATED: instanceStateMessage = "Instance Unallocated: " + instanceState.details; @@ -186,11 +237,8 @@ export class SPSSignalling { break; } - if (isError) { - this.onInstanceStateChanged(instanceStateMessage, true); - } else { - this.onInstanceStateChanged(instanceStateMessage, false); - } + // Emit an instance state changed with error + this.onInstanceStateChanged(instanceStateMessage, isError); } /** From 84180fd1d36ccfcf61080384dbd10e4435d0fea9 Mon Sep 17 00:00:00 2001 From: David MacPherson Date: Tue, 2 Apr 2024 12:57:24 +1000 Subject: [PATCH 07/13] Added commenting and formatting --- library/src/SignallingExtension.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/src/SignallingExtension.ts b/library/src/SignallingExtension.ts index fd7374cc..da2987be 100644 --- a/library/src/SignallingExtension.ts +++ b/library/src/SignallingExtension.ts @@ -237,7 +237,7 @@ export class SPSSignalling { break; } - // Emit an instance state changed with error + // Emit an instance state changed with an informative message and if error occurred this.onInstanceStateChanged(instanceStateMessage, isError); } @@ -249,7 +249,7 @@ export class SPSSignalling { let instanceStateMessage = ""; let isError = false; - // get the response type + // Create an informative message based on the state of the authentication response switch (authResponse.outcome) { case MessageAuthResponseOutcomeType.AUTHENTICATED: instanceStateMessage = "Step 1/3: Requesting Instance"; @@ -270,6 +270,7 @@ export class SPSSignalling { break; } + // Emit an authentication response with an informative message and if an error occurred this.onAuthenticationResponse(instanceStateMessage, isError); } -} \ No newline at end of file +} From f79f83fcf144b4acd41c60fe05bb862ec18abaf0 Mon Sep 17 00:00:00 2001 From: David MacPherson Date: Tue, 2 Apr 2024 12:59:31 +1000 Subject: [PATCH 08/13] Changed formatting of imported libraries --- library/src/SPSApplication.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/library/src/SPSApplication.ts b/library/src/SPSApplication.ts index 880e96c9..934b0cd5 100644 --- a/library/src/SPSApplication.ts +++ b/library/src/SPSApplication.ts @@ -1,8 +1,16 @@ -import { Application, SettingUIFlag, UIOptions } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -import { AggregatedStats, SettingFlag, TextParameters } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; import { LoadingOverlay } from './LoadingOverlay'; import { SPSSignalling } from './SignallingExtension'; import { MessageStats } from './Messages'; +import { + AggregatedStats, + SettingFlag, + TextParameters +} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; +import { + Application, + SettingUIFlag, + UIOptions +} from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; // For local testing. Declare a websocket URL that can be imported via a .env file that will override // the signalling server URL builder. @@ -61,7 +69,7 @@ export class SPSApplication extends Application { this.stream.setSignallingUrlBuilder(() => { // if we have overriden the signalling server URL with a .env file use it here - if (WEBSOCKET_URL !== undefined ) { + if (WEBSOCKET_URL !== undefined) { return WEBSOCKET_URL as string; } From b133fed34205b4661ffe1d86b58926dc6f63afc7 Mon Sep 17 00:00:00 2001 From: David MacPherson Date: Tue, 2 Apr 2024 13:00:03 +1000 Subject: [PATCH 09/13] Removed un-needed new line --- library/src/SPSApplication.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/library/src/SPSApplication.ts b/library/src/SPSApplication.ts index 934b0cd5..9cabce74 100644 --- a/library/src/SPSApplication.ts +++ b/library/src/SPSApplication.ts @@ -16,7 +16,6 @@ import { // the signalling server URL builder. declare var WEBSOCKET_URL: string; - export class SPSApplication extends Application { private loadingOverlay: LoadingOverlay; private signallingExtension: SPSSignalling; From afd79248cfd3965d6b2765c017aebf03097d64b0 Mon Sep 17 00:00:00 2001 From: David MacPherson Date: Tue, 2 Apr 2024 13:38:36 +1000 Subject: [PATCH 10/13] Commenting and formatting --- library/src/SPSApplication.ts | 52 ++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/library/src/SPSApplication.ts b/library/src/SPSApplication.ts index 9cabce74..1b947a5b 100644 --- a/library/src/SPSApplication.ts +++ b/library/src/SPSApplication.ts @@ -20,20 +20,26 @@ export class SPSApplication extends Application { private loadingOverlay: LoadingOverlay; private signallingExtension: SPSSignalling; + // Create a flags class for the send stats to server static Flags = class { static sendToServer = "sendStatsToServer" } constructor(config: UIOptions) { super(config); + + // Initialise the signaling server extensions to support sps signalling messages this.signallingExtension = new SPSSignalling(this.stream.webSocketController); this.signallingExtension.onAuthenticationResponse = this.handleSignallingResponse.bind(this); this.signallingExtension.onInstanceStateChanged = this.handleSignallingResponse.bind(this); + // Enforce the munging of the websocket address to support SPS this.enforceSpecialSignallingServerUrl(); - // Add 'Send Stats to Server' checkbox + // Add a SPS settings section to the settings panel const spsSettingsSection = this.configUI.buildSectionWithHeading(this.settingsPanel.settingsContentElement, "Scalable Pixel Streaming"); + + // Add the 'Send Stats to server' check box to the list of settings const sendStatsToServerSetting = new SettingFlag( SPSApplication.Flags.sendToServer, "Send stats to server", @@ -42,9 +48,13 @@ export class SPSApplication extends Application { this.stream.config.useUrlParams ); + // Add the 'Send Stats to server' check box to the sps settings section spsSettingsSection.appendChild(new SettingUIFlag(sendStatsToServerSetting).rootElement); + + // Initialise the loading overlay this.loadingOverlay = new LoadingOverlay(this.stream.videoElementParent); + // Add an event handler for when the statReceive event is emitted this.stream.addEventListener( 'statsReceived', ({ data: { aggregatedStats } }) => { @@ -55,38 +65,68 @@ export class SPSApplication extends Application { ); } + /** + * Handled the response when the sps messages are emitted + * @param signallingResp the informative response message + * @param isError if the message is an error + */ handleSignallingResponse(signallingResp: string, isError: boolean) { + + // Check if the message is an error if (isError) { + + // Show the error overlay this.showErrorOverlay(signallingResp); } else { + + // Show the loading overlay this.showLoadingOverlay(signallingResp); } } + /** + * Enforces changes the websocket path to conform to the SPS specification + * Can be overridden if the WEBSOCKET_URL var defined in the .env file has been defined + */ enforceSpecialSignallingServerUrl() { + // SPS needs to build a specific signalling server url based on the application name so K8s can distinguish it this.stream.setSignallingUrlBuilder(() => { - // if we have overriden the signalling server URL with a .env file use it here + // Check if the WEBSOCKET_URL var in the .env file has been defined if (WEBSOCKET_URL !== undefined) { + + // Return the value of the WEBSOCKET_URL var defined in the .env file return WEBSOCKET_URL as string; } - // get the current signalling url + // Get the current signalling server URL from the settings let signallingUrl = this.stream.config.getTextSettingValue(TextParameters.SignallingServerUrl); - // build the signalling URL based on the existing window location, the result should be 'domain.com/signalling/app-name' + // Build the signalling URL based on the existing window location, the result should be 'domain.com/signalling/app-name' signallingUrl = signallingUrl.endsWith("/") ? signallingUrl + "signalling" + window.location.pathname : signallingUrl + "/signalling" + window.location.pathname; + // Return the modified signalling server URL return signallingUrl }); } + /** + * Shows the loading overlay + * @param signallingResp The informative message to display + */ showLoadingOverlay(signallingResp: string) { + + // Hide the current overlay this.hideCurrentOverlay(); + + // Show the loading overlay this.loadingOverlay.show(); + + // Update the loading overlay with the signalling response this.loadingOverlay.update(signallingResp); + // Set the current overlay to the loading overlay this.currentOverlay = this.loadingOverlay; } @@ -95,7 +135,11 @@ export class SPSApplication extends Application { * @param stats - Aggregated Stats */ sendStatsToSignallingServer(stats: AggregatedStats) { + + // Create a new stats signalling message const data = new MessageStats(stats); + + // Send the stats message to the signalling server this.stream.webSocketController.webSocket.send(data.payload()); } } From 529670cc81bcc7849a90732b399aa5fb9bb76c1a Mon Sep 17 00:00:00 2001 From: David MacPherson Date: Tue, 2 Apr 2024 13:39:06 +1000 Subject: [PATCH 11/13] Changed the signalling resp to message --- library/src/SPSApplication.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/src/SPSApplication.ts b/library/src/SPSApplication.ts index 1b947a5b..2b0da763 100644 --- a/library/src/SPSApplication.ts +++ b/library/src/SPSApplication.ts @@ -113,9 +113,9 @@ export class SPSApplication extends Application { /** * Shows the loading overlay - * @param signallingResp The informative message to display + * @param message The message to display */ - showLoadingOverlay(signallingResp: string) { + showLoadingOverlay(message: string) { // Hide the current overlay this.hideCurrentOverlay(); @@ -124,7 +124,7 @@ export class SPSApplication extends Application { this.loadingOverlay.show(); // Update the loading overlay with the signalling response - this.loadingOverlay.update(signallingResp); + this.loadingOverlay.update(message); // Set the current overlay to the loading overlay this.currentOverlay = this.loadingOverlay; From 08b8281ce95713f406950ed555b4c37e31991f87 Mon Sep 17 00:00:00 2001 From: David MacPherson Date: Tue, 2 Apr 2024 13:49:57 +1000 Subject: [PATCH 12/13] Changed formatting of imports to multilined and alphabetise --- examples/typescript/src/index.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/typescript/src/index.ts b/examples/typescript/src/index.ts index cd8507fc..6614b6a1 100644 --- a/examples/typescript/src/index.ts +++ b/examples/typescript/src/index.ts @@ -1,4 +1,11 @@ -import { Config, PixelStreaming, SPSApplication, TextParameters, PixelStreamingApplicationStyle, MessageRecv, Flags } from "@tensorworks/libspsfrontend"; +import { + Config, + Flags, + MessageRecv, + PixelStreaming, + PixelStreamingApplicationStyle, + SPSApplication +} from "@tensorworks/libspsfrontend"; // Apply default styling from Epic Games Pixel Streaming Frontend export const PixelStreamingApplicationStyles = new PixelStreamingApplicationStyle(); From e9742699e6fc9edaafbc1e1ab1f70497389cb97d Mon Sep 17 00:00:00 2001 From: David MacPherson Date: Tue, 2 Apr 2024 13:54:49 +1000 Subject: [PATCH 13/13] Commenting and formatting --- examples/typescript/src/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/typescript/src/index.ts b/examples/typescript/src/index.ts index 6614b6a1..b670687c 100644 --- a/examples/typescript/src/index.ts +++ b/examples/typescript/src/index.ts @@ -27,6 +27,7 @@ class ScalablePixelStreaming extends PixelStreaming { } }; +// Initialise the SPS frontend on load of the body element document.body.onload = function () { // Create a config object. We default to sending the WebRTC offer from the browser as true, TimeoutIfIdle to true, AutoConnect to false and MaxReconnectAttempts to 0 @@ -41,10 +42,12 @@ document.body.onload = function () { stream.handleOnConfig(messageExtendedConfig); } - // Create and append our application + // Create the SPS application const spsApplication = new SPSApplication({ stream, onColorModeChanged: (isLightMode) => PixelStreamingApplicationStyles.setColorMode(isLightMode) /* Light/Dark mode support. */ }); + + // Append the SPS application element to the document body element document.body.appendChild(spsApplication.rootElement); } \ No newline at end of file