@epicgames-ps/lib-pixelstreamingfrontend-ue5.5 1.0.3 → 1.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 (92) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/Config/Config.js +8 -22
  3. package/dist/cjs/Config/Config.js.map +1 -1
  4. package/dist/cjs/Inputs/GamepadController.js.map +1 -1
  5. package/dist/cjs/Inputs/KeyboardController.js +0 -23
  6. package/dist/cjs/Inputs/KeyboardController.js.map +1 -1
  7. package/dist/cjs/Inputs/MouseController.js +9 -6
  8. package/dist/cjs/Inputs/MouseController.js.map +1 -1
  9. package/dist/cjs/Inputs/MouseControllerHovering.js.map +1 -1
  10. package/dist/cjs/Inputs/MouseControllerLocked.js +1 -0
  11. package/dist/cjs/Inputs/MouseControllerLocked.js.map +1 -1
  12. package/dist/cjs/PixelStreaming/PixelStreaming.js +12 -13
  13. package/dist/cjs/PixelStreaming/PixelStreaming.js.map +1 -1
  14. package/dist/cjs/UeInstanceMessage/StreamMessageController.js +4 -0
  15. package/dist/cjs/UeInstanceMessage/StreamMessageController.js.map +1 -1
  16. package/dist/cjs/Util/BrowserUtils.js +32 -0
  17. package/dist/cjs/Util/BrowserUtils.js.map +1 -0
  18. package/dist/cjs/Util/EventEmitter.js +11 -1
  19. package/dist/cjs/Util/EventEmitter.js.map +1 -1
  20. package/dist/cjs/Util/IURLSearchParams.js +1 -0
  21. package/dist/cjs/Util/IURLSearchParams.js.map +1 -1
  22. package/dist/cjs/Util/RTCUtils.js +1 -0
  23. package/dist/cjs/Util/RTCUtils.js.map +1 -1
  24. package/dist/cjs/VideoPlayer/VideoPlayer.js +12 -1
  25. package/dist/cjs/VideoPlayer/VideoPlayer.js.map +1 -1
  26. package/dist/cjs/WebRtcPlayer/WebRtcPlayerController.js +30 -6
  27. package/dist/cjs/WebRtcPlayer/WebRtcPlayerController.js.map +1 -1
  28. package/dist/esm/Config/Config.js +8 -22
  29. package/dist/esm/Config/Config.js.map +1 -1
  30. package/dist/esm/Inputs/GamepadController.js.map +1 -1
  31. package/dist/esm/Inputs/KeyboardController.js +0 -23
  32. package/dist/esm/Inputs/KeyboardController.js.map +1 -1
  33. package/dist/esm/Inputs/MouseController.js +9 -6
  34. package/dist/esm/Inputs/MouseController.js.map +1 -1
  35. package/dist/esm/Inputs/MouseControllerHovering.js.map +1 -1
  36. package/dist/esm/Inputs/MouseControllerLocked.js +1 -0
  37. package/dist/esm/Inputs/MouseControllerLocked.js.map +1 -1
  38. package/dist/esm/PixelStreaming/PixelStreaming.js +12 -13
  39. package/dist/esm/PixelStreaming/PixelStreaming.js.map +1 -1
  40. package/dist/esm/UeInstanceMessage/StreamMessageController.js +4 -0
  41. package/dist/esm/UeInstanceMessage/StreamMessageController.js.map +1 -1
  42. package/dist/esm/Util/BrowserUtils.js +28 -0
  43. package/dist/esm/Util/BrowserUtils.js.map +1 -0
  44. package/dist/esm/Util/EventEmitter.js +9 -0
  45. package/dist/esm/Util/EventEmitter.js.map +1 -1
  46. package/dist/esm/Util/IURLSearchParams.js +1 -0
  47. package/dist/esm/Util/IURLSearchParams.js.map +1 -1
  48. package/dist/esm/Util/RTCUtils.js +1 -0
  49. package/dist/esm/Util/RTCUtils.js.map +1 -1
  50. package/dist/esm/VideoPlayer/VideoPlayer.js +12 -1
  51. package/dist/esm/VideoPlayer/VideoPlayer.js.map +1 -1
  52. package/dist/esm/WebRtcPlayer/WebRtcPlayerController.js +31 -7
  53. package/dist/esm/WebRtcPlayer/WebRtcPlayerController.js.map +1 -1
  54. package/dist/types/Config/Config.d.ts +1 -0
  55. package/dist/types/Inputs/KeyboardController.d.ts +0 -2
  56. package/dist/types/PixelStreaming/PixelStreaming.d.ts +6 -6
  57. package/dist/types/Util/BrowserUtils.d.ts +3 -0
  58. package/dist/types/Util/EventEmitter.d.ts +14 -1
  59. package/dist/types/VideoPlayer/VideoPlayer.d.ts +2 -1
  60. package/dist/types/WebRtcPlayer/WebRtcPlayerController.d.ts +10 -5
  61. package/eslint.config.mjs +4 -4
  62. package/package.json +1 -1
  63. package/src/Config/Config.ts +18 -28
  64. package/src/Config/SettingBase.ts +1 -1
  65. package/src/Config/SettingFlag.ts +1 -1
  66. package/src/Config/SettingNumber.ts +1 -1
  67. package/src/Config/SettingOption.ts +2 -2
  68. package/src/Config/SettingText.ts +1 -1
  69. package/src/Inputs/GamepadController.ts +1 -2
  70. package/src/Inputs/IInputController.ts +1 -0
  71. package/src/Inputs/KeyboardController.ts +0 -31
  72. package/src/Inputs/MouseController.ts +9 -8
  73. package/src/Inputs/MouseControllerHovering.ts +1 -0
  74. package/src/Inputs/MouseControllerLocked.ts +1 -0
  75. package/src/PixelStreaming/PixelStreaming.ts +13 -19
  76. package/src/UeInstanceMessage/StreamMessageController.ts +4 -0
  77. package/src/Util/BrowserUtils.ts +36 -0
  78. package/src/Util/EventEmitter.ts +19 -0
  79. package/src/Util/IURLSearchParams.ts +1 -0
  80. package/src/Util/RTCUtils.ts +1 -0
  81. package/src/VideoPlayer/VideoPlayer.ts +14 -2
  82. package/src/WebRtcPlayer/WebRtcPlayerController.ts +34 -7
  83. package/tsconfig.cjs.json +1 -1
  84. package/tsconfig.esm.json +1 -1
  85. package/tsconfig.jest.json +1 -1
  86. package/dist/cjs/UI/OnScreenKeyboard.js +0 -86
  87. package/dist/cjs/UI/OnScreenKeyboard.js.map +0 -1
  88. package/dist/esm/UI/OnScreenKeyboard.js +0 -82
  89. package/dist/esm/UI/OnScreenKeyboard.js.map +0 -1
  90. package/dist/types/UI/OnScreenKeyboard.d.ts +0 -30
  91. package/src/UI/OnScreenKeyboard.ts +0 -102
  92. /package/{tsconfig.base.json → tsconfig.json} +0 -0
