@epicgames-ps/lib-pixelstreamingfrontend-ue5.5 0.0.12 → 0.1.0
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 +35 -0
- package/dist/lib-pixelstreamingfrontend.esm.js +1 -1
- package/dist/lib-pixelstreamingfrontend.js +1 -1
- package/package.json +1 -1
- package/readme.md +1 -1
- package/src/Inputs/FakeTouchController.ts +1 -1
- package/src/Inputs/GamepadController.ts +2 -2
- package/src/Inputs/IMouseEvents.ts +1 -1
- package/src/Inputs/ITouchController.ts +1 -1
- package/src/Inputs/KeyboardController.ts +2 -2
- package/src/Inputs/LockedMouseEvents.ts +2 -2
- package/src/Inputs/MouseController.ts +1 -1
- package/src/Inputs/TouchController.ts +1 -1
- package/src/Inputs/XRGamepadController.ts +44 -26
- package/src/PeerConnectionController/PeerConnectionController.ts +2 -2
- package/src/PixelStreaming/PixelStreaming.test.ts +4 -4
- package/src/PixelStreaming/PixelStreaming.ts +2 -2
- package/src/Util/CoordinateConverter.ts +6 -5
- package/src/Util/RTCUtils.ts +2 -2
- package/src/WebRtcPlayer/WebRtcPlayerController.ts +18 -0
- package/src/WebXR/WebXRController.ts +368 -179
- package/types/Inputs/GamepadController.d.ts +1 -1
- package/types/Inputs/IMouseEvents.d.ts +1 -1
- package/types/Inputs/ITouchController.d.ts +1 -1
- package/types/Inputs/KeyboardController.d.ts +1 -1
- package/types/Inputs/LockedMouseEvents.d.ts +1 -1
- package/types/Inputs/XRGamepadController.d.ts +8 -1
- package/types/PixelStreaming/PixelStreaming.d.ts +1 -1
- package/types/Util/RTCUtils.d.ts +2 -2
- package/types/WebXR/WebXRController.d.ts +19 -3
- package/src/Util/WebGLUtils.ts +0 -49
- package/src/Util/WebXRUtils.ts +0 -25
- package/types/Util/WebGLUtils.d.ts +0 -4
- package/types/Util/WebXRUtils.d.ts +0 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epicgames-ps/lib-pixelstreamingfrontend-ue5.5",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Frontend library for Unreal Engine 5.5 Pixel Streaming",
|
|
5
5
|
"main": "dist/lib-pixelstreamingfrontend.js",
|
|
6
6
|
"module": "dist/lib-pixelstreamingfrontend.esm.js",
|
package/readme.md
CHANGED
|
@@ -8,7 +8,7 @@ See [lib-pixelstreamingfrontend-ui](/Frontend/implementations/typescript) for an
|
|
|
8
8
|
- Create a websocket connection to communicate with the signalling server.
|
|
9
9
|
- Create a WebRTC player that displays the Unreal Engine video and audio.
|
|
10
10
|
- Handling of input from the user and transmitting it back to Unreal Engine.
|
|
11
|
-
- Opens a
|
|
11
|
+
- Opens a data channel connection sending and receiving custom data (in addition to input).
|
|
12
12
|
|
|
13
13
|
### Adding it to your project
|
|
14
14
|
`npm i @epicgames-ps/lib-pixelstreamingfrontend-ue5.4`
|
|
@@ -19,7 +19,7 @@ export class FakeTouchController implements ITouchController {
|
|
|
19
19
|
coordinateConverter: CoordinateConverter;
|
|
20
20
|
videoElementParentClientRect: DOMRect;
|
|
21
21
|
|
|
22
|
-
// Utility for keeping track of event handlers and
|
|
22
|
+
// Utility for keeping track of event handlers and to unregister them.
|
|
23
23
|
private touchEventListenerTracker = new EventListenerTracker();
|
|
24
24
|
|
|
25
25
|
/**
|
|
@@ -13,7 +13,7 @@ export class GamePadController {
|
|
|
13
13
|
requestAnimationFrame: (callback: FrameRequestCallback) => number;
|
|
14
14
|
toStreamerMessagesProvider: StreamMessageController;
|
|
15
15
|
|
|
16
|
-
// Utility for keeping track of event handlers and
|
|
16
|
+
// Utility for keeping track of event handlers and to unregister them.
|
|
17
17
|
private gamePadEventListenerTracker = new EventListenerTracker();
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -69,7 +69,7 @@ export class GamePadController {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
|
-
*
|
|
72
|
+
* Unregister all event handlers.
|
|
73
73
|
*/
|
|
74
74
|
unregisterGamePadEvents() {
|
|
75
75
|
this.gamePadEventListenerTracker.unregisterAll();
|
|
@@ -19,7 +19,7 @@ export class KeyboardController {
|
|
|
19
19
|
activeKeysProvider: ActiveKeys;
|
|
20
20
|
config: Config;
|
|
21
21
|
|
|
22
|
-
// Utility for keeping track of event handlers and
|
|
22
|
+
// Utility for keeping track of event handlers and to unregister them.
|
|
23
23
|
private keyboardEventListenerTracker = new EventListenerTracker();
|
|
24
24
|
|
|
25
25
|
/*
|
|
@@ -177,7 +177,7 @@ export class KeyboardController {
|
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
/**
|
|
180
|
-
*
|
|
180
|
+
* Unregister document keyboard events.
|
|
181
181
|
*/
|
|
182
182
|
unregisterKeyBoardEvents() {
|
|
183
183
|
this.keyboardEventListenerTracker.unregisterAll();
|
|
@@ -22,7 +22,7 @@ export class LockedMouseEvents implements IMouseEvents {
|
|
|
22
22
|
this.updateMouseMovePosition(mouseEvent);
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
// Utility for keeping track of event handlers and
|
|
25
|
+
// Utility for keeping track of event handlers and to unregister them.
|
|
26
26
|
private mouseEventListenerTracker = new EventListenerTracker();
|
|
27
27
|
|
|
28
28
|
/**
|
|
@@ -51,7 +51,7 @@ export class LockedMouseEvents implements IMouseEvents {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
|
-
*
|
|
54
|
+
* Unregister all event handlers.
|
|
55
55
|
*/
|
|
56
56
|
unregisterMouseEvents() {
|
|
57
57
|
this.mouseEventListenerTracker.unregisterAll();
|
|
@@ -20,7 +20,7 @@ export class MouseController {
|
|
|
20
20
|
coordinateConverter: CoordinateConverter;
|
|
21
21
|
activeKeysProvider: ActiveKeys;
|
|
22
22
|
|
|
23
|
-
// Utility for keeping track of event handlers and
|
|
23
|
+
// Utility for keeping track of event handlers and to unregister them.
|
|
24
24
|
private mouseEventListenerTracker = new EventListenerTracker();
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -18,7 +18,7 @@ export class TouchController implements ITouchController {
|
|
|
18
18
|
fingerIds = new Map();
|
|
19
19
|
maxByteValue = 255;
|
|
20
20
|
|
|
21
|
-
// Utility for keeping track of event handlers and
|
|
21
|
+
// Utility for keeping track of event handlers and to unregister them.
|
|
22
22
|
private touchEventListenerTracker = new EventListenerTracker();
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import { StreamMessageController } from '../UeInstanceMessage/StreamMessageController';
|
|
4
4
|
import { Controller } from './GamepadTypes';
|
|
5
|
-
import { WebXRUtils } from '../Util/WebXRUtils';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
|
-
* The class that handles the functionality of
|
|
7
|
+
* The class that handles the functionality of XR gamepads and controllers.
|
|
9
8
|
*/
|
|
10
9
|
export class XRGamepadController {
|
|
11
10
|
controllers: Array<Controller>;
|
|
@@ -19,6 +18,29 @@ export class XRGamepadController {
|
|
|
19
18
|
this.controllers = [];
|
|
20
19
|
}
|
|
21
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Deep copies the values from a gamepad by first converting it to a JSON object and then back to a gamepad
|
|
23
|
+
*
|
|
24
|
+
* @param gamepad the original gamepad
|
|
25
|
+
* @returns a new gamepad object, populated with the original gamepads values
|
|
26
|
+
*/
|
|
27
|
+
static deepCopyGamepad(gamepad: Gamepad): Gamepad {
|
|
28
|
+
return JSON.parse(
|
|
29
|
+
JSON.stringify({
|
|
30
|
+
buttons: gamepad.buttons.map((b) =>
|
|
31
|
+
JSON.parse(
|
|
32
|
+
JSON.stringify({
|
|
33
|
+
pressed: b.pressed,
|
|
34
|
+
touched: b.touched,
|
|
35
|
+
value: b.value
|
|
36
|
+
})
|
|
37
|
+
)
|
|
38
|
+
),
|
|
39
|
+
axes: gamepad.axes
|
|
40
|
+
})
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
22
44
|
updateStatus(
|
|
23
45
|
source: XRInputSource,
|
|
24
46
|
frame: XRFrame,
|
|
@@ -75,12 +97,10 @@ export class XRGamepadController {
|
|
|
75
97
|
currentState: undefined,
|
|
76
98
|
id: undefined
|
|
77
99
|
};
|
|
78
|
-
this.controllers[handedness].prevState =
|
|
79
|
-
WebXRUtils.deepCopyGamepad(source.gamepad);
|
|
100
|
+
this.controllers[handedness].prevState = XRGamepadController.deepCopyGamepad(source.gamepad);
|
|
80
101
|
}
|
|
81
102
|
|
|
82
|
-
this.controllers[handedness].currentState =
|
|
83
|
-
WebXRUtils.deepCopyGamepad(source.gamepad);
|
|
103
|
+
this.controllers[handedness].currentState = XRGamepadController.deepCopyGamepad(source.gamepad);
|
|
84
104
|
|
|
85
105
|
const controller = this.controllers[handedness];
|
|
86
106
|
const currState = controller.currentState;
|
|
@@ -92,35 +112,33 @@ export class XRGamepadController {
|
|
|
92
112
|
|
|
93
113
|
if (currButton.pressed) {
|
|
94
114
|
// press
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
this.toStreamerMessagesProvider.toStreamerHandlers.get(
|
|
100
|
-
'XRButtonReleased'
|
|
101
|
-
)([handedness, i, 0]);
|
|
115
|
+
const isRepeat = prevButton.pressed ? 1 : 0;
|
|
116
|
+
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonPressed')([handedness, i, isRepeat, currButton.value]);
|
|
117
|
+
} else if (prevButton.pressed) {
|
|
118
|
+
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonReleased')([handedness, i, 0]);
|
|
102
119
|
}
|
|
103
120
|
|
|
104
|
-
if (currButton.touched
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
this.toStreamerMessagesProvider.toStreamerHandlers.get(
|
|
111
|
-
'XRButtonReleased'
|
|
112
|
-
)([handedness, 3, 0]);
|
|
121
|
+
if (currButton.touched) {
|
|
122
|
+
// touched
|
|
123
|
+
const isRepeat = prevButton.touched ? 1 : 0;
|
|
124
|
+
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonTouched')([handedness, i, isRepeat]);
|
|
125
|
+
}
|
|
126
|
+
else if (prevButton.touched) {
|
|
127
|
+
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonTouchReleased')([handedness, i, 0]);
|
|
113
128
|
}
|
|
114
129
|
}
|
|
115
130
|
|
|
116
131
|
// Iterate over gamepad axes
|
|
117
132
|
for (let i = 0; i < currState.axes.length; i++) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
133
|
+
const curAxisValue = currState.axes[i];
|
|
134
|
+
const prevAxisValue = prevState.axes[i];
|
|
135
|
+
// Only send axis update if there is a change
|
|
136
|
+
if(curAxisValue != prevAxisValue) {
|
|
137
|
+
this.toStreamerMessagesProvider.toStreamerHandlers.get('XRAnalog')([handedness, i, curAxisValue]);
|
|
138
|
+
}
|
|
121
139
|
}
|
|
122
140
|
|
|
123
141
|
this.controllers[handedness].prevState = currState;
|
|
124
142
|
}
|
|
125
143
|
}
|
|
126
|
-
}
|
|
144
|
+
}
|
|
@@ -382,7 +382,7 @@ export class PeerConnectionController {
|
|
|
382
382
|
// Setup a transceiver for getting UE video
|
|
383
383
|
this.peerConnection?.addTransceiver('video', { direction: 'recvonly' });
|
|
384
384
|
|
|
385
|
-
// We can only set
|
|
385
|
+
// We can only set preferred codec on Chrome
|
|
386
386
|
if (RTCRtpReceiver.getCapabilities && this.preferredCodec != '') {
|
|
387
387
|
for (const transceiver of this.peerConnection?.getTransceivers() ?? []) {
|
|
388
388
|
if (
|
|
@@ -412,7 +412,7 @@ export class PeerConnectionController {
|
|
|
412
412
|
return option != this.preferredCodec;
|
|
413
413
|
})
|
|
414
414
|
.forEach((option) => {
|
|
415
|
-
//
|
|
415
|
+
// Amend the rest of the browsers supported codecs
|
|
416
416
|
const altCodec = option.split(' ');
|
|
417
417
|
codecs.push({
|
|
418
418
|
mimeType: 'video/' + altCodec[0] /* Name */,
|
|
@@ -122,7 +122,7 @@ describe('PixelStreaming', () => {
|
|
|
122
122
|
expect(webSocketSpyFunctions.constructorSpy).toHaveBeenCalledWith(mockSignallingUrl);
|
|
123
123
|
});
|
|
124
124
|
|
|
125
|
-
it('should
|
|
125
|
+
it('should auto connect to signalling server if auto connect setting is enabled', () => {
|
|
126
126
|
const config = new Config({ initialSettings: {ss: mockSignallingUrl, AutoConnect: true}});
|
|
127
127
|
|
|
128
128
|
expect(webSocketSpyFunctions.constructorSpy).not.toHaveBeenCalled();
|
|
@@ -212,7 +212,7 @@ describe('PixelStreaming', () => {
|
|
|
212
212
|
// We don't have a signalling server to respond with data so lets just fake a response with no streamers
|
|
213
213
|
triggerStreamerListMessage([]);
|
|
214
214
|
// Wait 2 seconds. This delay waits for the WebRtcPlayerController to realise the previously received list doesn't contain
|
|
215
|
-
// the streamer is was
|
|
215
|
+
// the streamer is was previously subscribed to, so it'll request the list again
|
|
216
216
|
jest.advanceTimersByTime(2000);
|
|
217
217
|
|
|
218
218
|
// Same as above but repeated for the second call
|
|
@@ -244,7 +244,7 @@ describe('PixelStreaming', () => {
|
|
|
244
244
|
);
|
|
245
245
|
});
|
|
246
246
|
|
|
247
|
-
it('should
|
|
247
|
+
it('should auto select a streamer if receiving only one streamer in streamerList message', () => {
|
|
248
248
|
const config = new Config({ initialSettings: {ss: mockSignallingUrl, AutoConnect: true}});
|
|
249
249
|
const streamerListSpy = jest.fn();
|
|
250
250
|
const pixelStreaming = new PixelStreaming(config);
|
|
@@ -267,7 +267,7 @@ describe('PixelStreaming', () => {
|
|
|
267
267
|
);
|
|
268
268
|
});
|
|
269
269
|
|
|
270
|
-
it('should not
|
|
270
|
+
it('should not auto select a streamer if receiving multiple streamers in streamerList message', () => {
|
|
271
271
|
const config = new Config({ initialSettings: {ss: mockSignallingUrl, AutoConnect: true}});
|
|
272
272
|
const streamerId2 = "MOCK_2_PIXEL_STREAMING";
|
|
273
273
|
const extendedStreamerIdList = [streamerId, streamerId2];
|
|
@@ -45,7 +45,7 @@ import { RTCUtils } from '../Util/RTCUtils';
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
export interface PixelStreamingOverrides {
|
|
48
|
-
/** The DOM
|
|
48
|
+
/** The DOM element where Pixel Streaming video and user input event handlers are attached to.
|
|
49
49
|
* You can give an existing DOM element here. If not given, the library will create a new div element
|
|
50
50
|
* that is not attached anywhere. In this case you can later get access to this new element and
|
|
51
51
|
* attach it to your web page. */
|
|
@@ -146,7 +146,7 @@ export class PixelStreaming {
|
|
|
146
146
|
this.config._addOnSettingChangedListener(
|
|
147
147
|
Flags.IsQualityController,
|
|
148
148
|
(wantsQualityController: boolean) => {
|
|
149
|
-
// If the setting has been set to true (either
|
|
149
|
+
// If the setting has been set to true (either programmatically or the user has flicked the toggle)
|
|
150
150
|
// and we aren't currently quality controller, send the request
|
|
151
151
|
if (
|
|
152
152
|
wantsQualityController === true &&
|
|
@@ -92,11 +92,12 @@ export class CoordinateConverter {
|
|
|
92
92
|
this.videoElement = this.videoElementProvider.getVideoElement();
|
|
93
93
|
|
|
94
94
|
if (this.videoElementParent && this.videoElement) {
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
95
|
+
const playerWidth = this.videoElementParent.clientWidth || 1;
|
|
96
|
+
const playerHeight = this.videoElementParent.clientHeight || 1;
|
|
97
|
+
const videoWidth = this.videoElement.videoWidth || 1;
|
|
98
|
+
const videoHeight = this.videoElement.videoHeight || 1;
|
|
99
|
+
const playerAspectRatio = playerHeight / playerWidth;
|
|
100
|
+
const videoAspectRatio = videoHeight / videoWidth;
|
|
100
101
|
if (playerAspectRatio > videoAspectRatio) {
|
|
101
102
|
Logger.Log(
|
|
102
103
|
Logger.GetStackTrace(),
|
package/src/Util/RTCUtils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export class RTCUtils {
|
|
2
|
-
static
|
|
2
|
+
static isVideoTransceiver(transceiver : RTCRtpTransceiver | undefined) : boolean {
|
|
3
3
|
return this.canTransceiverReceiveVideo(transceiver) || this.canTransceiverSendVideo(transceiver);
|
|
4
4
|
}
|
|
5
5
|
|
|
@@ -19,7 +19,7 @@ export class RTCUtils {
|
|
|
19
19
|
transceiver.sender.track.kind === 'video';
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
static
|
|
22
|
+
static isAudioTransceiver(transceiver : RTCRtpTransceiver | undefined) : boolean {
|
|
23
23
|
return this.canTransceiverReceiveAudio(transceiver) || this.canTransceiverSendAudio(transceiver);
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -707,6 +707,15 @@ export class WebRtcPlayerController {
|
|
|
707
707
|
data
|
|
708
708
|
)
|
|
709
709
|
);
|
|
710
|
+
this.streamMessageController.registerMessageHandler(
|
|
711
|
+
MessageDirection.ToStreamer,
|
|
712
|
+
'XREyeViews',
|
|
713
|
+
(data: Array<number | string>) =>
|
|
714
|
+
this.sendMessageController.sendMessageToStreamer(
|
|
715
|
+
'XREyeViews',
|
|
716
|
+
data
|
|
717
|
+
)
|
|
718
|
+
);
|
|
710
719
|
this.streamMessageController.registerMessageHandler(
|
|
711
720
|
MessageDirection.ToStreamer,
|
|
712
721
|
'XRHMDTransform',
|
|
@@ -743,6 +752,15 @@ export class WebRtcPlayerController {
|
|
|
743
752
|
data
|
|
744
753
|
)
|
|
745
754
|
);
|
|
755
|
+
this.streamMessageController.registerMessageHandler(
|
|
756
|
+
MessageDirection.ToStreamer,
|
|
757
|
+
'XRButtonTouchReleased',
|
|
758
|
+
(data: Array<number | string>) =>
|
|
759
|
+
this.sendMessageController.sendMessageToStreamer(
|
|
760
|
+
'XRButtonTouchReleased',
|
|
761
|
+
data
|
|
762
|
+
)
|
|
763
|
+
);
|
|
746
764
|
this.streamMessageController.registerMessageHandler(
|
|
747
765
|
MessageDirection.ToStreamer,
|
|
748
766
|
'XRButtonPressed',
|