@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.
Files changed (138) hide show
  1. package/.cspell.json +48 -0
  2. package/.eslintignore +8 -0
  3. package/.eslintrc.js +8 -0
  4. package/.prettierignore +0 -0
  5. package/.prettierrc.json +6 -0
  6. package/dist/lib-pixelstreamingfrontend.esm.js +1 -0
  7. package/dist/lib-pixelstreamingfrontend.js +1 -0
  8. package/jest.config.js +18 -0
  9. package/package.json +48 -0
  10. package/readme.md +15 -0
  11. package/src/AFK/AFKController.test.ts +162 -0
  12. package/src/AFK/AFKController.ts +158 -0
  13. package/src/Config/Config.test.ts +222 -0
  14. package/src/Config/Config.ts +970 -0
  15. package/src/Config/SettingBase.ts +65 -0
  16. package/src/Config/SettingFlag.ts +99 -0
  17. package/src/Config/SettingNumber.ts +111 -0
  18. package/src/Config/SettingOption.ts +124 -0
  19. package/src/Config/SettingText.ts +82 -0
  20. package/src/DataChannel/DataChannelController.ts +138 -0
  21. package/src/DataChannel/DataChannelLatencyTestController.ts +129 -0
  22. package/src/DataChannel/DataChannelLatencyTestResults.ts +67 -0
  23. package/src/DataChannel/DataChannelSender.ts +59 -0
  24. package/src/DataChannel/InitialSettings.ts +61 -0
  25. package/src/DataChannel/LatencyTestResults.ts +76 -0
  26. package/src/FreezeFrame/FreezeFrame.ts +114 -0
  27. package/src/FreezeFrame/FreezeFrameController.ts +114 -0
  28. package/src/Inputs/FakeTouchController.ts +199 -0
  29. package/src/Inputs/GamepadController.ts +314 -0
  30. package/src/Inputs/GamepadTypes.ts +10 -0
  31. package/src/Inputs/HoveringMouseEvents.ts +192 -0
  32. package/src/Inputs/IMouseEvents.ts +64 -0
  33. package/src/Inputs/ITouchController.ts +29 -0
  34. package/src/Inputs/InputClassesFactory.ts +140 -0
  35. package/src/Inputs/KeyboardController.ts +354 -0
  36. package/src/Inputs/LockedMouseEvents.ts +287 -0
  37. package/src/Inputs/MouseButtons.ts +25 -0
  38. package/src/Inputs/MouseController.ts +362 -0
  39. package/src/Inputs/SpecialKeyCodes.ts +16 -0
  40. package/src/Inputs/TouchController.ts +208 -0
  41. package/src/Inputs/XRGamepadController.ts +126 -0
  42. package/src/PeerConnectionController/AggregatedStats.ts +311 -0
  43. package/src/PeerConnectionController/CandidatePairStats.ts +17 -0
  44. package/src/PeerConnectionController/CandidateStat.ts +13 -0
  45. package/src/PeerConnectionController/CodecStats.ts +19 -0
  46. package/src/PeerConnectionController/DataChannelStats.ts +17 -0
  47. package/src/PeerConnectionController/InboundRTPStats.ts +154 -0
  48. package/src/PeerConnectionController/InboundTrackStats.ts +34 -0
  49. package/src/PeerConnectionController/OutBoundRTPStats.ts +26 -0
  50. package/src/PeerConnectionController/PeerConnectionController.ts +563 -0
  51. package/src/PeerConnectionController/SessionStats.ts +10 -0
  52. package/src/PeerConnectionController/StreamStats.ts +11 -0
  53. package/src/PixelStreaming/PixelStreaming.test.ts +626 -0
  54. package/src/PixelStreaming/PixelStreaming.ts +851 -0
  55. package/src/UI/OnScreenKeyboard.ts +97 -0
  56. package/src/UeInstanceMessage/ResponseController.ts +47 -0
  57. package/src/UeInstanceMessage/SendMessageController.ts +154 -0
  58. package/src/UeInstanceMessage/StreamMessageController.ts +233 -0
  59. package/src/UeInstanceMessage/ToStreamerMessagesController.ts +62 -0
  60. package/src/Util/CoordinateConverter.ts +289 -0
  61. package/src/Util/EventEmitter.ts +611 -0
  62. package/src/Util/EventListenerTracker.ts +29 -0
  63. package/src/Util/FileUtil.ts +140 -0
  64. package/src/Util/RTCUtils.ts +41 -0
  65. package/src/Util/WebGLUtils.ts +49 -0
  66. package/src/Util/WebXRUtils.ts +25 -0
  67. package/src/VideoPlayer/StreamController.ts +89 -0
  68. package/src/VideoPlayer/VideoPlayer.ts +246 -0
  69. package/src/WebRtcPlayer/WebRtcPlayerController.ts +2158 -0
  70. package/src/WebXR/WebXRController.ts +319 -0
  71. package/src/__test__/mockMediaStream.ts +124 -0
  72. package/src/__test__/mockRTCPeerConnection.ts +347 -0
  73. package/src/__test__/mockRTCRtpReceiver.ts +22 -0
  74. package/src/__test__/mockWebSocket.ts +136 -0
  75. package/src/pixelstreamingfrontend.ts +46 -0
  76. package/tsconfig.jest.json +8 -0
  77. package/tsconfig.json +24 -0
  78. package/types/AFK/AFKController.d.ts +39 -0
  79. package/types/Config/Config.d.ts +218 -0
  80. package/types/Config/SettingBase.d.ts +30 -0
  81. package/types/Config/SettingFlag.d.ts +33 -0
  82. package/types/Config/SettingNumber.d.ts +45 -0
  83. package/types/Config/SettingOption.d.ts +43 -0
  84. package/types/Config/SettingText.d.ts +29 -0
  85. package/types/DataChannel/DataChannelController.d.ts +59 -0
  86. package/types/DataChannel/DataChannelLatencyTestController.d.ts +26 -0
  87. package/types/DataChannel/DataChannelLatencyTestResults.d.ts +46 -0
  88. package/types/DataChannel/DataChannelSender.d.ts +21 -0
  89. package/types/DataChannel/InitialSettings.d.ts +44 -0
  90. package/types/DataChannel/LatencyTestResults.d.ts +31 -0
  91. package/types/FreezeFrame/FreezeFrame.d.ts +36 -0
  92. package/types/FreezeFrame/FreezeFrameController.d.ts +37 -0
  93. package/types/Inputs/FakeTouchController.d.ts +61 -0
  94. package/types/Inputs/GamepadController.d.ts +85 -0
  95. package/types/Inputs/GamepadTypes.d.ts +8 -0
  96. package/types/Inputs/HoveringMouseEvents.d.ts +56 -0
  97. package/types/Inputs/IMouseEvents.d.ts +53 -0
  98. package/types/Inputs/ITouchController.d.ts +24 -0
  99. package/types/Inputs/InputClassesFactory.d.ts +54 -0
  100. package/types/Inputs/KeyboardController.d.ts +62 -0
  101. package/types/Inputs/LockedMouseEvents.d.ts +80 -0
  102. package/types/Inputs/MouseButtons.d.ts +22 -0
  103. package/types/Inputs/MouseController.d.ts +75 -0
  104. package/types/Inputs/SpecialKeyCodes.d.ts +14 -0
  105. package/types/Inputs/TouchController.d.ts +53 -0
  106. package/types/Inputs/XRGamepadController.d.ts +15 -0
  107. package/types/PeerConnectionController/AggregatedStats.d.ts +77 -0
  108. package/types/PeerConnectionController/CandidatePairStats.d.ts +15 -0
  109. package/types/PeerConnectionController/CandidateStat.d.ts +11 -0
  110. package/types/PeerConnectionController/CodecStats.d.ts +14 -0
  111. package/types/PeerConnectionController/DataChannelStats.d.ts +15 -0
  112. package/types/PeerConnectionController/InboundRTPStats.d.ts +141 -0
  113. package/types/PeerConnectionController/InboundTrackStats.d.ts +32 -0
  114. package/types/PeerConnectionController/OutBoundRTPStats.d.ts +23 -0
  115. package/types/PeerConnectionController/PeerConnectionController.d.ts +132 -0
  116. package/types/PeerConnectionController/SessionStats.d.ts +8 -0
  117. package/types/PeerConnectionController/StreamStats.d.ts +9 -0
  118. package/types/PixelStreaming/PixelStreaming.d.ts +259 -0
  119. package/types/UI/OnScreenKeyboard.d.ts +31 -0
  120. package/types/UeInstanceMessage/ResponseController.d.ts +19 -0
  121. package/types/UeInstanceMessage/SendMessageController.d.ts +18 -0
  122. package/types/UeInstanceMessage/StreamMessageController.d.ts +29 -0
  123. package/types/UeInstanceMessage/ToStreamerMessagesController.d.ts +32 -0
  124. package/types/Util/CoordinateConverter.d.ts +100 -0
  125. package/types/Util/EventEmitter.d.ts +422 -0
  126. package/types/Util/EventListenerTracker.d.ts +14 -0
  127. package/types/Util/FileUtil.d.ts +32 -0
  128. package/types/Util/RTCUtils.d.ts +8 -0
  129. package/types/Util/WebGLUtils.d.ts +4 -0
  130. package/types/Util/WebXRUtils.d.ts +9 -0
  131. package/types/VideoPlayer/StreamController.d.ts +24 -0
  132. package/types/VideoPlayer/VideoPlayer.d.ts +78 -0
  133. package/types/WebRtcPlayer/WebRtcPlayerController.d.ts +377 -0
  134. package/types/WebXR/WebXRController.d.ts +26 -0
  135. package/types/pixelstreamingfrontend.d.ts +22 -0
  136. package/webpack.common.js +35 -0
  137. package/webpack.dev.js +35 -0
  138. package/webpack.prod.js +36 -0
