@epicgames-ps/lib-pixelstreamingfrontend-ue5.5 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cspell.json +48 -0
- package/.eslintignore +8 -0
- package/.eslintrc.js +8 -0
- package/.prettierignore +0 -0
- package/.prettierrc.json +6 -0
- package/dist/lib-pixelstreamingfrontend.esm.js +1 -0
- package/dist/lib-pixelstreamingfrontend.js +1 -0
- package/jest.config.js +18 -0
- package/package.json +48 -0
- package/readme.md +15 -0
- package/src/AFK/AFKController.test.ts +162 -0
- package/src/AFK/AFKController.ts +158 -0
- package/src/Config/Config.test.ts +222 -0
- package/src/Config/Config.ts +970 -0
- package/src/Config/SettingBase.ts +65 -0
- package/src/Config/SettingFlag.ts +99 -0
- package/src/Config/SettingNumber.ts +111 -0
- package/src/Config/SettingOption.ts +124 -0
- package/src/Config/SettingText.ts +82 -0
- package/src/DataChannel/DataChannelController.ts +138 -0
- package/src/DataChannel/DataChannelLatencyTestController.ts +129 -0
- package/src/DataChannel/DataChannelLatencyTestResults.ts +67 -0
- package/src/DataChannel/DataChannelSender.ts +59 -0
- package/src/DataChannel/InitialSettings.ts +61 -0
- package/src/DataChannel/LatencyTestResults.ts +76 -0
- package/src/FreezeFrame/FreezeFrame.ts +114 -0
- package/src/FreezeFrame/FreezeFrameController.ts +114 -0
- package/src/Inputs/FakeTouchController.ts +199 -0
- package/src/Inputs/GamepadController.ts +314 -0
- package/src/Inputs/GamepadTypes.ts +10 -0
- package/src/Inputs/HoveringMouseEvents.ts +192 -0
- package/src/Inputs/IMouseEvents.ts +64 -0
- package/src/Inputs/ITouchController.ts +29 -0
- package/src/Inputs/InputClassesFactory.ts +140 -0
- package/src/Inputs/KeyboardController.ts +354 -0
- package/src/Inputs/LockedMouseEvents.ts +287 -0
- package/src/Inputs/MouseButtons.ts +25 -0
- package/src/Inputs/MouseController.ts +362 -0
- package/src/Inputs/SpecialKeyCodes.ts +16 -0
- package/src/Inputs/TouchController.ts +208 -0
- package/src/Inputs/XRGamepadController.ts +126 -0
- package/src/PeerConnectionController/AggregatedStats.ts +311 -0
- package/src/PeerConnectionController/CandidatePairStats.ts +17 -0
- package/src/PeerConnectionController/CandidateStat.ts +13 -0
- package/src/PeerConnectionController/CodecStats.ts +19 -0
- package/src/PeerConnectionController/DataChannelStats.ts +17 -0
- package/src/PeerConnectionController/InboundRTPStats.ts +154 -0
- package/src/PeerConnectionController/InboundTrackStats.ts +34 -0
- package/src/PeerConnectionController/OutBoundRTPStats.ts +26 -0
- package/src/PeerConnectionController/PeerConnectionController.ts +563 -0
- package/src/PeerConnectionController/SessionStats.ts +10 -0
- package/src/PeerConnectionController/StreamStats.ts +11 -0
- package/src/PixelStreaming/PixelStreaming.test.ts +626 -0
- package/src/PixelStreaming/PixelStreaming.ts +851 -0
- package/src/UI/OnScreenKeyboard.ts +97 -0
- package/src/UeInstanceMessage/ResponseController.ts +47 -0
- package/src/UeInstanceMessage/SendMessageController.ts +154 -0
- package/src/UeInstanceMessage/StreamMessageController.ts +233 -0
- package/src/UeInstanceMessage/ToStreamerMessagesController.ts +62 -0
- package/src/Util/CoordinateConverter.ts +289 -0
- package/src/Util/EventEmitter.ts +611 -0
- package/src/Util/EventListenerTracker.ts +29 -0
- package/src/Util/FileUtil.ts +140 -0
- package/src/Util/RTCUtils.ts +41 -0
- package/src/Util/WebGLUtils.ts +49 -0
- package/src/Util/WebXRUtils.ts +25 -0
- package/src/VideoPlayer/StreamController.ts +89 -0
- package/src/VideoPlayer/VideoPlayer.ts +246 -0
- package/src/WebRtcPlayer/WebRtcPlayerController.ts +2158 -0
- package/src/WebXR/WebXRController.ts +319 -0
- package/src/__test__/mockMediaStream.ts +124 -0
- package/src/__test__/mockRTCPeerConnection.ts +347 -0
- package/src/__test__/mockRTCRtpReceiver.ts +22 -0
- package/src/__test__/mockWebSocket.ts +136 -0
- package/src/pixelstreamingfrontend.ts +46 -0
- package/tsconfig.jest.json +8 -0
- package/tsconfig.json +24 -0
- package/types/AFK/AFKController.d.ts +39 -0
- package/types/Config/Config.d.ts +218 -0
- package/types/Config/SettingBase.d.ts +30 -0
- package/types/Config/SettingFlag.d.ts +33 -0
- package/types/Config/SettingNumber.d.ts +45 -0
- package/types/Config/SettingOption.d.ts +43 -0
- package/types/Config/SettingText.d.ts +29 -0
- package/types/DataChannel/DataChannelController.d.ts +59 -0
- package/types/DataChannel/DataChannelLatencyTestController.d.ts +26 -0
- package/types/DataChannel/DataChannelLatencyTestResults.d.ts +46 -0
- package/types/DataChannel/DataChannelSender.d.ts +21 -0
- package/types/DataChannel/InitialSettings.d.ts +44 -0
- package/types/DataChannel/LatencyTestResults.d.ts +31 -0
- package/types/FreezeFrame/FreezeFrame.d.ts +36 -0
- package/types/FreezeFrame/FreezeFrameController.d.ts +37 -0
- package/types/Inputs/FakeTouchController.d.ts +61 -0
- package/types/Inputs/GamepadController.d.ts +85 -0
- package/types/Inputs/GamepadTypes.d.ts +8 -0
- package/types/Inputs/HoveringMouseEvents.d.ts +56 -0
- package/types/Inputs/IMouseEvents.d.ts +53 -0
- package/types/Inputs/ITouchController.d.ts +24 -0
- package/types/Inputs/InputClassesFactory.d.ts +54 -0
- package/types/Inputs/KeyboardController.d.ts +62 -0
- package/types/Inputs/LockedMouseEvents.d.ts +80 -0
- package/types/Inputs/MouseButtons.d.ts +22 -0
- package/types/Inputs/MouseController.d.ts +75 -0
- package/types/Inputs/SpecialKeyCodes.d.ts +14 -0
- package/types/Inputs/TouchController.d.ts +53 -0
- package/types/Inputs/XRGamepadController.d.ts +15 -0
- package/types/PeerConnectionController/AggregatedStats.d.ts +77 -0
- package/types/PeerConnectionController/CandidatePairStats.d.ts +15 -0
- package/types/PeerConnectionController/CandidateStat.d.ts +11 -0
- package/types/PeerConnectionController/CodecStats.d.ts +14 -0
- package/types/PeerConnectionController/DataChannelStats.d.ts +15 -0
- package/types/PeerConnectionController/InboundRTPStats.d.ts +141 -0
- package/types/PeerConnectionController/InboundTrackStats.d.ts +32 -0
- package/types/PeerConnectionController/OutBoundRTPStats.d.ts +23 -0
- package/types/PeerConnectionController/PeerConnectionController.d.ts +132 -0
- package/types/PeerConnectionController/SessionStats.d.ts +8 -0
- package/types/PeerConnectionController/StreamStats.d.ts +9 -0
- package/types/PixelStreaming/PixelStreaming.d.ts +259 -0
- package/types/UI/OnScreenKeyboard.d.ts +31 -0
- package/types/UeInstanceMessage/ResponseController.d.ts +19 -0
- package/types/UeInstanceMessage/SendMessageController.d.ts +18 -0
- package/types/UeInstanceMessage/StreamMessageController.d.ts +29 -0
- package/types/UeInstanceMessage/ToStreamerMessagesController.d.ts +32 -0
- package/types/Util/CoordinateConverter.d.ts +100 -0
- package/types/Util/EventEmitter.d.ts +422 -0
- package/types/Util/EventListenerTracker.d.ts +14 -0
- package/types/Util/FileUtil.d.ts +32 -0
- package/types/Util/RTCUtils.d.ts +8 -0
- package/types/Util/WebGLUtils.d.ts +4 -0
- package/types/Util/WebXRUtils.d.ts +9 -0
- package/types/VideoPlayer/StreamController.d.ts +24 -0
- package/types/VideoPlayer/VideoPlayer.d.ts +78 -0
- package/types/WebRtcPlayer/WebRtcPlayerController.d.ts +377 -0
- package/types/WebXR/WebXRController.d.ts +26 -0
- package/types/pixelstreamingfrontend.d.ts +22 -0
- package/webpack.common.js +35 -0
- package/webpack.dev.js +35 -0
- package/webpack.prod.js +36 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
import { UnquantizedDenormalizedUnsignedCoord } from '../Util/CoordinateConverter';
|
|
4
|
+
import { MessageReceive } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.5';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Class for handling on screen keyboard usage
|
|
8
|
+
*/
|
|
9
|
+
export class OnScreenKeyboard {
|
|
10
|
+
// If the user focuses on a UE input widget then we show them a button to open
|
|
11
|
+
// the on-screen keyboard. JavaScript security means we can only show the
|
|
12
|
+
// on-screen keyboard in response to a user interaction.
|
|
13
|
+
editTextButton: HTMLButtonElement;
|
|
14
|
+
|
|
15
|
+
// A hidden input text box which is used only for focusing and opening the
|
|
16
|
+
// on-screen keyboard.
|
|
17
|
+
hiddenInput: HTMLInputElement;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
* @param videoElementParent The div element the video player is injected into
|
|
22
|
+
*/
|
|
23
|
+
constructor(videoElementParent: HTMLElement) {
|
|
24
|
+
this.editTextButton = null;
|
|
25
|
+
this.hiddenInput = null;
|
|
26
|
+
|
|
27
|
+
if ('ontouchstart' in document.documentElement) {
|
|
28
|
+
this.createOnScreenKeyboardHelpers(videoElementParent);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* An override for unquantizeAndDenormalizeUnsigned
|
|
34
|
+
* @param x the x axis point
|
|
35
|
+
* @param y the y axis point
|
|
36
|
+
* @returns unquantizeAndDenormalizeUnsigned object
|
|
37
|
+
*/
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
39
|
+
unquantizeAndDenormalizeUnsigned(
|
|
40
|
+
x: number,
|
|
41
|
+
y: number
|
|
42
|
+
): UnquantizedDenormalizedUnsignedCoord {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Creates on screen keyboard helpers
|
|
48
|
+
* @param videoElementParent The div element the video player i injected into
|
|
49
|
+
*/
|
|
50
|
+
createOnScreenKeyboardHelpers(videoElementParent: HTMLElement) {
|
|
51
|
+
if (!this.hiddenInput) {
|
|
52
|
+
this.hiddenInput = document.createElement('input');
|
|
53
|
+
this.hiddenInput.id = 'hiddenInput';
|
|
54
|
+
this.hiddenInput.maxLength = 0;
|
|
55
|
+
videoElementParent.appendChild(this.hiddenInput);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!this.editTextButton) {
|
|
59
|
+
this.editTextButton = document.createElement('button');
|
|
60
|
+
this.editTextButton.id = 'editTextButton';
|
|
61
|
+
this.editTextButton.innerHTML = 'edit text';
|
|
62
|
+
videoElementParent.appendChild(this.editTextButton);
|
|
63
|
+
|
|
64
|
+
// Hide the 'edit text' button.
|
|
65
|
+
this.editTextButton.classList.add('hiddenState');
|
|
66
|
+
|
|
67
|
+
this.editTextButton.addEventListener('touchend', (event: Event) => {
|
|
68
|
+
// Show the on-screen keyboard.
|
|
69
|
+
this.hiddenInput.focus();
|
|
70
|
+
event.preventDefault();
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Shows the on screen keyboard
|
|
77
|
+
* @param command the command received via the data channel containing keyboard positions
|
|
78
|
+
*/
|
|
79
|
+
showOnScreenKeyboard(command: MessageReceive.MessageOnScreenKeyboard) {
|
|
80
|
+
if (command.showOnScreenKeyboard) {
|
|
81
|
+
// Show the 'edit text' button.
|
|
82
|
+
this.editTextButton.classList.remove('hiddenState');
|
|
83
|
+
// Place the 'edit text' button near the UE input widget.
|
|
84
|
+
const pos = this.unquantizeAndDenormalizeUnsigned(
|
|
85
|
+
command.x,
|
|
86
|
+
command.y
|
|
87
|
+
);
|
|
88
|
+
this.editTextButton.style.top = pos.y.toString() + 'px';
|
|
89
|
+
this.editTextButton.style.left = (pos.x - 40).toString() + 'px';
|
|
90
|
+
} else {
|
|
91
|
+
// Hide the 'edit text' button.
|
|
92
|
+
this.editTextButton.classList.add('hiddenState');
|
|
93
|
+
// Hide the on-screen keyboard.
|
|
94
|
+
this.hiddenInput.blur();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
import { Logger } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.5';
|
|
4
|
+
|
|
5
|
+
export class ResponseController {
|
|
6
|
+
responseEventListeners: Map<string, (response: string) => void> = new Map();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Add a response event listener to the response map
|
|
10
|
+
* @param name - The name of the response
|
|
11
|
+
* @param listener - The method to be activated when the response is selected
|
|
12
|
+
*/
|
|
13
|
+
addResponseEventListener(
|
|
14
|
+
name: string,
|
|
15
|
+
listener: (response: string) => void
|
|
16
|
+
) {
|
|
17
|
+
this.responseEventListeners.set(name, listener);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Remove a response event listener to the response map
|
|
22
|
+
* @param name - The name of the response
|
|
23
|
+
*/
|
|
24
|
+
removeResponseEventListener(name: string) {
|
|
25
|
+
this.responseEventListeners.delete(name);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Handle a response when receiving one form the streamer
|
|
30
|
+
* @param message - Data received from the data channel with the command in question
|
|
31
|
+
*/
|
|
32
|
+
onResponse(message: ArrayBuffer) {
|
|
33
|
+
Logger.Log(
|
|
34
|
+
Logger.GetStackTrace(),
|
|
35
|
+
'DataChannelReceiveMessageType.Response',
|
|
36
|
+
6
|
|
37
|
+
);
|
|
38
|
+
const responses = new TextDecoder('utf-16').decode(message.slice(1));
|
|
39
|
+
|
|
40
|
+
Logger.Log(Logger.GetStackTrace(), responses, 6);
|
|
41
|
+
this.responseEventListeners.forEach(
|
|
42
|
+
(listener: (response: string) => void) => {
|
|
43
|
+
listener(responses);
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
import { DataChannelSender } from '../DataChannel/DataChannelSender';
|
|
4
|
+
import { Logger } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.5';
|
|
5
|
+
import { StreamMessageController } from './StreamMessageController';
|
|
6
|
+
|
|
7
|
+
export class SendMessageController {
|
|
8
|
+
toStreamerMessagesMapProvider: StreamMessageController;
|
|
9
|
+
dataChannelSender: DataChannelSender;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param dataChannelSender - Data channel instance
|
|
13
|
+
* @param toStreamerMessagesMapProvider - Stream Messages instance
|
|
14
|
+
*/
|
|
15
|
+
constructor(
|
|
16
|
+
dataChannelSender: DataChannelSender,
|
|
17
|
+
toStreamerMessagesMapProvider: StreamMessageController
|
|
18
|
+
) {
|
|
19
|
+
this.dataChannelSender = dataChannelSender;
|
|
20
|
+
this.toStreamerMessagesMapProvider = toStreamerMessagesMapProvider;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Send a message to the streamer through the data channel
|
|
25
|
+
* @param messageType - the type of message we are sending
|
|
26
|
+
* @param messageData - the message data we are sending over the data channel
|
|
27
|
+
* @returns - nil
|
|
28
|
+
*/
|
|
29
|
+
sendMessageToStreamer(messageType: string, messageData?: Array<number | string>) {
|
|
30
|
+
if (messageData === undefined) {
|
|
31
|
+
messageData = [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const toStreamerMessages =
|
|
35
|
+
this.toStreamerMessagesMapProvider.toStreamerMessages;
|
|
36
|
+
const messageFormat = toStreamerMessages.get(messageType);
|
|
37
|
+
if (messageFormat === undefined) {
|
|
38
|
+
Logger.Error(
|
|
39
|
+
Logger.GetStackTrace(),
|
|
40
|
+
`Attempted to send a message to the streamer with message type: ${messageType}, but the frontend hasn't been configured to send such a message. Check you've added the message type in your cpp`
|
|
41
|
+
);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if(messageFormat.structure && messageData && messageFormat.structure.length !== messageData.length) {
|
|
46
|
+
Logger.Error(
|
|
47
|
+
Logger.GetStackTrace(),
|
|
48
|
+
`Provided message data doesn't match expected layout. Expected [ ${messageFormat.structure.map((element: string) => {
|
|
49
|
+
switch (element) {
|
|
50
|
+
case 'uint8':
|
|
51
|
+
case 'uint16':
|
|
52
|
+
case 'int16':
|
|
53
|
+
case 'float':
|
|
54
|
+
case 'double':
|
|
55
|
+
return 'number';
|
|
56
|
+
case 'string':
|
|
57
|
+
return 'string';
|
|
58
|
+
}
|
|
59
|
+
}).toString() } ] but received [ ${messageData.map((element: number | string) => typeof element).toString()} ]`
|
|
60
|
+
);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let byteLength = 0;
|
|
65
|
+
const textEncoder = new TextEncoder();
|
|
66
|
+
// One loop to calculate the length in bytes of all of the provided data
|
|
67
|
+
messageData.forEach((element: number | string, idx: number) => {
|
|
68
|
+
const type = messageFormat.structure[idx];
|
|
69
|
+
switch (type) {
|
|
70
|
+
case 'uint8':
|
|
71
|
+
byteLength += 1;
|
|
72
|
+
break;
|
|
73
|
+
|
|
74
|
+
case 'uint16':
|
|
75
|
+
byteLength += 2;
|
|
76
|
+
break;
|
|
77
|
+
|
|
78
|
+
case 'int16':
|
|
79
|
+
byteLength += 2;
|
|
80
|
+
break;
|
|
81
|
+
|
|
82
|
+
case 'float':
|
|
83
|
+
byteLength += 4;
|
|
84
|
+
break;
|
|
85
|
+
|
|
86
|
+
case 'double':
|
|
87
|
+
byteLength += 8;
|
|
88
|
+
break;
|
|
89
|
+
|
|
90
|
+
case 'string':
|
|
91
|
+
// 2 bytes for string length
|
|
92
|
+
byteLength += 2;
|
|
93
|
+
// 2 bytes per characters
|
|
94
|
+
byteLength += 2 * textEncoder.encode(element as string).length;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const data = new DataView(new ArrayBuffer(byteLength + 1));
|
|
100
|
+
data.setUint8(0, messageFormat.id);
|
|
101
|
+
let byteOffset = 1;
|
|
102
|
+
|
|
103
|
+
messageData.forEach((element: number | string, idx: number) => {
|
|
104
|
+
const type = messageFormat.structure[idx];
|
|
105
|
+
switch (type) {
|
|
106
|
+
case 'uint8':
|
|
107
|
+
data.setUint8(byteOffset, element as number);
|
|
108
|
+
byteOffset += 1;
|
|
109
|
+
break;
|
|
110
|
+
|
|
111
|
+
case 'uint16':
|
|
112
|
+
data.setUint16(byteOffset, element as number, true);
|
|
113
|
+
byteOffset += 2;
|
|
114
|
+
break;
|
|
115
|
+
|
|
116
|
+
case 'int16':
|
|
117
|
+
data.setInt16(byteOffset, element as number, true);
|
|
118
|
+
byteOffset += 2;
|
|
119
|
+
break;
|
|
120
|
+
|
|
121
|
+
case 'float':
|
|
122
|
+
data.setFloat32(byteOffset, element as number, true);
|
|
123
|
+
byteOffset += 4;
|
|
124
|
+
break;
|
|
125
|
+
|
|
126
|
+
case 'double':
|
|
127
|
+
data.setFloat64(byteOffset, element as number, true);
|
|
128
|
+
byteOffset += 8;
|
|
129
|
+
break;
|
|
130
|
+
|
|
131
|
+
case 'string':
|
|
132
|
+
data.setUint16(byteOffset, (element as string).length, true);
|
|
133
|
+
byteOffset += 2;
|
|
134
|
+
for (let i = 0; i < (element as string).length; i++) {
|
|
135
|
+
data.setUint16(byteOffset, (element as string).charCodeAt(i), true);
|
|
136
|
+
byteOffset += 2;
|
|
137
|
+
}
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
if (!this.dataChannelSender.canSend()) {
|
|
143
|
+
Logger.Info(
|
|
144
|
+
Logger.GetStackTrace(),
|
|
145
|
+
`Data channel cannot send yet, skipping sending message: ${messageType} - ${new Uint8Array(
|
|
146
|
+
data.buffer
|
|
147
|
+
)}`
|
|
148
|
+
);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
this.dataChannelSender.sendData(data.buffer);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
import { Logger } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.5';
|
|
4
|
+
|
|
5
|
+
export class ToStreamerMessage {
|
|
6
|
+
id: number;
|
|
7
|
+
structure?: Array<string>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class StreamMessageController {
|
|
11
|
+
toStreamerHandlers: Map<
|
|
12
|
+
string,
|
|
13
|
+
(messageData?: Array<number | string> | undefined) => void
|
|
14
|
+
>;
|
|
15
|
+
fromStreamerHandlers: Map<
|
|
16
|
+
string,
|
|
17
|
+
(messageType: string, messageData?: ArrayBuffer | undefined) => void
|
|
18
|
+
>;
|
|
19
|
+
// Type Format
|
|
20
|
+
toStreamerMessages: Map<string, ToStreamerMessage>;
|
|
21
|
+
// ID Type
|
|
22
|
+
fromStreamerMessages: Map<number, string>;
|
|
23
|
+
|
|
24
|
+
constructor() {
|
|
25
|
+
this.toStreamerHandlers = new Map();
|
|
26
|
+
this.fromStreamerHandlers = new Map();
|
|
27
|
+
this.toStreamerMessages = new Map();
|
|
28
|
+
this.fromStreamerMessages = new Map();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Populate the Default message protocol
|
|
33
|
+
*/
|
|
34
|
+
populateDefaultProtocol() {
|
|
35
|
+
/*
|
|
36
|
+
* Control Messages. Range = 0..49.
|
|
37
|
+
*/
|
|
38
|
+
this.toStreamerMessages.set('IFrameRequest', {
|
|
39
|
+
id: 0,
|
|
40
|
+
structure: []
|
|
41
|
+
});
|
|
42
|
+
this.toStreamerMessages.set('RequestQualityControl', {
|
|
43
|
+
id: 1,
|
|
44
|
+
structure: []
|
|
45
|
+
});
|
|
46
|
+
this.toStreamerMessages.set('FpsRequest', {
|
|
47
|
+
id: 2,
|
|
48
|
+
structure: []
|
|
49
|
+
});
|
|
50
|
+
this.toStreamerMessages.set('AverageBitrateRequest', {
|
|
51
|
+
id: 3,
|
|
52
|
+
structure: []
|
|
53
|
+
});
|
|
54
|
+
this.toStreamerMessages.set('StartStreaming', {
|
|
55
|
+
id: 4,
|
|
56
|
+
structure: []
|
|
57
|
+
});
|
|
58
|
+
this.toStreamerMessages.set('StopStreaming', {
|
|
59
|
+
id: 5,
|
|
60
|
+
structure: []
|
|
61
|
+
});
|
|
62
|
+
this.toStreamerMessages.set('LatencyTest', {
|
|
63
|
+
id: 6,
|
|
64
|
+
structure: ['string']
|
|
65
|
+
});
|
|
66
|
+
this.toStreamerMessages.set('RequestInitialSettings', {
|
|
67
|
+
id: 7,
|
|
68
|
+
structure: []
|
|
69
|
+
});
|
|
70
|
+
this.toStreamerMessages.set('TestEcho', {
|
|
71
|
+
id: 8,
|
|
72
|
+
structure: []
|
|
73
|
+
});
|
|
74
|
+
this.toStreamerMessages.set('DataChannelLatencyTest', {
|
|
75
|
+
id: 9,
|
|
76
|
+
structure: []
|
|
77
|
+
});
|
|
78
|
+
/*
|
|
79
|
+
* Input Messages. Range = 50..89.
|
|
80
|
+
*/
|
|
81
|
+
// Generic Input Messages. Range = 50..59.
|
|
82
|
+
this.toStreamerMessages.set('UIInteraction', {
|
|
83
|
+
id: 50,
|
|
84
|
+
structure: ['string']
|
|
85
|
+
});
|
|
86
|
+
this.toStreamerMessages.set('Command', {
|
|
87
|
+
id: 51,
|
|
88
|
+
structure: ['string']
|
|
89
|
+
});
|
|
90
|
+
// Keyboard Input Message. Range = 60..69.
|
|
91
|
+
this.toStreamerMessages.set('KeyDown', {
|
|
92
|
+
id: 60,
|
|
93
|
+
// keyCode isRepeat
|
|
94
|
+
structure: ['uint8', 'uint8']
|
|
95
|
+
});
|
|
96
|
+
this.toStreamerMessages.set('KeyUp', {
|
|
97
|
+
id: 61,
|
|
98
|
+
// keyCode
|
|
99
|
+
structure: ['uint8']
|
|
100
|
+
});
|
|
101
|
+
this.toStreamerMessages.set('KeyPress', {
|
|
102
|
+
id: 62,
|
|
103
|
+
// charcode
|
|
104
|
+
structure: ['uint16']
|
|
105
|
+
});
|
|
106
|
+
// Mouse Input Messages. Range = 70..79.
|
|
107
|
+
this.toStreamerMessages.set('MouseEnter', {
|
|
108
|
+
id: 70,
|
|
109
|
+
structure: []
|
|
110
|
+
});
|
|
111
|
+
this.toStreamerMessages.set('MouseLeave', {
|
|
112
|
+
id: 71,
|
|
113
|
+
structure: []
|
|
114
|
+
});
|
|
115
|
+
this.toStreamerMessages.set('MouseDown', {
|
|
116
|
+
id: 72,
|
|
117
|
+
// button x y
|
|
118
|
+
structure: ['uint8', 'uint16', 'uint16']
|
|
119
|
+
});
|
|
120
|
+
this.toStreamerMessages.set('MouseUp', {
|
|
121
|
+
id: 73,
|
|
122
|
+
// button x y
|
|
123
|
+
structure: ['uint8', 'uint16', 'uint16']
|
|
124
|
+
});
|
|
125
|
+
this.toStreamerMessages.set('MouseMove', {
|
|
126
|
+
id: 74,
|
|
127
|
+
// x y deltaX deltaY
|
|
128
|
+
structure: ['uint16', 'uint16', 'int16', 'int16']
|
|
129
|
+
});
|
|
130
|
+
this.toStreamerMessages.set('MouseWheel', {
|
|
131
|
+
id: 75,
|
|
132
|
+
// delta x y
|
|
133
|
+
structure: ['int16', 'uint16', 'uint16']
|
|
134
|
+
});
|
|
135
|
+
this.toStreamerMessages.set('MouseDouble', {
|
|
136
|
+
id: 76,
|
|
137
|
+
// button x y
|
|
138
|
+
structure: ['uint8', 'uint16', 'uint16']
|
|
139
|
+
});
|
|
140
|
+
// Touch Input Messages. Range = 80..89.
|
|
141
|
+
this.toStreamerMessages.set('TouchStart', {
|
|
142
|
+
id: 80,
|
|
143
|
+
// numtouches(1) x y idx force valid
|
|
144
|
+
structure: ['uint8', 'uint16', 'uint16', 'uint8', 'uint8', 'uint8']
|
|
145
|
+
});
|
|
146
|
+
this.toStreamerMessages.set('TouchEnd', {
|
|
147
|
+
id: 81,
|
|
148
|
+
// numtouches(1) x y idx force valid
|
|
149
|
+
structure: ['uint8', 'uint16', 'uint16', 'uint8', 'uint8', 'uint8']
|
|
150
|
+
});
|
|
151
|
+
this.toStreamerMessages.set('TouchMove', {
|
|
152
|
+
id: 82,
|
|
153
|
+
// numtouches(1) x y idx force valid
|
|
154
|
+
structure: ['uint8', 'uint16', 'uint16', 'uint8', 'uint8', 'uint8']
|
|
155
|
+
});
|
|
156
|
+
// Gamepad Input Messages. Range = 90..99
|
|
157
|
+
this.toStreamerMessages.set('GamepadConnected', {
|
|
158
|
+
id: 93,
|
|
159
|
+
structure: []
|
|
160
|
+
});
|
|
161
|
+
this.toStreamerMessages.set('GamepadButtonPressed', {
|
|
162
|
+
id: 90,
|
|
163
|
+
// ctrlerId button isRepeat
|
|
164
|
+
structure: ['uint8', 'uint8', 'uint8']
|
|
165
|
+
});
|
|
166
|
+
this.toStreamerMessages.set('GamepadButtonReleased', {
|
|
167
|
+
id: 91,
|
|
168
|
+
// ctrlerId button isRepeat(0)
|
|
169
|
+
structure: ['uint8', 'uint8', 'uint8']
|
|
170
|
+
});
|
|
171
|
+
this.toStreamerMessages.set('GamepadAnalog', {
|
|
172
|
+
id: 92,
|
|
173
|
+
// ctrlerId button analogValue
|
|
174
|
+
structure: ['uint8', 'uint8', 'double']
|
|
175
|
+
});
|
|
176
|
+
this.toStreamerMessages.set('GamepadDisconnected', {
|
|
177
|
+
id: 94,
|
|
178
|
+
// ctrlerId
|
|
179
|
+
structure: ['uint8']
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
this.fromStreamerMessages.set(0, 'QualityControlOwnership');
|
|
183
|
+
this.fromStreamerMessages.set(1, 'Response');
|
|
184
|
+
this.fromStreamerMessages.set(2, 'Command');
|
|
185
|
+
this.fromStreamerMessages.set(3, 'FreezeFrame');
|
|
186
|
+
this.fromStreamerMessages.set(4, 'UnfreezeFrame');
|
|
187
|
+
this.fromStreamerMessages.set(5, 'VideoEncoderAvgQP');
|
|
188
|
+
this.fromStreamerMessages.set(6, 'LatencyTest');
|
|
189
|
+
this.fromStreamerMessages.set(7, 'InitialSettings');
|
|
190
|
+
this.fromStreamerMessages.set(8, 'FileExtension');
|
|
191
|
+
this.fromStreamerMessages.set(9, 'FileMimeType');
|
|
192
|
+
this.fromStreamerMessages.set(10, 'FileContents');
|
|
193
|
+
this.fromStreamerMessages.set(11, 'TestEcho');
|
|
194
|
+
this.fromStreamerMessages.set(12, 'InputControlOwnership');
|
|
195
|
+
this.fromStreamerMessages.set(13, 'GamepadResponse');
|
|
196
|
+
this.fromStreamerMessages.set(14, 'DataChannelLatencyTest');
|
|
197
|
+
this.fromStreamerMessages.set(255, 'Protocol');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Register a message handler
|
|
202
|
+
* @param messageDirection - the direction of the message; toStreamer or fromStreamer
|
|
203
|
+
* @param messageType - the type of the message
|
|
204
|
+
* @param messageHandler - the function or method to be executed when this handler is called
|
|
205
|
+
*/
|
|
206
|
+
registerMessageHandler(
|
|
207
|
+
messageDirection: MessageDirection,
|
|
208
|
+
messageType: string,
|
|
209
|
+
messageHandler: (messageData?: unknown | undefined) => void
|
|
210
|
+
) {
|
|
211
|
+
switch (messageDirection) {
|
|
212
|
+
case MessageDirection.ToStreamer:
|
|
213
|
+
this.toStreamerHandlers.set(messageType, messageHandler);
|
|
214
|
+
break;
|
|
215
|
+
case MessageDirection.FromStreamer:
|
|
216
|
+
this.fromStreamerHandlers.set(messageType, messageHandler);
|
|
217
|
+
break;
|
|
218
|
+
default:
|
|
219
|
+
Logger.Log(
|
|
220
|
+
Logger.GetStackTrace(),
|
|
221
|
+
`Unknown message direction ${messageDirection}`
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* The enum for message directions
|
|
229
|
+
*/
|
|
230
|
+
export enum MessageDirection {
|
|
231
|
+
ToStreamer = 0,
|
|
232
|
+
FromStreamer = 1
|
|
233
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
import { SendMessageController } from './SendMessageController';
|
|
4
|
+
|
|
5
|
+
export class ToStreamerMessagesController {
|
|
6
|
+
sendMessageController: SendMessageController;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param sendMessageController - Stream message controller instance
|
|
10
|
+
*/
|
|
11
|
+
constructor(sendMessageController: SendMessageController) {
|
|
12
|
+
this.sendMessageController = sendMessageController;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Send Request to Take Quality Control to the UE Instance
|
|
17
|
+
*/
|
|
18
|
+
SendRequestQualityControl() {
|
|
19
|
+
this.sendMessageController.sendMessageToStreamer(
|
|
20
|
+
'RequestQualityControl'
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Send Max FPS Request to the UE Instance
|
|
26
|
+
*/
|
|
27
|
+
SendMaxFpsRequest() {
|
|
28
|
+
this.sendMessageController.sendMessageToStreamer('FpsRequest');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Send Average Bitrate Request to the UE Instance
|
|
33
|
+
*/
|
|
34
|
+
SendAverageBitrateRequest() {
|
|
35
|
+
this.sendMessageController.sendMessageToStreamer(
|
|
36
|
+
'AverageBitrateRequest'
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Send a Start Streaming Message to the UE Instance
|
|
42
|
+
*/
|
|
43
|
+
SendStartStreaming() {
|
|
44
|
+
this.sendMessageController.sendMessageToStreamer('StartStreaming');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Send a Stop Streaming Message to the UE Instance
|
|
49
|
+
*/
|
|
50
|
+
SendStopStreaming() {
|
|
51
|
+
this.sendMessageController.sendMessageToStreamer('StopStreaming');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Send a Request Initial Settings to the UE Instance
|
|
56
|
+
*/
|
|
57
|
+
SendRequestInitialSettings() {
|
|
58
|
+
this.sendMessageController.sendMessageToStreamer(
|
|
59
|
+
'RequestInitialSettings'
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|