@@ -7,6 +7,7 @@ import { SettingText } from './SettingText';
7
7
  import { SettingOption } from './SettingOption';
8
8
  import { PixelStreamingEventEmitter, SettingsChangedEvent } from '../Util/EventEmitter';
9
9
  import { SettingBase } from './SettingBase';
10
+ import { BrowserUtils } from '../Util/BrowserUtils';
10
11
 
11
12
  /**
12
13
  * A collection of flags that can be toggled and are core to all Pixel Streaming experiences.
@@ -25,6 +26,7 @@ export class Flags {
25
26
  static StartVideoMuted = 'StartVideoMuted' as const;
26
27
  static SuppressBrowserKeys = 'SuppressBrowserKeys' as const;
27
28
  static UseMic = 'UseMic' as const;
29
+ static UseModalForTextInput = 'UseModalForTextInput' as const;
28
30
  static UseCamera = 'UseCamera' as const;
29
31
  static KeyboardInput = 'KeyboardInput' as const;
30
32
  static MouseInput = 'MouseInput' as const;
@@ -214,33 +216,8 @@ export class Config {
214
216
  )
215
217
  );
216
218
 
217
- const getBrowserSupportedVideoCodecs = function (): Array<string> {
218
- const browserSupportedCodecs: Array<string> = [];
219
- // Try get the info needed from the RTCRtpReceiver. This is only available on chrome
220
- if (!RTCRtpReceiver.getCapabilities) {
221
- Logger.Warning(
222
- 'RTCRtpReceiver.getCapabilities API is not available in your browser, defaulting to guess that we support H.264.'
223
- );
224
- browserSupportedCodecs.push(
225
- 'H264 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f'
226
- );
227
- return browserSupportedCodecs;
228
- }
229
-
230
- const matcher = /(VP\d|H26\d|AV1).*/;
231
- const codecs = RTCRtpReceiver.getCapabilities('video').codecs;
232
- codecs.forEach((codec) => {
233
- const str = codec.mimeType.split('/')[1] + ' ' + (codec.sdpFmtpLine || '');
234
- const match = matcher.exec(str);
235
- if (match !== null) {
236
- browserSupportedCodecs.push(str);
237
- }
238
- });
239
- return browserSupportedCodecs;
240
- };
241
-
242
219
  const getDefaultVideoCodec = function (): string {
243
- const videoCodecs = getBrowserSupportedVideoCodecs();
220
+ const videoCodecs = BrowserUtils.getSupportedVideoCodecs();
244
221
  // If only one option, then select that.
245
222
  if (videoCodecs.length == 1) {
246
223
  return videoCodecs[0];
@@ -259,7 +236,7 @@ export class Config {
259
236
  };
260
237
 
261
238
  const matchSpecifiedCodecToClosestSupported = function (specifiedCodec: string): string {
262
- const browserSupportedCodecs: Array<string> = getBrowserSupportedVideoCodecs();
239
+ const browserSupportedCodecs: Array<string> = BrowserUtils.getSupportedVideoCodecs();
263
240
 
264
241
  // Codec supplied in url param is an exact match for the browser codec.
265
242
  // (e.g. H264 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f)
@@ -290,7 +267,7 @@ export class Config {
290
267
  settings && Object.prototype.hasOwnProperty.call(settings, OptionParameters.PreferredCodec)
291
268
  ? matchSpecifiedCodecToClosestSupported(settings[OptionParameters.PreferredCodec])
292
269
  : getDefaultVideoCodec(),
293
- getBrowserSupportedVideoCodecs(),
270
+ BrowserUtils.getSupportedVideoCodecs(),
294
271
  useUrlParams,
295
272
  matchSpecifiedCodecToClosestSupported
296
273
  )
@@ -353,6 +330,19 @@ export class Config {
353
330
  )
354
331
  );
355
332
 
333
+ this.flags.set(
334
+ Flags.UseModalForTextInput,
335
+ new SettingFlag(
336
+ Flags.UseModalForTextInput,
337
+ 'Use modal for text input',
338
+ 'When entering input into a streamed UE text widget, use an input modal.',
339
+ settings && Object.prototype.hasOwnProperty.call(settings, Flags.UseModalForTextInput)
340
+ ? settings[Flags.UseModalForTextInput]
341
+ : true,
342
+ useUrlParams
343
+ )
344
+ );
345
+
356
346
  this.flags.set(
357
347
  Flags.UseCamera,
358
348
  new SettingFlag(
@@ -18,7 +18,7 @@ export class SettingBase {
18
18
  label: string,
19
19
  description: string,
20
20
  defaultSettingValue: unknown,
21
-
21
+
22
22
  defaultOnChangeListener: (changedValue: unknown, setting: SettingBase) => void = () => {
23
23
  /* Do nothing, to be overridden. */
24
24
  }
@@ -16,7 +16,7 @@ export class SettingFlag<CustomIds extends string = FlagsIds> extends SettingBas
16
16
  description: string,
17
17
  defaultFlagValue: boolean,
18
18
  useUrlParams: boolean,
19
-
19
+
20
20
  defaultOnChangeListener: (changedValue: unknown, setting: SettingBase) => void = () => {
21
21
  /* Do nothing, to be overridden. */
22
22
  }
@@ -21,7 +21,7 @@ export class SettingNumber<CustomIds extends string = NumericParametersIds> exte
21
21
  max: number | null,
22
22
  defaultNumber: number,
23
23
  useUrlParams: boolean,
24
-
24
+
25
25
  defaultOnChangeListener: (changedValue: unknown, setting: SettingBase) => void = () => {
26
26
  /* Do nothing, to be overridden. */
27
27
  }
@@ -22,12 +22,12 @@ export class SettingOption<CustomIds extends string = OptionParametersIds> exten
22
22
  defaultTextValue: string,
23
23
  options: Array<string>,
24
24
  useUrlParams: boolean,
25
-
25
+
26
26
  defaultUrlParamResolver: (urlParamValue: string) => string = function (value: string) {
27
27
  /* Return the string as-is by default */
28
28
  return value;
29
29
  },
30
-
30
+
31
31
  defaultOnChangeListener: (changedValue: unknown, setting: SettingBase) => void = () => {
32
32
  /* Do nothing, to be overridden. */
33
33
  }
@@ -17,7 +17,7 @@ export class SettingText<CustomIds extends string = TextParametersIds> extends S
17
17
  description: string,
18
18
  defaultTextValue: string,
19
19
  useUrlParams: boolean,
20
-
20
+
21
21
  defaultOnChangeListener: (changedValue: unknown, setting: SettingBase) => void = () => {
22
22
  /* Do nothing, to be overridden. */
23
23
  }
@@ -21,7 +21,7 @@ declare global {
21
21
  /**
22
22
  * Gamepad layout codes enum
23
23
  */
24
-
24
+
25
25
  export enum GamepadLayout {
26
26
  RightClusterBottomButton = 0,
27
27
  RightClusterRightButton = 1,
@@ -46,7 +46,6 @@ export enum GamepadLayout {
46
46
  RightStickHorizontal = 2,
47
47
  RightStickVertical = 3
48
48
  }
49
-
50
49
 
51
50
  /**
52
51
  * Handles gamepad events from the document to send to the streamer.
@@ -1,3 +1,4 @@
1
+ // Copyright Epic Games, Inc. All Rights Reserved.
1
2
  /**
2
3
  * The base interface for all input controllers.
3
4
  * Since controllers mostly just register events and handle them the external interface is limited
@@ -19,7 +19,6 @@ export class KeyboardController implements IInputController {
19
19
  onKeyDownListener: (event: KeyboardEvent) => void;
20
20
  onKeyUpListener: (event: KeyboardEvent) => void;
21
21
  onKeyPressListener: (event: KeyboardEvent) => void;
22
- onCompositionEndListener: (event: CompositionEvent) => void;
23
22
 
24
23
  constructor(streamMessageController: StreamMessageController, config: Config, activeKeys: ActiveKeys) {
25
24
  this.streamMessageController = streamMessageController;
@@ -29,11 +28,9 @@ export class KeyboardController implements IInputController {
29
28
  this.onKeyDownListener = this.handleOnKeyDown.bind(this);
30
29
  this.onKeyUpListener = this.handleOnKeyUp.bind(this);
31
30
  this.onKeyPressListener = this.handleOnKeyPress.bind(this);
32
- this.onCompositionEndListener = this.handleOnCompositionEnd.bind(this);
33
31
  }
34
32
 
35
33
  register() {
36
- document.addEventListener('compositionend', this.onCompositionEndListener);
37
34
  document.addEventListener('keydown', this.onKeyDownListener);
38
35
  document.addEventListener('keyup', this.onKeyUpListener);
39
36
  //This has been deprecated as at Jun 13 2021
@@ -41,7 +38,6 @@ export class KeyboardController implements IInputController {
41
38
  }
42
39
 
43
40
  unregister() {
44
- document.removeEventListener('compositionend', this.onCompositionEndListener);
45
41
  document.removeEventListener('keydown', this.onKeyDownListener);
46
42
  document.removeEventListener('keyup', this.onKeyUpListener);
47
43
  document.removeEventListener('keypress', this.onKeyPressListener);
@@ -100,33 +96,6 @@ export class KeyboardController implements IInputController {
100
96
  toStreamerHandlers.get('KeyPress')?.([keyCode]);
101
97
  }
102
98
 
103
- private handleOnCompositionEnd(compositionEvent: CompositionEvent) {
104
- if (compositionEvent.data && compositionEvent.data.length) {
105
- compositionEvent.data.split('').forEach((char) => {
106
- // This keydown, keypress, keyup flow is required to mimic the way characters are
107
- // normally triggered
108
- this.handleOnKeyDown(
109
- new KeyboardEvent('keydown', {
110
- keyCode: char.toUpperCase().charCodeAt(0),
111
- charCode: char.charCodeAt(0)
112
- })
113
- );
114
- this.handleOnKeyPress(
115
- new KeyboardEvent('keypress', {
116
- keyCode: char.toUpperCase().charCodeAt(0),
117
- charCode: char.charCodeAt(0)
118
- })
119
- );
120
- this.handleOnKeyUp(
121
- new KeyboardEvent('keyup', {
122
- keyCode: char.toUpperCase().charCodeAt(0),
123
- charCode: char.charCodeAt(0)
124
- })
125
- );
126
- });
127
- }
128
- }
129
-
130
99
  /**
131
100
  * Gets the Keycode of the Key pressed
132
101
  * @param keyboardEvent - Key board Event
@@ -1,3 +1,4 @@
1
+ // Copyright Epic Games, Inc. All Rights Reserved.
1
2
  import { MouseButtonsMask, MouseButton } from './MouseButtons';
2
3
  import { StreamMessageController } from '../UeInstanceMessage/StreamMessageController';
3
4
  import { InputCoordTranslator } from '../Util/InputCoordTranslator';
@@ -57,22 +58,22 @@ export class MouseController implements IInputController {
57
58
  }
58
59
 
59
60
  registerMouseEnterAndLeaveEvents() {
60
- const videoElementParent = this.videoPlayer.getVideoParentElement() as HTMLDivElement;
61
- videoElementParent.addEventListener('mouseenter', this.onEnterListener);
62
- videoElementParent.addEventListener('mouseleave', this.onLeaveListener);
61
+ const videoElementParent = this.videoPlayer.getVideoParentElement();
62
+ videoElementParent?.addEventListener('mouseenter', this.onEnterListener);
63
+ videoElementParent?.addEventListener('mouseleave', this.onLeaveListener);
63
64
  }
64
65
 
65
66
  unregisterMouseEnterAndLeaveEvents() {
66
- const videoElementParent = this.videoPlayer.getVideoParentElement() as HTMLDivElement;
67
- videoElementParent.removeEventListener('mouseenter', this.onEnterListener);
68
- videoElementParent.removeEventListener('mouseleave', this.onLeaveListener);
67
+ const videoElementParent = this.videoPlayer.getVideoParentElement();
68
+ videoElementParent?.removeEventListener('mouseenter', this.onEnterListener);
69
+ videoElementParent?.removeEventListener('mouseleave', this.onLeaveListener);
69
70
  }
70
71
 
71
72
  private onMouseEnter(event: MouseEvent) {
72
73
  if (!this.videoPlayer.isVideoReady()) {
73
74
  return;
74
75
  }
75
- this.streamMessageController.toStreamerHandlers.get('MouseEnter')();
76
+ this.streamMessageController.toStreamerHandlers.get('MouseEnter')?.();
76
77
  this.pressMouseButtons(event.buttons, event.x, event.y);
77
78
  }
78
79
 
@@ -80,7 +81,7 @@ export class MouseController implements IInputController {
80
81
  if (!this.videoPlayer.isVideoReady()) {
81
82
  return;
82
83
  }
83
- this.streamMessageController.toStreamerHandlers.get('MouseLeave')();
84
+ this.streamMessageController.toStreamerHandlers.get('MouseLeave')?.();
84
85
  this.releaseMouseButtons(event.buttons, event.x, event.y);
85
86
  }
86
87
 
@@ -1,3 +1,4 @@
1
+ // Copyright Epic Games, Inc. All Rights Reserved.
1
2
  import { StreamMessageController } from '../UeInstanceMessage/StreamMessageController';
2
3
  import { InputCoordTranslator } from '../Util/InputCoordTranslator';
3
4
  import { VideoPlayer } from '../VideoPlayer/VideoPlayer';
@@ -1,3 +1,4 @@
1
+ // Copyright Epic Games, Inc. All Rights Reserved.
1
2
  import { Logger } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.5';
2
3
  import { StreamMessageController } from '../UeInstanceMessage/StreamMessageController';
3
4
  import { InputCoordTranslator, TranslatedCoordUnsigned } from '../Util/InputCoordTranslator';
@@ -7,7 +7,6 @@ import { WebRtcPlayerController } from '../WebRtcPlayer/WebRtcPlayerController';
7
7
  import { Flags, NumericParameters } from '../Config/Config';
8
8
  import { Logger } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.5';
9
9
  import { InitialSettings } from '../DataChannel/InitialSettings';
10
- import { OnScreenKeyboard } from '../UI/OnScreenKeyboard';
11
10
  import {
12
11
  PixelStreamingEventEmitter,
13
12
  InitialSettingsEvent,
@@ -78,8 +77,6 @@ export class PixelStreaming {
78
77
 
79
78
  private allowConsoleCommands = false;
80
79
 
81
- private onScreenKeyboardHelper: OnScreenKeyboard;
82
-
83
80
  private _videoStartTime: number;
84
81
  private _inputController: boolean;
85
82
 
@@ -104,13 +101,6 @@ export class PixelStreaming {
104
101
  // setup WebRTC
105
102
  this.setWebRtcPlayerController(new WebRtcPlayerController(this.config, this));
106
103
 
107
- // Onscreen keyboard
108
- this.onScreenKeyboardHelper = new OnScreenKeyboard(this.videoElementParent);
109
- this.onScreenKeyboardHelper.unquantizeAndDenormalizeUnsigned = (x: number, y: number) =>
110
- this._webRtcController.requestUnquantizedAndDenormalizeUnsigned(x, y);
111
- this._activateOnScreenKeyboard = (command: any) =>
112
- this.onScreenKeyboardHelper.showOnScreenKeyboard(command);
113
-
114
104
  this._webXrController = new WebXRController(this._webRtcController);
115
105
 
116
106
  this._setupWebRtcTCPRelayDetection = this._setupWebRtcTCPRelayDetection.bind(this);
@@ -277,15 +267,6 @@ export class PixelStreaming {
277
267
  this.config._registerOnChangeEvents(this._eventEmitter);
278
268
  }
279
269
 
280
- /**
281
- * Activate the on screen keyboard when receiving the command from the streamer
282
- * @param command - the keyboard command
283
- */
284
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
285
- _activateOnScreenKeyboard(command: any): void {
286
- throw new Error('Method not implemented.');
287
- }
288
-
289
270
  /**
290
271
  * Set the input control ownership
291
272
  * @param inputControlOwnership - does the user have input control ownership
@@ -819,6 +800,19 @@ export class PixelStreaming {
819
800
  return true;
820
801
  }
821
802
 
803
+ /**
804
+ * Sets the text contents of the currently focused UE text box widget.
805
+ * @param contents The new contents of the UE text box.
806
+ * @returns True if the message could be sent.
807
+ */
808
+ public sendTextboxEntry(contents: string): boolean {
809
+ if (!this._webRtcController.videoPlayer.isVideoReady()) {
810
+ return false;
811
+ }
812
+ this._webRtcController.sendTextboxEntry(contents);
813
+ return true;
814
+ }
815
+
822
816
  /**
823
817
  * Add a UE -> browser response event listener
824
818
  * @param name - The name of the response handler
@@ -81,6 +81,10 @@ export class StreamMessageController {
81
81
  id: 51,
82
82
  structure: ['string']
83
83
  });
84
+ this.toStreamerMessages.set('TextboxEntry', {
85
+ id: 52,
86
+ structure: ['string']
87
+ });
84
88
  // Keyboard Input Message. Range = 60..69.
85
89
  this.toStreamerMessages.set('KeyDown', {
86
90
  id: 60,
@@ -0,0 +1,36 @@
1
+ // Copyright Epic Games, Inc. All Rights Reserved.
2
+
3
+ import { Logger } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.5';
4
+
5
+ export class BrowserUtils {
6
+ static getSupportedVideoCodecs(): Array<string> {
7
+ const browserSupportedCodecs: Array<string> = [];
8
+ // Try get the info needed from the RTCRtpReceiver. This is only available on chrome
9
+ if (!RTCRtpReceiver.getCapabilities) {
10
+ Logger.Warning(
11
+ 'RTCRtpReceiver.getCapabilities API is not available in your browser, defaulting to guess that we support H.264.'
12
+ );
13
+ browserSupportedCodecs.push(
14
+ 'H264 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f'
15
+ );
16
+ return browserSupportedCodecs;
17
+ }
18
+
19
+ const matcher = /(VP\d|H26\d|AV1).*/;
20
+ const capabilities = RTCRtpReceiver.getCapabilities('video');
21
+ if (!capabilities) {
22
+ browserSupportedCodecs.push(
23
+ 'H264 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f'
24
+ );
25
+ return browserSupportedCodecs;
26
+ }
27
+ capabilities.codecs.forEach((codec) => {
28
+ const str = codec.mimeType.split('/')[1] + ' ' + (codec.sdpFmtpLine || '');
29
+ const match = matcher.exec(str);
30
+ if (match !== null) {
31
+ browserSupportedCodecs.push(str);
32
+ }
33
+ });
34
+ return browserSupportedCodecs;
35
+ }
36
+ }
@@ -1,3 +1,4 @@
1
+ // Copyright Epic Games, Inc. All Rights Reserved.
1
2
  import { FlagsIds, NumericParametersIds, OptionParametersIds, TextParametersIds } from '../Config/Config';
2
3
  import { LatencyTestResults } from '../DataChannel/LatencyTestResults';
3
4
  import { AggregatedStats } from '../PeerConnectionController/AggregatedStats';
@@ -427,6 +428,23 @@ export class LatencyCalculatedEvent extends Event {
427
428
  }
428
429
  }
429
430
 
431
+ /**
432
+ * An event that is emitted when we receive the "onScreenKeyboard" command from UE.
433
+ */
434
+ export class ShowOnScreenKeyboardEvent extends Event {
435
+ override readonly type: 'showOnScreenKeyboard';
436
+ readonly data: {
437
+ showOnScreenKeyboard: boolean;
438
+ x: number;
439
+ y: number;
440
+ contents: string;
441
+ };
442
+ constructor(data: ShowOnScreenKeyboardEvent['data']) {
443
+ super('showOnScreenKeyboard');
444
+ this.data = data;
445
+ }
446
+ }
447
+
430
448
  /**
431
449
  * An event that is emitted when receiving data channel latency test response from server.
432
450
  * This event is handled by DataChannelLatencyTestController
@@ -616,6 +634,7 @@ export type PixelStreamingEvent =
616
634
  | DataChannelCloseEvent
617
635
  | DataChannelErrorEvent
618
636
  | VideoInitializedEvent
637
+ | ShowOnScreenKeyboardEvent
619
638
  | StreamLoadingEvent
620
639
  | StreamPreConnectEvent
621
640
  | StreamReconnectEvent
@@ -1,3 +1,4 @@
1
+ // Copyright Epic Games, Inc. All Rights Reserved.
1
2
  /**
2
3
  * A case insensitive, partial implementation of URLSearchParams
3
4
  */
@@ -1,3 +1,4 @@
1
+ // Copyright Epic Games, Inc. All Rights Reserved.
1
2
  export class RTCUtils {
2
3
  static isVideoTransceiver(transceiver: RTCRtpTransceiver | undefined): boolean {
3
4
  return this.canTransceiverReceiveVideo(transceiver) || this.canTransceiverSendVideo(transceiver);
@@ -70,6 +70,18 @@ export class VideoPlayer {
70
70
  window.addEventListener('orientationchange', () => this.onOrientationChange());
71
71
  }
72
72
 
73
+ public destroy() {
74
+ this.videoElement.src = '';
75
+ this.videoElement.srcObject = null;
76
+ this.videoElement.remove();
77
+
78
+ if (this.audioElement) {
79
+ this.audioElement.src = '';
80
+ this.audioElement.srcObject = null;
81
+ this.audioElement.remove();
82
+ }
83
+ }
84
+
73
85
  public setAudioElement(audioElement: HTMLAudioElement): void {
74
86
  this.audioElement = audioElement;
75
87
  }
@@ -117,8 +129,8 @@ export class VideoPlayer {
117
129
  * Get the current context of the html video elements parent
118
130
  * @returns - the current context of the video elements parent
119
131
  */
120
- getVideoParentElement(): HTMLElement {
121
- return this.videoElement.parentElement;
132
+ getVideoParentElement(): HTMLElement | undefined {
133
+ return this.videoElement.parentElement ?? undefined;
122
134
  }
123
135
 
124
136
  /**
@@ -34,7 +34,7 @@ import { ResponseController } from '../UeInstanceMessage/ResponseController';
34
34
  import { SendMessageController } from '../UeInstanceMessage/SendMessageController';
35
35
  import { ToStreamerMessagesController } from '../UeInstanceMessage/ToStreamerMessagesController';
36
36
  import { DataChannelSender } from '../DataChannel/DataChannelSender';
37
- import { InputCoordTranslator, UntranslatedCoordUnsigned } from '../Util/InputCoordTranslator';
37
+ import { InputCoordTranslator } from '../Util/InputCoordTranslator';
38
38
  import { PixelStreaming } from '../PixelStreaming/PixelStreaming';
39
39
  import {
40
40
  DataChannelCloseEvent,
@@ -45,6 +45,7 @@ import {
45
45
  PlayStreamErrorEvent,
46
46
  PlayStreamEvent,
47
47
  PlayStreamRejectedEvent,
48
+ ShowOnScreenKeyboardEvent,
48
49
  StreamerListMessageEvent,
49
50
  StreamerIDChangedMessageEvent
50
51
  } from '../Util/EventEmitter';
@@ -56,6 +57,7 @@ import { IURLSearchParams } from '../Util/IURLSearchParams';
56
57
  import { IInputController } from '../Inputs/IInputController';
57
58
  import { GamepadController } from '../Inputs/GamepadController';
58
59
  import { LatencyInfo } from '../PeerConnectionController/LatencyCalculator';
60
+ import { BrowserUtils } from '../Util/BrowserUtils';
59
61
 
60
62
  /**
61
63
  * Entry point for the WebRTC Player
@@ -232,6 +234,11 @@ export class WebRtcPlayerController {
232
234
 
233
235
  this.forceReconnect = false;
234
236
 
237
+ // Reset the list of all possible codecs on disconnect so that if the next connection has "NegotiateCodecs" on
238
+ // then all codecs can be negotiated
239
+ this.config.getSettingOption(OptionParameters.PreferredCodec).options =
240
+ BrowserUtils.getSupportedVideoCodecs();
241
+
235
242
  this.pixelStreaming._onDisconnect(disconnectMessage, allowClickToReconnect);
236
243
 
237
244
  this.afkController.stopAfkWarningTimer();
@@ -335,12 +342,11 @@ export class WebRtcPlayerController {
335
342
  }
336
343
 
337
344
  /**
338
- * Make a request to UnquantizedAndDenormalizeUnsigned coordinates
339
- * @param x x axis coordinate
340
- * @param y y axis coordinate
345
+ * Destroys the video player and makes sure resources are freed. This helps to prevent the issue in chrome
346
+ * where it refuses to make new video players.
341
347
  */
342
- requestUnquantizedAndDenormalizeUnsigned(x: number, y: number): UntranslatedCoordUnsigned {
343
- return this.coordinateConverter.untranslateUnsigned(x, y);
348
+ destroyVideoPlayer() {
349
+ this.videoPlayer.destroy();
344
350
  }
345
351
 
346
352
  /**
@@ -700,11 +706,23 @@ export class WebRtcPlayerController {
700
706
 
701
707
  Logger.Info('Data Channel Command: ' + commandAsString);
702
708
  const command = JSON.parse(commandAsString);
709
+
710
+ // Handle "onScreenKeyboard" event
703
711
  if (command.command === 'onScreenKeyboard') {
704
- this.pixelStreaming._activateOnScreenKeyboard(command);
712
+ this.handleOnScreenKeyboardCommand(command);
705
713
  }
706
714
  }
707
715
 
716
+ handleOnScreenKeyboardCommand(command: any) {
717
+ const data: ShowOnScreenKeyboardEvent['data'] = {
718
+ showOnScreenKeyboard: command.showOnScreenKeyboard ?? true,
719
+ x: command.x ?? 0,
720
+ y: command.y ?? 0,
721
+ contents: command.contents ?? ''
722
+ };
723
+ this.pixelStreaming.dispatchEvent(new ShowOnScreenKeyboardEvent(data));
724
+ }
725
+
708
726
  /**
709
727
  * Handles a protocol message received from the streamer
710
728
  * @param message the message data from the streamer
@@ -1762,6 +1780,15 @@ export class WebRtcPlayerController {
1762
1780
  this.toStreamerMessagesController.SendRequestQualityControl();
1763
1781
  }
1764
1782
 
1783
+ /**
1784
+ * Send a `TextBoxEntry` message back to UE.
1785
+ * @param contents The new contents of the UE side text box.
1786
+ */
1787
+ sendTextboxEntry(contents: string) {
1788
+ Logger.Info('---- Sending TextboxEntry message ----');
1789
+ this.streamMessageController.toStreamerHandlers.get('TextboxEntry')?.([contents]);
1790
+ }
1791
+
1765
1792
  /**
1766
1793
  * Handles when a Latency Test Result are received from the UE Instance
1767
1794
  * @param message - Latency Test Timings
package/tsconfig.cjs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "extends": "./tsconfig.base.json",
2
+ "extends": "./tsconfig.json",
3
3
  "compilerOptions": {
4
4
  "outDir": "./dist/cjs",
5
5
  "module": "commonjs"
package/tsconfig.esm.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "extends": "./tsconfig.base.json",
2
+ "extends": "./tsconfig.json",
3
3
  "compilerOptions": {
4
4
  "outDir": "./dist/esm",
5
5
  "module": "es6",
@@ -1,5 +1,5 @@
1
1
  {
2
- "extends": "./tsconfig.base.json",
2
+ "extends": "./tsconfig.json",
3
3
  "include": ["./src/**/*.ts"],
4
4
  "exclude": [],
5
5
  "compilerOptions": {