@@ -0,0 +1,319 @@
1
+ // Copyright Epic Games, Inc. All Rights Reserved.
2
+
3
+ import { Logger } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.5';
4
+ import { WebRtcPlayerController } from '../WebRtcPlayer/WebRtcPlayerController';
5
+ import { WebGLUtils } from '../Util/WebGLUtils';
6
+ import { Controller } from '../Inputs/GamepadTypes';
7
+ import { XRGamepadController } from '../Inputs/XRGamepadController';
8
+ import { XrFrameEvent } from '../Util/EventEmitter'
9
+ import { Flags } from '../pixelstreamingfrontend';
10
+
11
+ export class WebXRController {
12
+ private xrSession: XRSession;
13
+ private xrRefSpace: XRReferenceSpace;
14
+ private gl: WebGL2RenderingContext;
15
+
16
+ private positionLocation: number;
17
+ private texcoordLocation: number;
18
+ private resolutionLocation: WebGLUniformLocation;
19
+ private offsetLocation: WebGLUniformLocation;
20
+
21
+ private positionBuffer: WebGLBuffer;
22
+ private texcoordBuffer: WebGLBuffer;
23
+
24
+ private webRtcController: WebRtcPlayerController;
25
+ private xrGamepadController: XRGamepadController;
26
+ private xrControllers: Array<Controller>;
27
+
28
+ onSessionStarted: EventTarget;
29
+ onSessionEnded: EventTarget;
30
+ onFrame: EventTarget;
31
+
32
+ constructor(webRtcPlayerController: WebRtcPlayerController) {
33
+ this.xrSession = null;
34
+ this.webRtcController = webRtcPlayerController;
35
+ this.xrControllers = [];
36
+ this.xrGamepadController = new XRGamepadController(
37
+ this.webRtcController.streamMessageController
38
+ );
39
+ this.onSessionEnded = new EventTarget();
40
+ this.onSessionStarted = new EventTarget();
41
+ this.onFrame = new EventTarget();
42
+ }
43
+
44
+ public xrClicked() {
45
+ if (!this.xrSession) {
46
+ navigator.xr
47
+ .requestSession('immersive-vr')
48
+ .then((session: XRSession) => {
49
+ this.onXrSessionStarted(session);
50
+ });
51
+ } else {
52
+ this.xrSession.end();
53
+ }
54
+ }
55
+
56
+ onXrSessionEnded() {
57
+ Logger.Log(Logger.GetStackTrace(), 'XR Session ended');
58
+ this.xrSession = null;
59
+ this.onSessionEnded.dispatchEvent(new Event('xrSessionEnded'));
60
+ }
61
+
62
+ onXrSessionStarted(session: XRSession) {
63
+ Logger.Log(Logger.GetStackTrace(), 'XR Session started');
64
+
65
+ this.xrSession = session;
66
+ this.xrSession.addEventListener('end', () => {
67
+ this.onXrSessionEnded();
68
+ });
69
+
70
+ const canvas = document.createElement('canvas');
71
+ this.gl = canvas.getContext('webgl2', {
72
+ xrCompatible: true
73
+ });
74
+
75
+ this.xrSession.updateRenderState({
76
+ baseLayer: new XRWebGLLayer(this.xrSession, this.gl)
77
+ });
78
+
79
+ // setup vertex shader
80
+ const vertexShader = this.gl.createShader(this.gl.VERTEX_SHADER);
81
+ this.gl.shaderSource(vertexShader, WebGLUtils.vertexShader());
82
+ this.gl.compileShader(vertexShader);
83
+
84
+ // setup fragment shader
85
+ const fragmentShader = this.gl.createShader(this.gl.FRAGMENT_SHADER);
86
+ this.gl.shaderSource(fragmentShader, WebGLUtils.fragmentShader());
87
+ this.gl.compileShader(fragmentShader);
88
+
89
+ // setup GLSL program
90
+ const shaderProgram = this.gl.createProgram();
91
+ this.gl.attachShader(shaderProgram, vertexShader);
92
+ this.gl.attachShader(shaderProgram, fragmentShader);
93
+ this.gl.linkProgram(shaderProgram);
94
+ this.gl.useProgram(shaderProgram);
95
+
96
+ // look up where vertex data needs to go
97
+ this.positionLocation = this.gl.getAttribLocation(
98
+ shaderProgram,
99
+ 'a_position'
100
+ );
101
+ this.texcoordLocation = this.gl.getAttribLocation(
102
+ shaderProgram,
103
+ 'a_texCoord'
104
+ );
105
+ // Create a buffer to put three 2d clip space points in
106
+ this.positionBuffer = this.gl.createBuffer();
107
+ // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
108
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
109
+
110
+ // Turn on the position attribute
111
+ this.gl.enableVertexAttribArray(this.positionLocation);
112
+ // Create a texture.
113
+ const texture = this.gl.createTexture();
114
+ this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
115
+ // Set the parameters so we can render any size image.
116
+ this.gl.texParameteri(
117
+ this.gl.TEXTURE_2D,
118
+ this.gl.TEXTURE_WRAP_S,
119
+ this.gl.CLAMP_TO_EDGE
120
+ );
121
+ this.gl.texParameteri(
122
+ this.gl.TEXTURE_2D,
123
+ this.gl.TEXTURE_WRAP_T,
124
+ this.gl.CLAMP_TO_EDGE
125
+ );
126
+ this.gl.texParameteri(
127
+ this.gl.TEXTURE_2D,
128
+ this.gl.TEXTURE_MIN_FILTER,
129
+ this.gl.NEAREST
130
+ );
131
+ this.gl.texParameteri(
132
+ this.gl.TEXTURE_2D,
133
+ this.gl.TEXTURE_MAG_FILTER,
134
+ this.gl.NEAREST
135
+ );
136
+
137
+ this.texcoordBuffer = this.gl.createBuffer();
138
+ // lookup uniforms
139
+ this.resolutionLocation = this.gl.getUniformLocation(
140
+ shaderProgram,
141
+ 'u_resolution'
142
+ );
143
+ this.offsetLocation = this.gl.getUniformLocation(
144
+ shaderProgram,
145
+ 'u_offset'
146
+ );
147
+
148
+ session.requestReferenceSpace('local').then((refSpace) => {
149
+ this.xrRefSpace = refSpace;
150
+ this.xrSession.requestAnimationFrame(
151
+ (time: DOMHighResTimeStamp, frame: XRFrame) =>
152
+ this.onXrFrame(time, frame)
153
+ );
154
+ });
155
+
156
+ this.onSessionStarted.dispatchEvent(new Event('xrSessionStarted'));
157
+ }
158
+
159
+ onXrFrame(time: DOMHighResTimeStamp, frame: XRFrame) {
160
+ const pose = frame.getViewerPose(this.xrRefSpace);
161
+ if (pose) {
162
+ const matrix = pose.transform.matrix;
163
+ const mat = [];
164
+ for (let i = 0; i < 16; i++) {
165
+ mat[i] = new Float32Array([matrix[i]])[0];
166
+ }
167
+
168
+ // prettier-ignore
169
+ this.webRtcController.streamMessageController.toStreamerHandlers.get('XRHMDTransform')([
170
+ mat[0], mat[4], mat[8], mat[12],
171
+ mat[1], mat[5], mat[9], mat[13],
172
+ mat[2], mat[6], mat[10], mat[14],
173
+ mat[3], mat[7], mat[11], mat[15]
174
+ ]);
175
+
176
+ const glLayer = this.xrSession.renderState.baseLayer;
177
+ // If we do have a valid pose, bind the WebGL layer's framebuffer,
178
+ // which is where any content to be displayed on the XRDevice must be
179
+ // rendered.
180
+ this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, glLayer.framebuffer);
181
+
182
+ // Upload the image into the texture. WebGL knows how to extract the current frame from the video element
183
+ this.gl.texImage2D(
184
+ this.gl.TEXTURE_2D,
185
+ 0,
186
+ this.gl.RGBA,
187
+ this.gl.RGBA,
188
+ this.gl.UNSIGNED_BYTE,
189
+ this.webRtcController.videoPlayer.getVideoElement()
190
+ );
191
+ this.render(this.webRtcController.videoPlayer.getVideoElement());
192
+ }
193
+
194
+ if (this.webRtcController.config.isFlagEnabled(Flags.XRControllerInput)) {
195
+ this.xrSession.inputSources.forEach(
196
+ (source: XRInputSource, index: number, array: XRInputSource[]) => {
197
+ this.xrGamepadController.updateStatus(
198
+ source,
199
+ frame,
200
+ this.xrRefSpace
201
+ );
202
+ },
203
+ this
204
+ );
205
+ }
206
+
207
+ this.xrSession.requestAnimationFrame(
208
+ (time: DOMHighResTimeStamp, frame: XRFrame) =>
209
+ this.onXrFrame(time, frame)
210
+ );
211
+
212
+ this.onFrame.dispatchEvent(new XrFrameEvent({
213
+ time,
214
+ frame
215
+ }));
216
+ }
217
+
218
+ private render(videoElement: HTMLVideoElement) {
219
+ if (!this.gl) {
220
+ return;
221
+ }
222
+
223
+ const glLayer = this.xrSession.renderState.baseLayer;
224
+ this.gl.viewport(
225
+ 0,
226
+ 0,
227
+ glLayer.framebufferWidth,
228
+ glLayer.framebufferHeight
229
+ );
230
+ this.gl.uniform4f(this.offsetLocation, 1.0, 1.0, 0.0, 0.0);
231
+
232
+ // Set rectangle
233
+ // prettier-ignore
234
+ this.gl.bufferData(
235
+ this.gl.ARRAY_BUFFER,
236
+ new Float32Array([
237
+ 0, 0,
238
+ videoElement.videoWidth, 0,
239
+ 0, videoElement.videoHeight,
240
+ 0, videoElement.videoHeight,
241
+ videoElement.videoWidth, 0,
242
+ videoElement.videoWidth, videoElement.videoHeight
243
+ ]),
244
+ this.gl.STATIC_DRAW
245
+ );
246
+
247
+ // Provide texture coordinates for the rectangle
248
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texcoordBuffer);
249
+ this.gl.bufferData(
250
+ this.gl.ARRAY_BUFFER,
251
+ new Float32Array([
252
+ 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0
253
+ ]),
254
+ this.gl.STATIC_DRAW
255
+ );
256
+
257
+ let size; // components per iteration
258
+ let type; // the data type
259
+ let normalize; // normalize the data
260
+ let stride; // 0 = move forward size * sizeof(type) each iteration to get the next position
261
+ let offset; // start position of the buffer
262
+
263
+ // Bind the position buffer.
264
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
265
+ // Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
266
+ size = 2; // 2 components per iteration
267
+ type = this.gl.FLOAT; // the data is 32bit floats
268
+ normalize = false; // don't normalize the data
269
+ stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
270
+ offset = 0; // start at the beginning of the buffer
271
+ this.gl.vertexAttribPointer(
272
+ this.positionLocation,
273
+ size,
274
+ type,
275
+ normalize,
276
+ stride,
277
+ offset
278
+ );
279
+ // Turn on the texcoord attribute
280
+ this.gl.enableVertexAttribArray(this.texcoordLocation);
281
+ // bind the texcoord buffer.
282
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texcoordBuffer);
283
+ // Tell the texcoord attribute how to get data out of texcoordBuffer (ARRAY_BUFFER)
284
+ size = 2; // 2 components per iteration
285
+ type = this.gl.FLOAT; // the data is 32bit floats
286
+ normalize = false; // don't normalize the data
287
+ stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
288
+ offset = 0; // start at the beginning of the buffer
289
+ this.gl.vertexAttribPointer(
290
+ this.texcoordLocation,
291
+ size,
292
+ type,
293
+ normalize,
294
+ stride,
295
+ offset
296
+ );
297
+ // set the resolution
298
+ this.gl.uniform2f(
299
+ this.resolutionLocation,
300
+ videoElement.videoWidth,
301
+ videoElement.videoHeight
302
+ );
303
+ // draw the rectangle.
304
+ const primitiveType = this.gl.TRIANGLES;
305
+ const count = 6;
306
+ offset = 0;
307
+ this.gl.drawArrays(primitiveType, offset, count);
308
+ }
309
+
310
+ static isSessionSupported(mode: XRSessionMode): Promise<boolean> {
311
+ if (navigator.xr) {
312
+ return navigator.xr.isSessionSupported(mode);
313
+ } else {
314
+ return new Promise<boolean>(() => {
315
+ return false;
316
+ });
317
+ }
318
+ }
319
+ }
@@ -0,0 +1,124 @@
1
+ export class MockMediaStreamImpl implements MediaStream {
2
+ active: boolean;
3
+ id: string;
4
+
5
+ constructor(data?: MediaStream | MediaStreamTrack[]) {
6
+ //
7
+ }
8
+
9
+ onaddtrack: ((this: MediaStream, ev: MediaStreamTrackEvent) => any) | null;
10
+ onremovetrack: ((this: MediaStream, ev: MediaStreamTrackEvent) => any) | null;
11
+ addTrack(track: MediaStreamTrack): void {
12
+ throw new Error("Method not implemented.");
13
+ }
14
+ clone(): MediaStream {
15
+ throw new Error("Method not implemented.");
16
+ }
17
+ getAudioTracks(): MediaStreamTrack[] {
18
+ throw new Error("Method not implemented.");
19
+ }
20
+ getTrackById(trackId: string): MediaStreamTrack | null {
21
+ throw new Error("Method not implemented.");
22
+ }
23
+ getTracks(): MediaStreamTrack[] {
24
+ throw new Error("Method not implemented.");
25
+ }
26
+ getVideoTracks(): MediaStreamTrack[] {
27
+ throw new Error("Method not implemented.");
28
+ }
29
+ removeTrack(track: MediaStreamTrack): void {
30
+ throw new Error("Method not implemented.");
31
+ }
32
+ addEventListener<K extends keyof MediaStreamEventMap>(type: K, listener: (this: MediaStream, ev: MediaStreamEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void;
33
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void;
34
+ addEventListener(type: unknown, listener: unknown, options?: unknown): void {
35
+ throw new Error("Method not implemented.");
36
+ }
37
+ removeEventListener<K extends keyof MediaStreamEventMap>(type: K, listener: (this: MediaStream, ev: MediaStreamEventMap[K]) => any, options?: boolean | EventListenerOptions | undefined): void;
38
+ removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions | undefined): void;
39
+ removeEventListener(type: unknown, listener: unknown, options?: unknown): void {
40
+ throw new Error("Method not implemented.");
41
+ }
42
+ dispatchEvent(event: Event): boolean {
43
+ throw new Error("Method not implemented.");
44
+ }
45
+
46
+ }
47
+
48
+ export class MockMediaStreamTrackImpl implements MediaStreamTrack {
49
+ contentHint: string;
50
+ enabled: boolean;
51
+ id: string;
52
+ kind: string;
53
+ label: string;
54
+ muted: boolean;
55
+ readyState: MediaStreamTrackState;
56
+
57
+ constructor() {
58
+ this.kind = 'video';
59
+ this.readyState = 'live';
60
+ }
61
+
62
+ onended: ((this: MediaStreamTrack, ev: Event) => any) | null;
63
+ onmute: ((this: MediaStreamTrack, ev: Event) => any) | null;
64
+ onunmute: ((this: MediaStreamTrack, ev: Event) => any) | null;
65
+ applyConstraints(constraints?: MediaTrackConstraints | undefined): Promise<void> {
66
+ throw new Error("Method not implemented.");
67
+ }
68
+ clone(): MediaStreamTrack {
69
+ throw new Error("Method not implemented.");
70
+ }
71
+ getCapabilities(): MediaTrackCapabilities {
72
+ throw new Error("Method not implemented.");
73
+ }
74
+ getConstraints(): MediaTrackConstraints {
75
+ throw new Error("Method not implemented.");
76
+ }
77
+ getSettings(): MediaTrackSettings {
78
+ throw new Error("Method not implemented.");
79
+ }
80
+ stop(): void {
81
+ throw new Error("Method not implemented.");
82
+ }
83
+ addEventListener<K extends keyof MediaStreamTrackEventMap>(type: K, listener: (this: MediaStreamTrack, ev: MediaStreamTrackEventMap[K]) => any, options?: boolean | AddEventListenerOptions | undefined): void;
84
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions | undefined): void;
85
+ addEventListener(type: unknown, listener: unknown, options?: unknown): void {
86
+ throw new Error("Method not implemented.");
87
+ }
88
+ removeEventListener<K extends keyof MediaStreamTrackEventMap>(type: K, listener: (this: MediaStreamTrack, ev: MediaStreamTrackEventMap[K]) => any, options?: boolean | EventListenerOptions | undefined): void;
89
+ removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions | undefined): void;
90
+ removeEventListener(type: unknown, listener: unknown, options?: unknown): void {
91
+ throw new Error("Method not implemented.");
92
+ }
93
+ dispatchEvent(event: Event): boolean {
94
+ throw new Error("Method not implemented.");
95
+ }
96
+ }
97
+
98
+ const mockHTMLMediaElementPlay = (ableToPlay: boolean) => {
99
+ if (ableToPlay) {
100
+ return Promise.resolve();
101
+ }
102
+ return Promise.reject("mock cancel");
103
+ };
104
+
105
+ const originalMediaStream = global.MediaStream;
106
+ const originalMediaStreamTrack = global.MediaStreamTrack;
107
+ export const mockMediaStream = () => {
108
+ global.MediaStream = MockMediaStreamImpl;
109
+ global.MediaStreamTrack = MockMediaStreamTrackImpl;
110
+ }
111
+
112
+ export const unmockMediaStream = () => {
113
+ global.MediaStream = originalMediaStream;
114
+ global.MediaStreamTrack = originalMediaStreamTrack;
115
+ }
116
+
117
+ export const mockHTMLMediaElement = (options: { ableToPlay: boolean, readyState?: number }) => {
118
+ const { ableToPlay, readyState } = options;
119
+ jest.spyOn(HTMLMediaElement.prototype, 'play').mockReturnValue(mockHTMLMediaElementPlay(ableToPlay));
120
+ if (readyState !== undefined) {
121
+ jest.spyOn(HTMLMediaElement.prototype, 'readyState', 'get').mockReturnValue(readyState);
122
+ }
123
+ }
124
+