@epicgames-ps/lib-pixelstreamingfrontend-ue5.4
Version:
Frontend library for Unreal Engine 5.4 Pixel Streaming
892 lines (793 loc) • 32.2 kB
text/typescript
// Copyright Epic Games, Inc. All Rights Reserved.
import { Config, OptionParameters } from '../Config/Config';
import { LatencyTestResults } from '../DataChannel/LatencyTestResults';
import { AggregatedStats } from '../PeerConnectionController/AggregatedStats';
import { WebRtcPlayerController } from '../WebRtcPlayer/WebRtcPlayerController';
import { Flags, NumericParameters } from '../Config/Config';
import { Logger } from '../Logger/Logger';
import { InitialSettings } from '../DataChannel/InitialSettings';
import { OnScreenKeyboard } from '../UI/OnScreenKeyboard';
import {
EventEmitter,
InitialSettingsEvent,
LatencyTestResultEvent,
PixelStreamingEvent,
StatsReceivedEvent,
StreamLoadingEvent,
StreamPreConnectEvent,
StreamReconnectEvent,
StreamPreDisconnectEvent,
VideoEncoderAvgQPEvent,
VideoInitializedEvent,
WebRtcAutoConnectEvent,
WebRtcConnectedEvent,
WebRtcConnectingEvent,
WebRtcDisconnectedEvent,
WebRtcFailedEvent,
WebRtcSdpEvent,
DataChannelLatencyTestResponseEvent,
DataChannelLatencyTestResultEvent,
PlayerCountEvent,
WebRtcTCPRelayDetectedEvent
} from '../Util/EventEmitter';
import { MessageOnScreenKeyboard } from '../WebSockets/MessageReceive';
import { WebXRController } from '../WebXR/WebXRController';
import { MessageDirection } from '../UeInstanceMessage/StreamMessageController';
import {
DataChannelLatencyTestConfig,
DataChannelLatencyTestController
} from "../DataChannel/DataChannelLatencyTestController";
import {
DataChannelLatencyTestResponse,
DataChannelLatencyTestResult
} from "../DataChannel/DataChannelLatencyTestResults";
import { RTCUtils } from '../Util/RTCUtils';
export interface PixelStreamingOverrides {
/** The DOM elment where Pixel Streaming video and user input event handlers are attached to.
* You can give an existing DOM element here. If not given, the library will create a new div element
* that is not attached anywhere. In this case you can later get access to this new element and
* attach it to your web page. */
videoElementParent?: HTMLElement;
}
/**
* The key class for the browser side of a Pixel Streaming application, it includes:
* WebRTC handling, XR support, input handling, and emitters for lifetime and state change events.
* Users are encouraged to use this class as is, through composition, or extend it. In any case,
* this will likely be the core of your Pixel Streaming experience in terms of functionality.
*/
export class PixelStreaming {
protected _webRtcController: WebRtcPlayerController;
protected _webXrController: WebXRController;
protected _dataChannelLatencyTestController: DataChannelLatencyTestController;
/**
* Configuration object. You can read or modify config through this object. Whenever
* the configuration is changed, the library will emit a `settingsChanged` event.
*/
public config: Config;
private _videoElementParent: HTMLElement;
private allowConsoleCommands = false;
private onScreenKeyboardHelper: OnScreenKeyboard;
private _videoStartTime: number;
private _inputController: boolean;
private _eventEmitter: EventEmitter;
/**
* @param config - A newly instantiated config object
* @param overrides - Parameters to override default behaviour
* returns the base Pixel streaming object
*/
constructor(config: Config, overrides?: PixelStreamingOverrides) {
this.config = config;
if (overrides?.videoElementParent) {
this._videoElementParent = overrides.videoElementParent;
}
this._eventEmitter = new EventEmitter();
this.configureSettings();
// setup WebRTC
this.setWebRtcPlayerController(
new WebRtcPlayerController(this.config, this)
);
// Onscreen keyboard
this.onScreenKeyboardHelper = new OnScreenKeyboard(
this.videoElementParent
);
this.onScreenKeyboardHelper.unquantizeAndDenormalizeUnsigned = (
x: number,
y: number
) =>
this._webRtcController.requestUnquantizedAndDenormalizeUnsigned(
x,
y
);
this._activateOnScreenKeyboard = (command: MessageOnScreenKeyboard) =>
this.onScreenKeyboardHelper.showOnScreenKeyboard(command);
this._webXrController = new WebXRController(this._webRtcController);
this._setupWebRtcTCPRelayDetection = this._setupWebRtcTCPRelayDetection.bind(this)
// Add event listener for the webRtcConnected event
this._eventEmitter.addEventListener("webRtcConnected", (webRtcConnectedEvent: WebRtcConnectedEvent) => {
// Bind to the stats received event
this._eventEmitter.addEventListener("statsReceived", this._setupWebRtcTCPRelayDetection);
});
}
/**
* Gets the element that contains the video stream element.
*/
public get videoElementParent(): HTMLElement {
if (!this._videoElementParent) {
this._videoElementParent = document.createElement('div');
this._videoElementParent.id = 'videoElementParent';
}
return this._videoElementParent;
}
/**
* Configure the settings with on change listeners and any additional per experience settings.
*/
private configureSettings(): void {
this.config._addOnSettingChangedListener(
Flags.IsQualityController,
(wantsQualityController: boolean) => {
// If the setting has been set to true (either programatically or the user has flicked the toggle)
// and we aren't currently quality controller, send the request
if (
wantsQualityController === true &&
!this._webRtcController.isQualityController
) {
this._webRtcController.sendRequestQualityControlOwnership();
}
}
);
this.config._addOnSettingChangedListener(
Flags.AFKDetection,
(isAFKEnabled: boolean) => {
this._webRtcController.setAfkEnabled(isAFKEnabled);
}
);
this.config._addOnSettingChangedListener(
Flags.MatchViewportResolution,
() => {
this._webRtcController.videoPlayer.updateVideoStreamSize();
}
);
this.config._addOnSettingChangedListener(
Flags.HoveringMouseMode,
(isHoveringMouse: boolean) => {
this.config.setFlagLabel(
Flags.HoveringMouseMode,
`Control Scheme: ${
isHoveringMouse ? 'Hovering' : 'Locked'
} Mouse`
);
this._webRtcController.setMouseInputEnabled(this.config.isFlagEnabled(Flags.MouseInput));
}
);
// user input
this.config._addOnSettingChangedListener(
Flags.KeyboardInput,
(isEnabled: boolean) => {
this._webRtcController.setKeyboardInputEnabled(isEnabled);
}
);
this.config._addOnSettingChangedListener(
Flags.MouseInput,
(isEnabled: boolean) => {
this._webRtcController.setMouseInputEnabled(isEnabled);
}
);
this.config._addOnSettingChangedListener(
Flags.FakeMouseWithTouches,
(_isFakeMouseEnabled: boolean) => {
this._webRtcController.setTouchInputEnabled(this.config.isFlagEnabled(Flags.TouchInput));
}
);
this.config._addOnSettingChangedListener(
Flags.TouchInput,
(isEnabled: boolean) => {
this._webRtcController.setTouchInputEnabled(isEnabled);
}
);
this.config._addOnSettingChangedListener(
Flags.GamepadInput,
(isEnabled: boolean) => {
this._webRtcController.setGamePadInputEnabled(isEnabled);
}
);
// encoder settings
this.config._addOnNumericSettingChangedListener(
NumericParameters.MinQP,
(newValue: number) => {
Logger.Log(
Logger.GetStackTrace(),
'-------- Sending MinQP --------',
7
);
this._webRtcController.sendEncoderMinQP(newValue);
Logger.Log(
Logger.GetStackTrace(),
'-------------------------------------------',
7
);
}
);
this.config._addOnNumericSettingChangedListener(
NumericParameters.MaxQP,
(newValue: number) => {
Logger.Log(
Logger.GetStackTrace(),
'-------- Sending encoder settings --------',
7
);
this._webRtcController.sendEncoderMaxQP(newValue);
Logger.Log(
Logger.GetStackTrace(),
'-------------------------------------------',
7
);
}
);
// WebRTC settings
this.config._addOnNumericSettingChangedListener(
NumericParameters.WebRTCMinBitrate,
(newValue: number) => {
Logger.Log(
Logger.GetStackTrace(),
'-------- Sending web rtc settings --------',
7
);
this._webRtcController.sendWebRTCMinBitrate(newValue * 1000 /* kbps to bps */);
Logger.Log(
Logger.GetStackTrace(),
'-------------------------------------------',
7
);
}
);
this.config._addOnNumericSettingChangedListener(
NumericParameters.WebRTCMaxBitrate,
(newValue: number) => {
Logger.Log(
Logger.GetStackTrace(),
'-------- Sending web rtc settings --------',
7
);
this._webRtcController.sendWebRTCMaxBitrate(newValue * 1000 /* kbps to bps */);
Logger.Log(
Logger.GetStackTrace(),
'-------------------------------------------',
7
);
}
);
this.config._addOnNumericSettingChangedListener(
NumericParameters.WebRTCFPS,
(newValue: number) => {
Logger.Log(
Logger.GetStackTrace(),
'-------- Sending web rtc settings --------',
7
);
this._webRtcController.sendWebRTCFps(newValue);
Logger.Log(
Logger.GetStackTrace(),
'-------------------------------------------',
7
);
}
);
this.config._addOnOptionSettingChangedListener(
OptionParameters.PreferredCodec,
(newValue: string) => {
if (this._webRtcController) {
this._webRtcController.setPreferredCodec(newValue);
}
}
);
this.config._registerOnChangeEvents(this._eventEmitter);
}
/**
* Activate the on screen keyboard when receiving the command from the streamer
* @param command - the keyboard command
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_activateOnScreenKeyboard(command: MessageOnScreenKeyboard): void {
throw new Error('Method not implemented.');
}
/**
* Set the input control ownership
* @param inputControlOwnership - does the user have input control ownership
*/
_onInputControlOwnership(inputControlOwnership: boolean): void {
this._inputController = inputControlOwnership;
}
/**
* Instantiate the WebRTCPlayerController interface to provide WebRTCPlayerController functionality within this class and set up anything that requires it
* @param webRtcPlayerController - a WebRtcPlayerController controller instance
*/
private setWebRtcPlayerController(
webRtcPlayerController: WebRtcPlayerController
) {
this._webRtcController = webRtcPlayerController;
this._webRtcController.setPreferredCodec(
this.config.getSettingOption(OptionParameters.PreferredCodec)
.selected
);
this._webRtcController.resizePlayerStyle();
// connect if auto connect flag is enabled
this.checkForAutoConnect();
}
/**
* Connect to signaling server.
*/
public connect() {
this._eventEmitter.dispatchEvent(new StreamPreConnectEvent());
this._webRtcController.connectToSignallingServer();
}
/**
* Reconnects to the signaling server. If connection is up, disconnects first
* before establishing a new connection
*/
public reconnect() {
this._eventEmitter.dispatchEvent(new StreamReconnectEvent());
this._webRtcController.tryReconnect("Reconnecting...");
}
/**
* Disconnect from the signaling server and close open peer connections.
*/
public disconnect() {
this._eventEmitter.dispatchEvent(new StreamPreDisconnectEvent());
this._webRtcController.close();
}
/**
* Play the stream. Can be called only after a peer connection has been established.
*/
public play() {
this._onStreamLoading();
this._webRtcController.playStream();
}
/**
* Auto connect if AutoConnect flag is enabled
*/
private checkForAutoConnect() {
// set up if the auto play will be used or regular click to start
if (this.config.isFlagEnabled(Flags.AutoConnect)) {
// if autoplaying show an info overlay while while waiting for the connection to begin
this._onWebRtcAutoConnect();
this._webRtcController.connectToSignallingServer();
}
}
/**
* Will unmute the microphone track which is sent to Unreal Engine.
* By default, will only unmute an existing mic track.
*
* @param forceEnable Can be used for cases when this object wasn't initialized with a mic track.
* If this parameter is true, the connection will be restarted with a microphone.
* Warning: this takes some time, as a full renegotiation and reconnection will happen.
*/
public unmuteMicrophone(forceEnable = false) : void {
// If there's an existing mic track, we just set muted state
if (this.config.isFlagEnabled('UseMic')) {
this.setMicrophoneMuted(false);
return;
}
// If there's no pre-existing mic track, and caller is ok with full reset, we enable and reset
if (forceEnable) {
this.config.setFlagEnabled("UseMic", true);
this.reconnect();
return;
}
// If we prefer not to force a reconnection, just warn the user that this operation didn't happen
Logger.Warning(
Logger.GetStackTrace(),
'Trying to unmute mic, but PixelStreaming was initialized with no microphone track. Call with forceEnable == true to re-connect with a mic track.'
);
}
public muteMicrophone() : void {
if (this.config.isFlagEnabled('UseMic')) {
this.setMicrophoneMuted(true);
return;
}
// If there wasn't a mic track, just let user know there's nothing to mute
Logger.Info(
Logger.GetStackTrace(),
'Trying to mute mic, but PixelStreaming has no microphone track, so sending sound is already disabled.'
);
}
private setMicrophoneMuted(mute: boolean) : void
{
for (const transceiver of this._webRtcController?.peerConnectionController?.peerConnection?.getTransceivers() ?? []) {
if (RTCUtils.canTransceiverSendAudio(transceiver)) {
transceiver.sender.track.enabled = !mute;
}
}
}
/**
* Emit an event on auto connecting
*/
_onWebRtcAutoConnect() {
this._eventEmitter.dispatchEvent(new WebRtcAutoConnectEvent());
}
/**
* Set up functionality to happen when receiving a webRTC answer
*/
_onWebRtcSdp() {
this._eventEmitter.dispatchEvent(new WebRtcSdpEvent());
}
/**
* Emits a StreamLoading event
*/
_onStreamLoading() {
this._eventEmitter.dispatchEvent(new StreamLoadingEvent());
}
/**
* Event fired when the video is disconnected - emits given eventString or an override
* message from webRtcController if one has been set
* @param eventString - a string describing why the connection closed
* @param allowClickToReconnect - true if we want to allow the user to retry the connection with a click
*/
_onDisconnect(eventString: string, allowClickToReconnect: boolean) {
this._eventEmitter.dispatchEvent(
new WebRtcDisconnectedEvent({
eventString: eventString,
allowClickToReconnect: allowClickToReconnect
})
);
}
/**
* Handles when Web Rtc is connecting
*/
_onWebRtcConnecting() {
this._eventEmitter.dispatchEvent(new WebRtcConnectingEvent());
}
/**
* Handles when Web Rtc has connected
*/
_onWebRtcConnected() {
this._eventEmitter.dispatchEvent(new WebRtcConnectedEvent());
}
/**
* Handles when Web Rtc fails to connect
*/
_onWebRtcFailed() {
this._eventEmitter.dispatchEvent(new WebRtcFailedEvent());
}
/**
* Handle when the Video has been Initialized
*/
_onVideoInitialized() {
this._eventEmitter.dispatchEvent(new VideoInitializedEvent());
this._videoStartTime = Date.now();
}
/**
* Set up functionality to happen when receiving latency test results
* @param latency - latency test results object
*/
_onLatencyTestResult(latencyTimings: LatencyTestResults) {
this._eventEmitter.dispatchEvent(
new LatencyTestResultEvent({ latencyTimings })
);
}
_onDataChannelLatencyTestResponse(response: DataChannelLatencyTestResponse) {
this._eventEmitter.dispatchEvent(
new DataChannelLatencyTestResponseEvent({ response })
);
}
/**
* Set up functionality to happen when receiving video statistics
* @param videoStats - video statistics as a aggregate stats object
*/
_onVideoStats(videoStats: AggregatedStats) {
// Duration
if (!this._videoStartTime || this._videoStartTime === undefined) {
this._videoStartTime = Date.now();
}
videoStats.handleSessionStatistics(
this._videoStartTime,
this._inputController,
this._webRtcController.videoAvgQp
);
this._eventEmitter.dispatchEvent(
new StatsReceivedEvent({ aggregatedStats: videoStats })
);
}
/**
* Set up functionality to happen when calculating the average video encoder qp
* @param QP - the quality number of the stream
*/
_onVideoEncoderAvgQP(QP: number) {
this._eventEmitter.dispatchEvent(
new VideoEncoderAvgQPEvent({ avgQP: QP })
);
}
/**
* Set up functionality to happen when receiving and handling initial settings for the UE app
* @param settings - initial UE app settings
*/
_onInitialSettings(settings: InitialSettings) {
this._eventEmitter.dispatchEvent(
new InitialSettingsEvent({ settings })
);
if (settings.PixelStreamingSettings) {
this.allowConsoleCommands =
settings.PixelStreamingSettings.AllowPixelStreamingCommands ?? false;
if (this.allowConsoleCommands === false) {
Logger.Info(
Logger.GetStackTrace(),
'-AllowPixelStreamingCommands=false, sending arbitrary console commands from browser to UE is disabled.'
);
}
}
const useUrlParams = this.config.useUrlParams;
const urlParams = new URLSearchParams(window.location.search);
Logger.Info(
Logger.GetStackTrace(),
`using URL parameters ${useUrlParams}`
);
if (settings.EncoderSettings) {
this.config.setNumericSetting(
NumericParameters.MinQP,
// If a setting is set in the URL, make sure we respect that value as opposed to what the application sends us
(useUrlParams && urlParams.has(NumericParameters.MinQP))
? Number.parseFloat(urlParams.get(NumericParameters.MinQP))
: settings.EncoderSettings.MinQP
);
this.config.setNumericSetting(
NumericParameters.MaxQP,
(useUrlParams && urlParams.has(NumericParameters.MaxQP))
? Number.parseFloat(urlParams.get(NumericParameters.MaxQP))
: settings.EncoderSettings.MaxQP
);
}
if (settings.WebRTCSettings) {
this.config.setNumericSetting(
NumericParameters.WebRTCMinBitrate,
(useUrlParams && urlParams.has(NumericParameters.WebRTCMinBitrate))
? Number.parseFloat(urlParams.get(NumericParameters.WebRTCMinBitrate))
: (settings.WebRTCSettings.MinBitrate / 1000) /* bps to kbps */
);
this.config.setNumericSetting(
NumericParameters.WebRTCMaxBitrate,
(useUrlParams && urlParams.has(NumericParameters.WebRTCMaxBitrate))
? Number.parseFloat(urlParams.get(NumericParameters.WebRTCMaxBitrate))
: (settings.WebRTCSettings.MaxBitrate / 1000) /* bps to kbps */
);
this.config.setNumericSetting(
NumericParameters.WebRTCFPS,
(useUrlParams && urlParams.has(NumericParameters.WebRTCFPS))
? Number.parseFloat(urlParams.get(NumericParameters.WebRTCFPS))
: settings.WebRTCSettings.FPS
);
}
}
/**
* Set up functionality to happen when setting quality control ownership of a stream
* @param hasQualityOwnership - does this user have quality ownership of the stream true / false
*/
_onQualityControlOwnership(hasQualityOwnership: boolean) {
this.config.setFlagEnabled(
Flags.IsQualityController,
hasQualityOwnership
);
}
_onPlayerCount(playerCount: number) {
this._eventEmitter.dispatchEvent(
new PlayerCountEvent({ count: playerCount })
);
}
// Sets up to emit the webrtc tcp relay detect event
_setupWebRtcTCPRelayDetection(statsReceivedEvent: StatsReceivedEvent) {
// Get the active candidate pair
let activeCandidatePair = statsReceivedEvent.data.aggregatedStats.getActiveCandidatePair();
// Check if the active candidate pair is not null
if (activeCandidatePair != null) {
// Get the local candidate assigned to the active candidate pair
let localCandidate = statsReceivedEvent.data.aggregatedStats.localCandidates.find((candidate) => candidate.id == activeCandidatePair.localCandidateId, null)
// Check if the local candidate is not null, candidate type is relay and the relay protocol is tcp
if (localCandidate != null && localCandidate.candidateType == 'relay' && localCandidate.relayProtocol == 'tcp') {
// Send the web rtc tcp relay detected event
this._eventEmitter.dispatchEvent(new WebRtcTCPRelayDetectedEvent());
}
// The check is completed and the stats listen event can be removed
this._eventEmitter.removeEventListener("statsReceived", this._setupWebRtcTCPRelayDetection);
}
}
/**
* Request a connection latency test.
* NOTE: There are plans to refactor all request* functions. Expect changes if you use this!
* @returns
*/
public requestLatencyTest() {
if (!this._webRtcController.videoPlayer.isVideoReady()) {
return false;
}
this._webRtcController.sendLatencyTest();
return true;
}
/**
* Request a data channel latency test.
* NOTE: There are plans to refactor all request* functions. Expect changes if you use this!
*/
public requestDataChannelLatencyTest(config: DataChannelLatencyTestConfig) {
if (!this._webRtcController.videoPlayer.isVideoReady()) {
return false;
}
if (!this._dataChannelLatencyTestController) {
this._dataChannelLatencyTestController = new DataChannelLatencyTestController(
this._webRtcController.sendDataChannelLatencyTest.bind(this._webRtcController),
(result: DataChannelLatencyTestResult) => {
this._eventEmitter.dispatchEvent(new DataChannelLatencyTestResultEvent( { result }))
});
this.addEventListener(
"dataChannelLatencyTestResponse",
({data: {response} }) => {
this._dataChannelLatencyTestController.receive(response);
}
)
}
return this._dataChannelLatencyTestController.start(config);
}
/**
* Request for the UE application to show FPS counter.
* NOTE: There are plans to refactor all request* functions. Expect changes if you use this!
* @returns
*/
public requestShowFps() {
if (!this._webRtcController.videoPlayer.isVideoReady()) {
return false;
}
this._webRtcController.sendShowFps();
return true;
}
/**
* Request for a new IFrame from the UE application.
* NOTE: There are plans to refactor all request* functions. Expect changes if you use this!
* @returns
*/
public requestIframe() {
if (!this._webRtcController.videoPlayer.isVideoReady()) {
return false;
}
this._webRtcController.sendIframeRequest();
return true;
}
/**
* Send data to UE application. The data will be run through JSON.stringify() so e.g. strings
* and any serializable plain JSON objects with no recurrence can be sent.
* @returns true if succeeded, false if rejected
*/
public emitUIInteraction(descriptor: object | string) {
if (!this._webRtcController.videoPlayer.isVideoReady()) {
return false;
}
this._webRtcController.emitUIInteraction(descriptor);
return true;
}
/**
* Send a command to UE application. Blocks ConsoleCommand descriptors unless UE
* has signaled that it allows console commands.
* @returns true if succeeded, false if rejected
*/
public emitCommand(descriptor: object) {
if (!this._webRtcController.videoPlayer.isVideoReady()) {
return false;
}
if (!this.allowConsoleCommands && 'ConsoleCommand' in descriptor) {
return false;
}
this._webRtcController.emitCommand(descriptor);
return true;
}
/**
* Send a console command to UE application. Only allowed if UE has signaled that it allows
* console commands.
* @returns true if succeeded, false if rejected
*/
public emitConsoleCommand(command: string) {
if (!this.allowConsoleCommands || !this._webRtcController.videoPlayer.isVideoReady()) {
return false;
}
this._webRtcController.emitConsoleCommand(command);
return true;
}
/**
* Add a UE -> browser response event listener
* @param name - The name of the response handler
* @param listener - The method to be activated when a message is received
*/
public addResponseEventListener(
name: string,
listener: (response: string) => void
) {
this._webRtcController.responseController.addResponseEventListener(name, listener);
}
/**
* Remove a UE -> browser response event listener
* @param name - The name of the response handler
*/
public removeResponseEventListener(name: string) {
this._webRtcController.responseController.removeResponseEventListener(name);
}
/**
* Dispatch a new event.
* @param e event
* @returns
*/
public dispatchEvent(e: PixelStreamingEvent): boolean {
return this._eventEmitter.dispatchEvent(e);
}
/**
* Register an event handler.
* @param type event name
* @param listener event handler function
*/
public addEventListener<
T extends PixelStreamingEvent['type'],
E extends PixelStreamingEvent & { type: T }
>(type: T, listener: (e: Event & E) => void) {
this._eventEmitter.addEventListener(type, listener);
}
/**
* Remove an event handler.
* @param type event name
* @param listener event handler function
*/
public removeEventListener<
T extends PixelStreamingEvent['type'],
E extends PixelStreamingEvent & { type: T }
>(type: T, listener: (e: Event & E) => void) {
this._eventEmitter.removeEventListener(type, listener);
}
/**
* Enable/disable XR mode.
*/
public toggleXR() {
this.webXrController.xrClicked();
}
/**
* Pass in a function to generate a signalling server URL.
* This function is useful if you need to programmatically construct your signalling server URL.
* @param signallingUrlBuilderFunc A function that generates a signalling server url.
*/
public setSignallingUrlBuilder(signallingUrlBuilderFunc: ()=>string) {
this._webRtcController.signallingUrlBuilder = signallingUrlBuilderFunc;
}
/**
* Public getter for the websocket controller. Access to this property allows you to send
* custom websocket messages.
*/
public get webSocketController() {
return this._webRtcController.webSocketController;
}
/**
* Public getter for the webXrController controller. Used for all XR features.
*/
public get webXrController() {
return this._webXrController;
}
public registerMessageHandler(name: string, direction: MessageDirection, handler?: (data: ArrayBuffer | Array<number | string>) => void) {
if(direction === MessageDirection.FromStreamer && typeof handler === 'undefined') {
Logger.Warning(Logger.GetStackTrace(), `Unable to register an undefined handler for ${name}`)
return;
}
if(direction === MessageDirection.ToStreamer && typeof handler === 'undefined') {
this._webRtcController.streamMessageController.registerMessageHandler(
direction,
name,
(data: Array<number | string>) =>
this._webRtcController.sendMessageController.sendMessageToStreamer(
name,
data
)
);
} else {
this._webRtcController.streamMessageController.registerMessageHandler(
direction,
name,
(data: ArrayBuffer) => handler(data)
);
}
}
public get toStreamerHandlers() {
return this._webRtcController.streamMessageController.toStreamerHandlers;
}
public isReconnecting() {
return this._webRtcController.isReconnecting;
}
}