diff --git a/examples/typescript/package-lock.json b/examples/typescript/package-lock.json index 0826def..6109e29 100644 --- a/examples/typescript/package-lock.json +++ b/examples/typescript/package-lock.json @@ -1,12 +1,12 @@ { "name": "@tensorworks/spstypescriptexample", - "version": "0.0.1", + "version": "0.0.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@tensorworks/spstypescriptexample", - "version": "0.0.1", + "version": "0.0.3", "license": "MIT", "dependencies": { "dotenv": "^16.0.3" diff --git a/examples/typescript/package.json b/examples/typescript/package.json index 8f8162d..50e2a44 100644 --- a/examples/typescript/package.json +++ b/examples/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@tensorworks/spstypescriptexample", - "version": "0.0.2", + "version": "0.0.3", "description": "The typescript example for consuming the Scalable Pixel Streaming Frontend", "main": "./src/index.ts", "scripts": { diff --git a/examples/typescript/src/index.ts b/examples/typescript/src/index.ts index 93497d6..66f1d30 100644 --- a/examples/typescript/src/index.ts +++ b/examples/typescript/src/index.ts @@ -1,61 +1,79 @@ -import { Config, PixelStreaming, SPSApplication, TextParameters, PixelStreamingApplicationStyle, MessageRecv, Flags, WebRtcDisconnectedEvent } from "@tensorworks/libspsfrontend"; - -// Apply default styling from Epic Games Pixel Streaming Frontend -export const PixelStreamingApplicationStyles = new PixelStreamingApplicationStyle(); -PixelStreamingApplicationStyles.applyStyleSheet(); - -// Extend the MessageRecv to allow the engine version to exist as part of our config message from the signalling server -class MessageExtendedConfig extends MessageRecv { - peerConnectionOptions: RTCConfiguration; - engineVersion: string; - platform: string; - frontendToSendOffer: boolean; -}; - -// Extend PixelStreaming to use our custom extended config that includes the engine version -class ScalablePixelStreaming extends PixelStreaming { - // Create a new method that retains original functionality - public handleOnConfig(messageExtendedConfig: MessageExtendedConfig) { - this._webRtcController.handleOnConfigMessage(messageExtendedConfig); - } -}; - -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 - const config = new Config({ useUrlParams: true, initialSettings: { OfferToReceive: true, TimeoutIfIdle: true, AutoConnect: false, MaxReconnectAttempts: 0 } }); - - // Create stream and spsApplication instances that implement the Epic Games Pixel Streaming Frontend PixelStreaming and Application types - const stream = new ScalablePixelStreaming(config); - - // Override the onConfig so we can determine if we need to send the WebRTC offer based on what is sent from the signalling server - stream.webSocketController.onConfig = (messageExtendedConfig: MessageExtendedConfig) => { - stream.config.setFlagEnabled(Flags.BrowserSendOffer, messageExtendedConfig.frontendToSendOffer); - stream.handleOnConfig(messageExtendedConfig); - } - - // override the _onDisconnect function to intercept webrtc disconnect events - // and modify how the event is fired by always showing a click to reconnect overlay. - // we also add a full stop to the AFK message. - stream._onDisconnect = function (eventString: string) { - - // check if the eventString coming in is the inactivity string and add a full stop - if (eventString == "You have been disconnected due to inactivity") { - eventString += "." - } - - this._eventEmitter.dispatchEvent( - new WebRtcDisconnectedEvent({ - eventString: eventString, - allowClickToReconnect: true - }) - ); - } - - // Create and append our application - const spsApplication = new SPSApplication({ - stream, - onColorModeChanged: (isLightMode) => PixelStreamingApplicationStyles.setColorMode(isLightMode) /* Light/Dark mode support. */ - }); - document.body.appendChild(spsApplication.rootElement); +import { Config, PixelStreaming, SPSApplication, PixelStreamingApplicationStyle, Flags, TextParameters, BaseMessage, WebRtcDisconnectedEvent } from "@tensorworks/libspsfrontend"; + +// Apply default styling from Epic Games Pixel Streaming Frontend +export const PixelStreamingApplicationStyles = new PixelStreamingApplicationStyle(); +PixelStreamingApplicationStyles.applyStyleSheet(); + +// Extend the default "Config" message supplied by PSInfra library to include the following: +// - Engine version +// - Platform +// - FrontendSendOffer +class MessageExtendedConfig implements BaseMessage { + type: string; + peerConnectionOptions: RTCConfiguration; + engineVersion: string; + platform: string; + frontendToSendOffer: boolean; +}; + +// Extend PixelStreaming to use our custom extended config that includes the engine version +class ScalablePixelStreaming extends PixelStreaming { + // Create a new method that retains original functionality + public handleOnConfig(messageExtendedConfig: MessageExtendedConfig) { + this._webRtcController.handleOnConfigMessage(messageExtendedConfig); + } +}; + +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 + const config = new Config({ useUrlParams: true, initialSettings: { OfferToReceive: true, TimeoutIfIdle: true, AutoConnect: false, MaxReconnectAttempts: 0 } }); + + // Handle setting custom signalling url from code or by querying url parameters (e.g. ?ss=ws://my.signaling.server). + { + // Replace with your custom signalling url if you need to. + // Otherwise SPS will use ws|wss://window.location.host/signalling/window.location.pathname + let YOUR_CUSTOM_SIGNALLING_URL_HERE : string = ""; // <-- replace here + + // Check the ?ss= url parameter for a custom signalling url. + const urlParams = new URLSearchParams(window.location.search); + if (urlParams.has(TextParameters.SignallingServerUrl)) { + YOUR_CUSTOM_SIGNALLING_URL_HERE = urlParams.get(TextParameters.SignallingServerUrl); + } + config.setTextSetting(TextParameters.SignallingServerUrl, YOUR_CUSTOM_SIGNALLING_URL_HERE); + } + + // Create stream and spsApplication instances that implement the Epic Games Pixel Streaming Frontend PixelStreaming and Application types + const stream = new ScalablePixelStreaming(config); + + // Override the onConfig so we can determine if we need to send the WebRTC offer based on what is sent from the signalling server + stream.signallingProtocol.addListener("config", (config : MessageExtendedConfig) => { + stream.config.setFlagEnabled(Flags.BrowserSendOffer, config.frontendToSendOffer); + stream.handleOnConfig(config); + }); + + // override the _onDisconnect function to intercept webrtc disconnect events + // and modify how the event is fired by always showing a click to reconnect overlay. + // we also add a full stop to the AFK message. + stream._onDisconnect = function (eventString: string) { + + // check if the eventString coming in is the inactivity string and add a full stop + if (eventString == "You have been disconnected due to inactivity") { + eventString += "." + } + + this._eventEmitter.dispatchEvent( + new WebRtcDisconnectedEvent({ + eventString: eventString, + allowClickToReconnect: true + }) + ); + } + + // Create and append our application + const spsApplication = new SPSApplication({ + stream, + onColorModeChanged: (isLightMode) => PixelStreamingApplicationStyles.setColorMode(isLightMode) /* Light/Dark mode support. */ + }); + document.body.appendChild(spsApplication.rootElement); } \ No newline at end of file diff --git a/library/package-lock.json b/library/package-lock.json index 4c27c69..e40fbec 100644 --- a/library/package-lock.json +++ b/library/package-lock.json @@ -1,16 +1,16 @@ { "name": "@tensorworks/libspsfrontend", - "version": "0.3.4", + "version": "0.4.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@tensorworks/libspsfrontend", - "version": "0.3.4", + "version": "0.4.0", "license": "MIT", "dependencies": { - "@epicgames-ps/lib-pixelstreamingfrontend-ue5.4": "^0.0.4", - "@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4": "^0.0.4" + "@epicgames-ps/lib-pixelstreamingfrontend-ue5.5": "^0.1.2", + "@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5": "^0.1.0" }, "devDependencies": { "css-loader": "^6.7.3", @@ -25,11 +25,11 @@ } }, "node_modules/@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", + "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", "dependencies": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" @@ -44,25 +44,36 @@ "node": ">=10.0.0" } }, - "node_modules/@epicgames-ps/lib-pixelstreamingfrontend-ue5.4": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingfrontend-ue5.4/-/lib-pixelstreamingfrontend-ue5.4-0.0.4.tgz", - "integrity": "sha512-PrfrTJ6rf/yxp/GXVDM3hwSyMUooUYd/z90TMxaYcTWU3RbXG8qT85pS5dceGoPwCkwLIiznpWOPOSq70bUupg==", + "node_modules/@epicgames-ps/lib-pixelstreamingcommon-ue5.5": { + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingcommon-ue5.5/-/lib-pixelstreamingcommon-ue5.5-0.0.14.tgz", + "integrity": "sha512-GXu1GJUfXAWnTHylBYAfvE9SVPXl8B6ovD/6CbQh0AXxktadbA4KsDbuEFuZHIVEVLLn6vXsBkkKf7yZODphOQ==", "dependencies": { + "@protobuf-ts/plugin": "^2.9.3", + "@types/ws": "^8.5.10", + "ws": "^8.17.1" + } + }, + "node_modules/@epicgames-ps/lib-pixelstreamingfrontend-ue5.5": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingfrontend-ue5.5/-/lib-pixelstreamingfrontend-ue5.5-0.1.2.tgz", + "integrity": "sha512-jpjpZTc1vZZNQ+xRxnPmNeBc3U+Wxx6C7iSGZrBRqkVXkDV6C8oV+yoTgKN4JWTvpXUOLRQ/9MJR5wYCWnxu1Q==", + "dependencies": { + "@epicgames-ps/lib-pixelstreamingcommon-ue5.5": "^0.0.14", "sdp": "^3.1.0" } }, - "node_modules/@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4/-/lib-pixelstreamingfrontend-ui-ue5.4-0.0.4.tgz", - "integrity": "sha512-RFwWo4vY9DRhiVKWWLMBsagpIxiJoQ+GBtI2OmzcgAAb8djGHMDAiljyagwIpTW6r6rxQrl10AGCSlZDKeQSvQ==", + "node_modules/@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5/-/lib-pixelstreamingfrontend-ui-ue5.5-0.1.0.tgz", + "integrity": "sha512-WUfemK/iO/oqb916W4RQrrYufYJ3zHk6KHn8R/m7HLL/0MP6gnXpvvSSs1m/hXwtPR3u4PrB+2kOMCmXtFN57A==", "dependencies": { "jss": "^10.9.2", "jss-plugin-camel-case": "^10.9.2", "jss-plugin-global": "^10.9.2" }, "peerDependencies": { - "@epicgames-ps/lib-pixelstreamingfrontend-ue5.4": "^0.0.4" + "@epicgames-ps/lib-pixelstreamingfrontend-ue5.5": "^0.1.0" } }, "node_modules/@jridgewell/gen-mapping": { @@ -135,6 +146,76 @@ "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "dev": true }, + "node_modules/@protobuf-ts/plugin": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.9.4.tgz", + "integrity": "sha512-Db5Laq5T3mc6ERZvhIhkj1rn57/p8gbWiCKxQWbZBBl20wMuqKoHbRw4tuD7FyXi+IkwTToaNVXymv5CY3E8Rw==", + "dependencies": { + "@protobuf-ts/plugin-framework": "^2.9.4", + "@protobuf-ts/protoc": "^2.9.4", + "@protobuf-ts/runtime": "^2.9.4", + "@protobuf-ts/runtime-rpc": "^2.9.4", + "typescript": "^3.9" + }, + "bin": { + "protoc-gen-dump": "bin/protoc-gen-dump", + "protoc-gen-ts": "bin/protoc-gen-ts" + } + }, + "node_modules/@protobuf-ts/plugin-framework": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.9.4.tgz", + "integrity": "sha512-9nuX1kjdMliv+Pes8dQCKyVhjKgNNfwxVHg+tx3fLXSfZZRcUHMc1PMwB9/vTvc6gBKt9QGz5ERqSqZc0++E9A==", + "dependencies": { + "@protobuf-ts/runtime": "^2.9.4", + "typescript": "^3.9" + } + }, + "node_modules/@protobuf-ts/plugin-framework/node_modules/typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@protobuf-ts/plugin/node_modules/typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/@protobuf-ts/protoc": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.9.4.tgz", + "integrity": "sha512-hQX+nOhFtrA+YdAXsXEDrLoGJqXHpgv4+BueYF0S9hy/Jq0VRTVlJS1Etmf4qlMt/WdigEes5LOd/LDzui4GIQ==", + "bin": { + "protoc": "protoc.js" + } + }, + "node_modules/@protobuf-ts/runtime": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.9.4.tgz", + "integrity": "sha512-vHRFWtJJB/SiogWDF0ypoKfRIZ41Kq+G9cEFj6Qm1eQaAhJ1LDFvgZ7Ja4tb3iLOQhz0PaoPnnOijF1qmEqTxg==" + }, + "node_modules/@protobuf-ts/runtime-rpc": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.9.4.tgz", + "integrity": "sha512-y9L9JgnZxXFqH5vD4d7j9duWvIJ7AShyBRoNKJGhu9Q27qIbchfzli66H9RvrQNIFk5ER7z1Twe059WZGqERcA==", + "dependencies": { + "@protobuf-ts/runtime": "^2.9.4" + } + }, "node_modules/@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -252,8 +333,7 @@ "node_modules/@types/node": { "version": "18.15.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", - "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==", - "dev": true + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -302,10 +382,9 @@ } }, "node_modules/@types/ws": { - "version": "8.5.4", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", - "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", - "dev": true, + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", "dependencies": { "@types/node": "*" } @@ -1130,9 +1209,9 @@ } }, "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/debug": { "version": "2.6.9", @@ -2023,9 +2102,9 @@ } }, "node_modules/hyphenate-style-name": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", - "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz", + "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==" }, "node_modules/iconv-lite": { "version": "0.4.24", @@ -3114,9 +3193,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/relateurl": { "version": "0.2.7", @@ -4282,10 +4361,9 @@ "dev": true }, "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "dev": true, + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "engines": { "node": ">=10.0.0" }, @@ -4311,11 +4389,11 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", + "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", "requires": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" } }, "@discoveryjs/json-ext": { @@ -4324,18 +4402,29 @@ "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "dev": true }, - "@epicgames-ps/lib-pixelstreamingfrontend-ue5.4": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingfrontend-ue5.4/-/lib-pixelstreamingfrontend-ue5.4-0.0.4.tgz", - "integrity": "sha512-PrfrTJ6rf/yxp/GXVDM3hwSyMUooUYd/z90TMxaYcTWU3RbXG8qT85pS5dceGoPwCkwLIiznpWOPOSq70bUupg==", + "@epicgames-ps/lib-pixelstreamingcommon-ue5.5": { + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingcommon-ue5.5/-/lib-pixelstreamingcommon-ue5.5-0.0.14.tgz", + "integrity": "sha512-GXu1GJUfXAWnTHylBYAfvE9SVPXl8B6ovD/6CbQh0AXxktadbA4KsDbuEFuZHIVEVLLn6vXsBkkKf7yZODphOQ==", "requires": { + "@protobuf-ts/plugin": "^2.9.3", + "@types/ws": "^8.5.10", + "ws": "^8.17.1" + } + }, + "@epicgames-ps/lib-pixelstreamingfrontend-ue5.5": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingfrontend-ue5.5/-/lib-pixelstreamingfrontend-ue5.5-0.1.2.tgz", + "integrity": "sha512-jpjpZTc1vZZNQ+xRxnPmNeBc3U+Wxx6C7iSGZrBRqkVXkDV6C8oV+yoTgKN4JWTvpXUOLRQ/9MJR5wYCWnxu1Q==", + "requires": { + "@epicgames-ps/lib-pixelstreamingcommon-ue5.5": "^0.0.14", "sdp": "^3.1.0" } }, - "@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4/-/lib-pixelstreamingfrontend-ui-ue5.4-0.0.4.tgz", - "integrity": "sha512-RFwWo4vY9DRhiVKWWLMBsagpIxiJoQ+GBtI2OmzcgAAb8djGHMDAiljyagwIpTW6r6rxQrl10AGCSlZDKeQSvQ==", + "@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5/-/lib-pixelstreamingfrontend-ui-ue5.5-0.1.0.tgz", + "integrity": "sha512-WUfemK/iO/oqb916W4RQrrYufYJ3zHk6KHn8R/m7HLL/0MP6gnXpvvSSs1m/hXwtPR3u4PrB+2kOMCmXtFN57A==", "requires": { "jss": "^10.9.2", "jss-plugin-camel-case": "^10.9.2", @@ -4405,6 +4494,59 @@ "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "dev": true }, + "@protobuf-ts/plugin": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin/-/plugin-2.9.4.tgz", + "integrity": "sha512-Db5Laq5T3mc6ERZvhIhkj1rn57/p8gbWiCKxQWbZBBl20wMuqKoHbRw4tuD7FyXi+IkwTToaNVXymv5CY3E8Rw==", + "requires": { + "@protobuf-ts/plugin-framework": "^2.9.4", + "@protobuf-ts/protoc": "^2.9.4", + "@protobuf-ts/runtime": "^2.9.4", + "@protobuf-ts/runtime-rpc": "^2.9.4", + "typescript": "^3.9" + }, + "dependencies": { + "typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==" + } + } + }, + "@protobuf-ts/plugin-framework": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/plugin-framework/-/plugin-framework-2.9.4.tgz", + "integrity": "sha512-9nuX1kjdMliv+Pes8dQCKyVhjKgNNfwxVHg+tx3fLXSfZZRcUHMc1PMwB9/vTvc6gBKt9QGz5ERqSqZc0++E9A==", + "requires": { + "@protobuf-ts/runtime": "^2.9.4", + "typescript": "^3.9" + }, + "dependencies": { + "typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==" + } + } + }, + "@protobuf-ts/protoc": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/protoc/-/protoc-2.9.4.tgz", + "integrity": "sha512-hQX+nOhFtrA+YdAXsXEDrLoGJqXHpgv4+BueYF0S9hy/Jq0VRTVlJS1Etmf4qlMt/WdigEes5LOd/LDzui4GIQ==" + }, + "@protobuf-ts/runtime": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.9.4.tgz", + "integrity": "sha512-vHRFWtJJB/SiogWDF0ypoKfRIZ41Kq+G9cEFj6Qm1eQaAhJ1LDFvgZ7Ja4tb3iLOQhz0PaoPnnOijF1qmEqTxg==" + }, + "@protobuf-ts/runtime-rpc": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.9.4.tgz", + "integrity": "sha512-y9L9JgnZxXFqH5vD4d7j9duWvIJ7AShyBRoNKJGhu9Q27qIbchfzli66H9RvrQNIFk5ER7z1Twe059WZGqERcA==", + "requires": { + "@protobuf-ts/runtime": "^2.9.4" + } + }, "@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -4522,8 +4664,7 @@ "@types/node": { "version": "18.15.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", - "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==", - "dev": true + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" }, "@types/qs": { "version": "6.9.7", @@ -4572,10 +4713,9 @@ } }, "@types/ws": { - "version": "8.5.4", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", - "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", - "dev": true, + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", "requires": { "@types/node": "*" } @@ -5209,9 +5349,9 @@ "dev": true }, "csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "debug": { "version": "2.6.9", @@ -5891,9 +6031,9 @@ "dev": true }, "hyphenate-style-name": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", - "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz", + "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==" }, "iconv-lite": { "version": "0.4.24", @@ -6700,9 +6840,9 @@ } }, "regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "relateurl": { "version": "0.2.7", @@ -7548,10 +7688,9 @@ "dev": true }, "ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "dev": true, + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "requires": {} }, "yallist": { diff --git a/library/package.json b/library/package.json index b0678aa..9be2f11 100644 --- a/library/package.json +++ b/library/package.json @@ -1,6 +1,6 @@ { "name": "@tensorworks/libspsfrontend", - "version": "0.3.4", + "version": "0.4.0", "description": "The Scalable Pixel Streaming Frontend Library consuming Epic Games' Pixel Streaming Frontend", "main": "dist/libspsfrontend.min.js", "module": "dist/libspsfrontend.esm.js", @@ -14,8 +14,8 @@ "author": "TensorWorks Pty Ltd", "license": "MIT", "dependencies": { - "@epicgames-ps/lib-pixelstreamingfrontend-ue5.4": "^0.0.4", - "@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4": "^0.0.4" + "@epicgames-ps/lib-pixelstreamingfrontend-ue5.5": "^0.1.2", + "@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5": "^0.1.0" }, "devDependencies": { "css-loader": "^6.7.3", diff --git a/library/src/LoadingOverlay.ts b/library/src/LoadingOverlay.ts index 86067e3..22251b4 100644 --- a/library/src/LoadingOverlay.ts +++ b/library/src/LoadingOverlay.ts @@ -1,4 +1,4 @@ -import { TextOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; +import { TextOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; export class LoadingOverlay extends TextOverlay { diff --git a/library/src/Messages.ts b/library/src/Messages.ts index 8430cb6..9520616 100644 --- a/library/src/Messages.ts +++ b/library/src/Messages.ts @@ -5,18 +5,15 @@ import { DataChannelStats, InboundAudioStats, InboundVideoStats, - MessageSend, + BaseMessage, OutBoundVideoStats -} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; - -export enum MessageSendTypes { - STATS = "stats", -} +} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; /** * Aggregated Stats Message Wrapper */ -export class MessageStats extends MessageSend { +export class MessageStats implements BaseMessage { + type: string; inboundVideoStats: InboundVideoStats; inboundAudioStats: InboundAudioStats; candidatePair: CandidatePairStats; @@ -26,11 +23,10 @@ export class MessageStats extends MessageSend { outboundVideoStats: OutBoundVideoStats; /** - * @param aggregatedStats - Aggregated Stats + * @param aggregatedStats - Aggregated Stats */ constructor(aggregatedStats: AggregatedStats) { - super(); - this.type = MessageSendTypes.STATS + this.type = "stats"; this.inboundVideoStats = aggregatedStats.inboundVideoStats; this.inboundAudioStats = aggregatedStats.inboundAudioStats; this.candidatePair = aggregatedStats.getActiveCandidatePair(); diff --git a/library/src/SPSApplication.ts b/library/src/SPSApplication.ts index 880e96c..695add2 100644 --- a/library/src/SPSApplication.ts +++ b/library/src/SPSApplication.ts @@ -1,5 +1,5 @@ -import { Application, SettingUIFlag, UIOptions } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4'; -import { AggregatedStats, SettingFlag, TextParameters } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; +import { Application, SettingUIFlag, UIOptions } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +import { AggregatedStats, SettingFlag, TextParameters } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; import { LoadingOverlay } from './LoadingOverlay'; import { SPSSignalling } from './SignallingExtension'; import { MessageStats } from './Messages'; @@ -19,7 +19,7 @@ export class SPSApplication extends Application { constructor(config: UIOptions) { super(config); - this.signallingExtension = new SPSSignalling(this.stream.webSocketController); + this.signallingExtension = new SPSSignalling(this.stream.signallingProtocol); this.signallingExtension.onAuthenticationResponse = this.handleSignallingResponse.bind(this); this.signallingExtension.onInstanceStateChanged = this.handleSignallingResponse.bind(this); @@ -60,18 +60,26 @@ export class SPSApplication extends Application { // 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 + // If we have overriden the signalling server URL with a .env file use it here if (WEBSOCKET_URL !== undefined ) { return WEBSOCKET_URL as string; } - // get the current signalling url - let signallingUrl = this.stream.config.getTextSettingValue(TextParameters.SignallingServerUrl); + // If there is signalling url specified, then use that. + let customSignallingUrl = this.stream.config.getTextSettingValue(TextParameters.SignallingServerUrl); + if(customSignallingUrl && customSignallingUrl !== "") { + return customSignallingUrl; + } - // 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; + // If neither environment used or customSignallingUrl specified, then build the URL using the domain we are on. - return signallingUrl + // Construct the signalling url from the base url, prepend protocol, then append /signalling, then append /rest-of-path?myargs + const urlProtocol: string = window.location.protocol === 'http:' ? 'ws://' : 'wss://'; + const urlBase: string = window.location.host; + const urlPath: string = window.location.pathname; + // Build the signalling URL based on the existing window location, the result should be 'domain.com/signalling/app-name' + const signallingUrl = urlProtocol + urlBase + "/signalling" + urlPath; + return signallingUrl; }); } @@ -89,6 +97,6 @@ export class SPSApplication extends Application { */ sendStatsToSignallingServer(stats: AggregatedStats) { const data = new MessageStats(stats); - this.stream.webSocketController.webSocket.send(data.payload()); + this.stream.signallingProtocol.sendMessage(data); } } diff --git a/library/src/SignallingExtension.ts b/library/src/SignallingExtension.ts index 6071c5b..ed2af37 100644 --- a/library/src/SignallingExtension.ts +++ b/library/src/SignallingExtension.ts @@ -1,14 +1,14 @@ import { Logger, - MessageRecv, - MessageSend, - WebSocketController, -} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4'; + BaseMessage, + SignallingProtocol, +} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; /** * Auth Request Message Wrapper */ -export class MessageAuthRequest extends MessageSend { +export class MessageAuthRequest implements BaseMessage { + type: string; token: string; provider: string; @@ -17,7 +17,6 @@ export class MessageAuthRequest extends MessageSend { * @param provider - Name of the provider that is registered in the auth plugin */ constructor(token: string, provider: string) { - super(); this.type = "authenticationRequest"; this.token = token; this.provider = provider; @@ -37,14 +36,14 @@ export enum InstanceState { /** * Instance State Message wrapper */ -export class MessageInstanceState extends MessageRecv { +export class MessageInstanceState { state: InstanceState; details: string; progress: number; } /** - * Types of Authentication reposes + * Types of Authentication responses */ export enum MessageAuthResponseOutcomeType { REDIRECT = "REDIRECT", @@ -54,9 +53,9 @@ export enum MessageAuthResponseOutcomeType { } /** - * Authentication Response Message wrapper + * Structure for auth responses */ -export class MessageAuthResponse extends MessageRecv { +export class MessageAuthResponse { outcome: MessageAuthResponseOutcomeType; redirect: string; error: string; @@ -65,13 +64,14 @@ export class MessageAuthResponse extends MessageRecv { /** * Instance Request Message Wrapper */ -export class MessageRequestInstance extends MessageSend { +export class MessageRequestInstance implements BaseMessage { + + type: string; // An opaque string representing optional configuration data to pass to the signalling server for instance customisation - data: string + data: string; constructor() { - super(); this.type = "requestInstance"; } } @@ -85,37 +85,34 @@ export class SPSSignalling { onInstanceStateChanged: (stateChangedMsg: string, isError: boolean) => void; onAuthenticationResponse: (authRespMsg: string, isError: boolean) => void; - constructor(websocketController: WebSocketController) { - this.extendSignallingProtocol(websocketController); + constructor(signallingProtocol: SignallingProtocol) { + this.extendSignallingProtocol(signallingProtocol); } /** * Extend the signalling protocol with SPS specific messages. */ - extendSignallingProtocol(webSocketController: WebSocketController) { + extendSignallingProtocol(signallingProtocol: SignallingProtocol) { // authenticationRequired - webSocketController.signallingProtocol.addMessageHandler("authenticationRequired", (authReqPayload: string) => { + signallingProtocol.addListener("authenticationRequired", (authReqPayload: BaseMessage) => { Logger.Log(Logger.GetStackTrace(), "AUTHENTICATION_REQUIRED", 6); const url_string = window.location.href; const url = new URL(url_string); const authRequest = new MessageAuthRequest(url.searchParams.get("code"), url.searchParams.get("provider")); - webSocketController.webSocket.send(authRequest.payload()); + signallingProtocol.sendMessage(authRequest); }); // instanceState - webSocketController.signallingProtocol.addMessageHandler("instanceState", (instanceStatePayload: string) => { + signallingProtocol.addListener("instanceState", (instanceState: MessageInstanceState) => { Logger.Log(Logger.GetStackTrace(), "INSTANCE_STATE", 6); - const instanceState: MessageInstanceState = JSON.parse(instanceStatePayload); this.handleInstanceStateChanged(instanceState); }); // authenticationResponse - webSocketController.signallingProtocol.addMessageHandler("authenticationResponse", (authRespPayload: string) => { + signallingProtocol.addListener("authenticationResponse", (authenticationResponse: MessageAuthResponse) => { Logger.Log(Logger.GetStackTrace(), "AUTHENTICATION_RESPONSE", 6); - const authenticationResponse: MessageAuthResponse = JSON.parse(authRespPayload); - this.handleAuthenticationResponse(authenticationResponse); switch (authenticationResponse.outcome) { @@ -125,8 +122,7 @@ export class SPSSignalling { } case MessageAuthResponseOutcomeType.AUTHENTICATED: { Logger.Log(Logger.GetStackTrace(), "User is authenticated and now requesting an instance", 6); - - webSocketController.webSocket.send(new MessageRequestInstance().payload()); + signallingProtocol.sendMessage(new MessageRequestInstance()); break; } case MessageAuthResponseOutcomeType.INVALID_TOKEN: { @@ -148,7 +144,7 @@ export class SPSSignalling { /** * Set up functionality to happen when an instance state change occurs and updates the info overlay with the response - * @param instanceState - the message instance state + * @param instanceState - the message instance state */ handleInstanceStateChanged(instanceState: MessageInstanceState) { let instanceStateMessage = ""; diff --git a/library/src/index.ts b/library/src/index.ts index 557a0fb..dca0268 100644 --- a/library/src/index.ts +++ b/library/src/index.ts @@ -1,50 +1,48 @@ -// 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"; - -// Epic Games Pixel Streaming Frontend exports -export { WebRtcPlayerController, WebRtcDisconnectedEvent } 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'; - -// 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'; +// Scalable Pixel Streaming Frontend exports +export { SPSApplication } from "./SPSApplication"; +export { LoadingOverlay } from "./LoadingOverlay"; +export { MessageStats } from "./Messages"; +export { MessageAuthRequest, InstanceState, MessageInstanceState, MessageAuthResponseOutcomeType, MessageAuthResponse, MessageRequestInstance, SPSSignalling } from "./SignallingExtension"; + +// Epic Games Pixel Streaming Frontend exports +export { WebRtcPlayerController, WebRtcDisconnectedEvent } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { WebXRController } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { Config, ControlSchemeType, Flags, NumericParameters, TextParameters, OptionParameters, FlagsIds, NumericParametersIds, TextParametersIds, OptionParametersIds, AllSettings } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { SettingBase } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { SettingFlag } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { SettingNumber } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { SettingOption } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { SettingText } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { PixelStreaming } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { AfkLogic } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { LatencyTestResults } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { EncoderSettings, InitialSettings, WebRTCSettings } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { AggregatedStats } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { Logger } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { UnquantizedAndDenormalizeUnsigned } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { BaseMessage, MessageRegistry } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { SignallingProtocol } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { CandidatePairStats } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { CandidateStat } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { DataChannelStats } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { InboundAudioStats, InboundVideoStats } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; +export { OutBoundVideoStats } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.5'; + +// Epic Games Pixel Streaming Frontend UI exports +export { Application, UIOptions } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { PixelStreamingApplicationStyle } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { AFKOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { ActionOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { OverlayBase } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { ConnectOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { DisconnectOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { ErrorOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { InfoOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { PlayOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { TextOverlay } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { ConfigUI } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { SettingUIBase } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { SettingUIFlag } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { SettingUINumber } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { SettingUIOption } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5'; +export { SettingUIText } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.5';