@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.
Files changed (34) hide show
  1. package/.cspell.json +35 -0
  2. package/dist/lib-pixelstreamingfrontend.esm.js +1 -1
  3. package/dist/lib-pixelstreamingfrontend.js +1 -1
  4. package/package.json +1 -1
  5. package/readme.md +1 -1
  6. package/src/Inputs/FakeTouchController.ts +1 -1
  7. package/src/Inputs/GamepadController.ts +2 -2
  8. package/src/Inputs/IMouseEvents.ts +1 -1
  9. package/src/Inputs/ITouchController.ts +1 -1
  10. package/src/Inputs/KeyboardController.ts +2 -2
  11. package/src/Inputs/LockedMouseEvents.ts +2 -2
  12. package/src/Inputs/MouseController.ts +1 -1
  13. package/src/Inputs/TouchController.ts +1 -1
  14. package/src/Inputs/XRGamepadController.ts +44 -26
  15. package/src/PeerConnectionController/PeerConnectionController.ts +2 -2
  16. package/src/PixelStreaming/PixelStreaming.test.ts +4 -4
  17. package/src/PixelStreaming/PixelStreaming.ts +2 -2
  18. package/src/Util/CoordinateConverter.ts +6 -5
  19. package/src/Util/RTCUtils.ts +2 -2
  20. package/src/WebRtcPlayer/WebRtcPlayerController.ts +18 -0
  21. package/src/WebXR/WebXRController.ts +368 -179
  22. package/types/Inputs/GamepadController.d.ts +1 -1
  23. package/types/Inputs/IMouseEvents.d.ts +1 -1
  24. package/types/Inputs/ITouchController.d.ts +1 -1
  25. package/types/Inputs/KeyboardController.d.ts +1 -1
  26. package/types/Inputs/LockedMouseEvents.d.ts +1 -1
  27. package/types/Inputs/XRGamepadController.d.ts +8 -1
  28. package/types/PixelStreaming/PixelStreaming.d.ts +1 -1
  29. package/types/Util/RTCUtils.d.ts +2 -2
  30. package/types/WebXR/WebXRController.d.ts +19 -3
  31. package/src/Util/WebGLUtils.ts +0 -49
  32. package/src/Util/WebXRUtils.ts +0 -25
  33. package/types/Util/WebGLUtils.d.ts +0 -4
  34. 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.12",
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 datachannel connection sending and receiving custom data (in addition to input).
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 unregistering them
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 unregistering them
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
- * Unregisters all event handlers
72
+ * Unregister all event handlers.
73
73
  */
74
74
  unregisterGamePadEvents() {
75
75
  this.gamePadEventListenerTracker.unregisterAll();
@@ -58,7 +58,7 @@ export interface IMouseEvents {
58
58
  handleContextMenu?(mouseEvent: MouseEvent): void;
59
59
 
60
60
  /**
61
- * Unregisters any registered mouse event handlers
61
+ * Unregister any registered mouse event handlers
62
62
  */
63
63
  unregisterMouseEvents(): void;
64
64
  }
@@ -23,7 +23,7 @@ export interface ITouchController {
23
23
  onTouchMove(touchEvent: TouchEvent): void;
24
24
 
25
25
  /**
26
- * Unregisters all touch event handlers
26
+ * Unregister all touch event handlers.
27
27
  */
28
28
  unregisterTouchEvents(): void;
29
29
  }
@@ -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 unregistering them
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
- * Unregisters document keyboard events
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 unregistering them
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
- * Unregisters all event handlers
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 unregistering them
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 unregistering them
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 xrgamepads and controllers
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
- this.toStreamerMessagesProvider.toStreamerHandlers.get(
96
- 'XRButtonPressed'
97
- )([handedness, i, prevButton.pressed ? 1 : 0]);
98
- } else if (!currButton.pressed && prevButton.pressed) {
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 && !currButton.pressed) {
105
- // press
106
- this.toStreamerMessagesProvider.toStreamerHandlers.get(
107
- 'XRButtonPressed'
108
- )([handedness, 3, prevButton.touched ? 1 : 0]);
109
- } else if (!currButton.touched && prevButton.touched) {
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
- this.toStreamerMessagesProvider.toStreamerHandlers.get(
119
- 'XRAnalog'
120
- )([handedness, i, currState.axes[i]]);
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 preferrec codec on Chrome
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
- // Ammend the rest of the browsers supported codecs
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 autoconnect to signalling server if autoconnect setting is enabled', () => {
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 preiously subscribed to, so it'll request the list again
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 autoselect a streamer if receiving only one streamer in streamerList message', () => {
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 autoselect a streamer if receiving multiple streamers in streamerList message', () => {
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 elment where Pixel Streaming video and user input event handlers are attached to.
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 programatically or the user has flicked the toggle)
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 playerAspectRatio =
96
- this.videoElementParent.clientHeight /
97
- this.videoElementParent.clientWidth;
98
- const videoAspectRatio =
99
- this.videoElement.videoHeight / this.videoElement.videoWidth;
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(),
@@ -1,5 +1,5 @@
1
1
  export class RTCUtils {
2
- static isVideoTransciever(transceiver : RTCRtpTransceiver | undefined) : boolean {
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 isAudioTransciever(transceiver : RTCRtpTransceiver | undefined) : boolean {
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',