@yang__yj/pixelstreaming-core 1.0.0 → 1.0.1

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 (237) 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/coverage/clover.xml +3480 -0
  7. package/coverage/coverage-final.json +62 -0
  8. package/coverage/lcov-report/base.css +224 -0
  9. package/coverage/lcov-report/block-navigation.js +87 -0
  10. package/coverage/lcov-report/favicon.png +0 -0
  11. package/coverage/lcov-report/index.html +356 -0
  12. package/coverage/lcov-report/prettify.css +1 -0
  13. package/coverage/lcov-report/prettify.js +2 -0
  14. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  15. package/coverage/lcov-report/sorter.js +196 -0
  16. package/coverage/lcov-report/src/AFK/AFKController.ts.html +559 -0
  17. package/coverage/lcov-report/src/AFK/index.html +116 -0
  18. package/coverage/lcov-report/src/Config/Config.ts.html +2764 -0
  19. package/coverage/lcov-report/src/Config/SettingBase.ts.html +280 -0
  20. package/coverage/lcov-report/src/Config/SettingFlag.ts.html +382 -0
  21. package/coverage/lcov-report/src/Config/SettingNumber.ts.html +418 -0
  22. package/coverage/lcov-report/src/Config/SettingOption.ts.html +424 -0
  23. package/coverage/lcov-report/src/Config/SettingText.ts.html +331 -0
  24. package/coverage/lcov-report/src/Config/index.html +191 -0
  25. package/coverage/lcov-report/src/DataChannel/DataChannelController.ts.html +499 -0
  26. package/coverage/lcov-report/src/DataChannel/DataChannelSender.ts.html +262 -0
  27. package/coverage/lcov-report/src/DataChannel/InitialSettings.ts.html +268 -0
  28. package/coverage/lcov-report/src/DataChannel/LatencyTestResults.ts.html +313 -0
  29. package/coverage/lcov-report/src/DataChannel/index.html +161 -0
  30. package/coverage/lcov-report/src/FreezeFrame/FreezeFrame.ts.html +427 -0
  31. package/coverage/lcov-report/src/FreezeFrame/FreezeFrameController.ts.html +427 -0
  32. package/coverage/lcov-report/src/FreezeFrame/index.html +131 -0
  33. package/coverage/lcov-report/src/Inputs/FakeTouchController.ts.html +682 -0
  34. package/coverage/lcov-report/src/Inputs/GamepadController.ts.html +985 -0
  35. package/coverage/lcov-report/src/Inputs/HoveringMouseEvents.ts.html +688 -0
  36. package/coverage/lcov-report/src/Inputs/InputClassesFactory.ts.html +505 -0
  37. package/coverage/lcov-report/src/Inputs/KeyboardController.ts.html +1048 -0
  38. package/coverage/lcov-report/src/Inputs/LockedMouseEvents.ts.html +946 -0
  39. package/coverage/lcov-report/src/Inputs/MouseButtons.ts.html +160 -0
  40. package/coverage/lcov-report/src/Inputs/MouseController.ts.html +1171 -0
  41. package/coverage/lcov-report/src/Inputs/SpecialKeyCodes.ts.html +133 -0
  42. package/coverage/lcov-report/src/Inputs/TouchController.ts.html +712 -0
  43. package/coverage/lcov-report/src/Inputs/XRGamepadController.ts.html +463 -0
  44. package/coverage/lcov-report/src/Inputs/index.html +266 -0
  45. package/coverage/lcov-report/src/Logger/Logger.ts.html +325 -0
  46. package/coverage/lcov-report/src/Logger/index.html +116 -0
  47. package/coverage/lcov-report/src/PeerConnectionController/AggregatedStats.ts.html +1018 -0
  48. package/coverage/lcov-report/src/PeerConnectionController/CandidatePairStats.ts.html +136 -0
  49. package/coverage/lcov-report/src/PeerConnectionController/CandidateStat.ts.html +124 -0
  50. package/coverage/lcov-report/src/PeerConnectionController/DataChannelStats.ts.html +136 -0
  51. package/coverage/lcov-report/src/PeerConnectionController/InboundRTPStats.ts.html +547 -0
  52. package/coverage/lcov-report/src/PeerConnectionController/OutBoundRTPStats.ts.html +163 -0
  53. package/coverage/lcov-report/src/PeerConnectionController/PeerConnectionController.ts.html +1795 -0
  54. package/coverage/lcov-report/src/PeerConnectionController/SessionStats.ts.html +115 -0
  55. package/coverage/lcov-report/src/PeerConnectionController/StreamStats.ts.html +118 -0
  56. package/coverage/lcov-report/src/PeerConnectionController/index.html +236 -0
  57. package/coverage/lcov-report/src/PixelStreaming/PixelStreaming.ts.html +2269 -0
  58. package/coverage/lcov-report/src/PixelStreaming/index.html +116 -0
  59. package/coverage/lcov-report/src/UI/OnScreenKeyboard.ts.html +376 -0
  60. package/coverage/lcov-report/src/UI/index.html +116 -0
  61. package/coverage/lcov-report/src/UeInstanceMessage/ResponseController.ts.html +226 -0
  62. package/coverage/lcov-report/src/UeInstanceMessage/SendDescriptorController.ts.html +346 -0
  63. package/coverage/lcov-report/src/UeInstanceMessage/SendMessageController.ts.html +364 -0
  64. package/coverage/lcov-report/src/UeInstanceMessage/StreamMessageController.ts.html +862 -0
  65. package/coverage/lcov-report/src/UeInstanceMessage/ToStreamerMessagesController.ts.html +271 -0
  66. package/coverage/lcov-report/src/UeInstanceMessage/TwoWayMap.ts.html +241 -0
  67. package/coverage/lcov-report/src/UeInstanceMessage/index.html +191 -0
  68. package/coverage/lcov-report/src/Util/CoordinateConverter.ts.html +952 -0
  69. package/coverage/lcov-report/src/Util/EventEmitter.ts.html +1705 -0
  70. package/coverage/lcov-report/src/Util/EventListenerTracker.ts.html +172 -0
  71. package/coverage/lcov-report/src/Util/FileUtil.ts.html +505 -0
  72. package/coverage/lcov-report/src/Util/WebGLUtils.ts.html +232 -0
  73. package/coverage/lcov-report/src/Util/WebXRUtils.ts.html +160 -0
  74. package/coverage/lcov-report/src/Util/index.html +191 -0
  75. package/coverage/lcov-report/src/VideoPlayer/StreamController.ts.html +349 -0
  76. package/coverage/lcov-report/src/VideoPlayer/VideoPlayer.ts.html +799 -0
  77. package/coverage/lcov-report/src/VideoPlayer/index.html +131 -0
  78. package/coverage/lcov-report/src/WebRtcPlayer/WebRtcPlayerController.ts.html +6199 -0
  79. package/coverage/lcov-report/src/WebRtcPlayer/index.html +116 -0
  80. package/coverage/lcov-report/src/WebSockets/MessageReceive.ts.html +352 -0
  81. package/coverage/lcov-report/src/WebSockets/MessageSend.ts.html +604 -0
  82. package/coverage/lcov-report/src/WebSockets/SignallingProtocol.ts.html +622 -0
  83. package/coverage/lcov-report/src/WebSockets/WebSocketController.ts.html +844 -0
  84. package/coverage/lcov-report/src/WebSockets/index.html +161 -0
  85. package/coverage/lcov-report/src/WebXR/WebXRController.ts.html +1042 -0
  86. package/coverage/lcov-report/src/WebXR/index.html +116 -0
  87. package/coverage/lcov-report/src/__test__/index.html +161 -0
  88. package/coverage/lcov-report/src/__test__/mockMediaStream.ts.html +457 -0
  89. package/coverage/lcov-report/src/__test__/mockRTCPeerConnection.ts.html +1126 -0
  90. package/coverage/lcov-report/src/__test__/mockRTCRtpReceiver.ts.html +151 -0
  91. package/coverage/lcov-report/src/__test__/mockWebSocket.ts.html +475 -0
  92. package/coverage/lcov-report/src/index.html +116 -0
  93. package/coverage/lcov-report/src/pixelstreamingfrontend.ts.html +232 -0
  94. package/coverage/lcov.info +6458 -0
  95. package/jest.config.js +18 -0
  96. package/package.json +46 -18
  97. package/readme.md +15 -0
  98. package/src/AFK/AFKController.test.ts +162 -0
  99. package/src/AFK/AFKController.ts +158 -0
  100. package/src/Config/Config.test.ts +222 -0
  101. package/src/Config/Config.ts +909 -0
  102. package/src/Config/SettingBase.ts +65 -0
  103. package/src/Config/SettingFlag.ts +99 -0
  104. package/src/Config/SettingNumber.ts +111 -0
  105. package/src/Config/SettingOption.ts +124 -0
  106. package/src/Config/SettingText.ts +82 -0
  107. package/src/DataChannel/DataChannelController.ts +138 -0
  108. package/src/DataChannel/DataChannelLatencyTestController.ts +129 -0
  109. package/src/DataChannel/DataChannelLatencyTestResults.ts +67 -0
  110. package/src/DataChannel/DataChannelSender.ts +59 -0
  111. package/src/DataChannel/InitialSettings.ts +61 -0
  112. package/src/DataChannel/LatencyTestResults.ts +76 -0
  113. package/src/FreezeFrame/FreezeFrame.ts +114 -0
  114. package/src/FreezeFrame/FreezeFrameController.ts +114 -0
  115. package/src/Inputs/FakeTouchController.ts +199 -0
  116. package/src/Inputs/GamepadController.ts +300 -0
  117. package/src/Inputs/GamepadTypes.ts +10 -0
  118. package/src/Inputs/HoveringMouseEvents.ts +192 -0
  119. package/src/Inputs/IMouseEvents.ts +64 -0
  120. package/src/Inputs/ITouchController.ts +29 -0
  121. package/src/Inputs/InputClassesFactory.ts +140 -0
  122. package/src/Inputs/KeyboardController.ts +318 -0
  123. package/src/Inputs/LockedMouseEvents.ts +287 -0
  124. package/src/Inputs/MouseButtons.ts +25 -0
  125. package/src/Inputs/MouseController.ts +362 -0
  126. package/src/Inputs/SpecialKeyCodes.ts +16 -0
  127. package/src/Inputs/TouchController.ts +253 -0
  128. package/src/Inputs/XRGamepadController.ts +126 -0
  129. package/src/Logger/Logger.ts +80 -0
  130. package/src/PeerConnectionController/AggregatedStats.ts +311 -0
  131. package/src/PeerConnectionController/CandidatePairStats.ts +17 -0
  132. package/src/PeerConnectionController/CandidateStat.ts +13 -0
  133. package/src/PeerConnectionController/CodecStats.ts +19 -0
  134. package/src/PeerConnectionController/DataChannelStats.ts +17 -0
  135. package/src/PeerConnectionController/InboundRTPStats.ts +154 -0
  136. package/src/PeerConnectionController/InboundTrackStats.ts +34 -0
  137. package/src/PeerConnectionController/OutBoundRTPStats.ts +26 -0
  138. package/src/PeerConnectionController/PeerConnectionController.ts +563 -0
  139. package/src/PeerConnectionController/SessionStats.ts +10 -0
  140. package/src/PeerConnectionController/StreamStats.ts +11 -0
  141. package/src/PixelStreaming/PixelStreaming.test.ts +624 -0
  142. package/src/PixelStreaming/PixelStreaming.ts +847 -0
  143. package/src/UI/OnScreenKeyboard.ts +97 -0
  144. package/src/UeInstanceMessage/ResponseController.ts +47 -0
  145. package/src/UeInstanceMessage/SendMessageController.ts +154 -0
  146. package/src/UeInstanceMessage/StreamMessageController.ts +233 -0
  147. package/src/UeInstanceMessage/ToStreamerMessagesController.ts +62 -0
  148. package/src/Util/CoordinateConverter.ts +289 -0
  149. package/src/Util/EventEmitter.ts +595 -0
  150. package/src/Util/EventListenerTracker.ts +29 -0
  151. package/src/Util/FileUtil.ts +140 -0
  152. package/src/Util/RTCUtils.ts +41 -0
  153. package/src/Util/WebGLUtils.ts +49 -0
  154. package/src/Util/WebXRUtils.ts +25 -0
  155. package/src/VideoPlayer/StreamController.ts +89 -0
  156. package/src/VideoPlayer/VideoPlayer.ts +246 -0
  157. package/src/WebRtcPlayer/WebRtcPlayerController.ts +2144 -0
  158. package/src/WebSockets/MessageReceive.ts +89 -0
  159. package/src/WebSockets/MessageSend.ts +185 -0
  160. package/src/WebSockets/SignallingProtocol.ts +180 -0
  161. package/src/WebSockets/WebSocketController.ts +267 -0
  162. package/src/WebXR/WebXRController.ts +319 -0
  163. package/src/__test__/mockMediaStream.ts +124 -0
  164. package/src/__test__/mockRTCPeerConnection.ts +347 -0
  165. package/src/__test__/mockRTCRtpReceiver.ts +22 -0
  166. package/src/__test__/mockWebSocket.ts +130 -0
  167. package/src/pixelstreamingfrontend.ts +50 -0
  168. package/tsconfig.jest.json +8 -0
  169. package/tsconfig.json +24 -0
  170. package/webpack.common.js +35 -0
  171. package/webpack.dev.js +35 -0
  172. package/webpack.prod.js +36 -0
  173. package/yang__yj-pixelstreaming-core-1.0.1.tgz +0 -0
  174. /package/{library/dist → dist}/lib-pixelstreamingfrontend.esm.js +0 -0
  175. /package/{library/dist → dist}/lib-pixelstreamingfrontend.js +0 -0
  176. /package/{library/types → types}/AFK/AFKController.d.ts +0 -0
  177. /package/{library/types → types}/Config/Config.d.ts +0 -0
  178. /package/{library/types → types}/Config/SettingBase.d.ts +0 -0
  179. /package/{library/types → types}/Config/SettingFlag.d.ts +0 -0
  180. /package/{library/types → types}/Config/SettingNumber.d.ts +0 -0
  181. /package/{library/types → types}/Config/SettingOption.d.ts +0 -0
  182. /package/{library/types → types}/Config/SettingText.d.ts +0 -0
  183. /package/{library/types → types}/DataChannel/DataChannelController.d.ts +0 -0
  184. /package/{library/types → types}/DataChannel/DataChannelSender.d.ts +0 -0
  185. /package/{library/types → types}/DataChannel/InitialSettings.d.ts +0 -0
  186. /package/{library/types → types}/DataChannel/LatencyTestResults.d.ts +0 -0
  187. /package/{library/types → types}/FreezeFrame/FreezeFrame.d.ts +0 -0
  188. /package/{library/types → types}/FreezeFrame/FreezeFrameController.d.ts +0 -0
  189. /package/{library/types → types}/Inputs/FakeTouchController.d.ts +0 -0
  190. /package/{library/types → types}/Inputs/GamepadController.d.ts +0 -0
  191. /package/{library/types → types}/Inputs/GamepadTypes.d.ts +0 -0
  192. /package/{library/types → types}/Inputs/HoveringMouseEvents.d.ts +0 -0
  193. /package/{library/types → types}/Inputs/IMouseEvents.d.ts +0 -0
  194. /package/{library/types → types}/Inputs/ITouchController.d.ts +0 -0
  195. /package/{library/types → types}/Inputs/InputClassesFactory.d.ts +0 -0
  196. /package/{library/types → types}/Inputs/KeyboardController.d.ts +0 -0
  197. /package/{library/types → types}/Inputs/LockedMouseEvents.d.ts +0 -0
  198. /package/{library/types → types}/Inputs/MouseButtons.d.ts +0 -0
  199. /package/{library/types → types}/Inputs/MouseController.d.ts +0 -0
  200. /package/{library/types → types}/Inputs/SpecialKeyCodes.d.ts +0 -0
  201. /package/{library/types → types}/Inputs/TouchController.d.ts +0 -0
  202. /package/{library/types → types}/Inputs/XRGamepadController.d.ts +0 -0
  203. /package/{library/types → types}/Logger/Logger.d.ts +0 -0
  204. /package/{library/types → types}/PeerConnectionController/AggregatedStats.d.ts +0 -0
  205. /package/{library/types → types}/PeerConnectionController/CandidatePairStats.d.ts +0 -0
  206. /package/{library/types → types}/PeerConnectionController/CandidateStat.d.ts +0 -0
  207. /package/{library/types → types}/PeerConnectionController/CodecStats.d.ts +0 -0
  208. /package/{library/types → types}/PeerConnectionController/DataChannelStats.d.ts +0 -0
  209. /package/{library/types → types}/PeerConnectionController/InboundRTPStats.d.ts +0 -0
  210. /package/{library/types → types}/PeerConnectionController/InboundTrackStats.d.ts +0 -0
  211. /package/{library/types → types}/PeerConnectionController/OutBoundRTPStats.d.ts +0 -0
  212. /package/{library/types → types}/PeerConnectionController/PeerConnectionController.d.ts +0 -0
  213. /package/{library/types → types}/PeerConnectionController/SessionStats.d.ts +0 -0
  214. /package/{library/types → types}/PeerConnectionController/StreamStats.d.ts +0 -0
  215. /package/{library/types → types}/PixelStreaming/PixelStreaming.d.ts +0 -0
  216. /package/{library/types → types}/UI/OnScreenKeyboard.d.ts +0 -0
  217. /package/{library/types → types}/UeInstanceMessage/ResponseController.d.ts +0 -0
  218. /package/{library/types → types}/UeInstanceMessage/SendDescriptorController.d.ts +0 -0
  219. /package/{library/types → types}/UeInstanceMessage/SendMessageController.d.ts +0 -0
  220. /package/{library/types → types}/UeInstanceMessage/StreamMessageController.d.ts +0 -0
  221. /package/{library/types → types}/UeInstanceMessage/ToStreamerMessagesController.d.ts +0 -0
  222. /package/{library/types → types}/UeInstanceMessage/TwoWayMap.d.ts +0 -0
  223. /package/{library/types → types}/Util/CoordinateConverter.d.ts +0 -0
  224. /package/{library/types → types}/Util/EventEmitter.d.ts +0 -0
  225. /package/{library/types → types}/Util/EventListenerTracker.d.ts +0 -0
  226. /package/{library/types → types}/Util/FileUtil.d.ts +0 -0
  227. /package/{library/types → types}/Util/WebGLUtils.d.ts +0 -0
  228. /package/{library/types → types}/Util/WebXRUtils.d.ts +0 -0
  229. /package/{library/types → types}/VideoPlayer/StreamController.d.ts +0 -0
  230. /package/{library/types → types}/VideoPlayer/VideoPlayer.d.ts +0 -0
  231. /package/{library/types → types}/WebRtcPlayer/WebRtcPlayerController.d.ts +0 -0
  232. /package/{library/types → types}/WebSockets/MessageReceive.d.ts +0 -0
  233. /package/{library/types → types}/WebSockets/MessageSend.d.ts +0 -0
  234. /package/{library/types → types}/WebSockets/SignallingProtocol.d.ts +0 -0
  235. /package/{library/types → types}/WebSockets/WebSocketController.d.ts +0 -0
  236. /package/{library/types → types}/WebXR/WebXRController.d.ts +0 -0
  237. /package/{library/types → types}/pixelstreamingfrontend.d.ts +0 -0
@@ -0,0 +1,2144 @@
1
+ // Copyright Epic Games, Inc. All Rights Reserved.
2
+
3
+ import { ElMessage, ElMessageBox } from 'element-plus'
4
+ import { useRoute, useRouter } from "vue-router";
5
+ import { WebSocketController } from '../WebSockets/WebSocketController';
6
+ import { StreamController } from '../VideoPlayer/StreamController';
7
+ import {
8
+ MessageAnswer,
9
+ MessageOffer,
10
+ MessageConfig,
11
+ MessageStreamerList
12
+ } from '../WebSockets/MessageReceive';
13
+ import { FreezeFrameController } from '../FreezeFrame/FreezeFrameController';
14
+ import { AFKController } from '../AFK/AFKController';
15
+ import { DataChannelController } from '../DataChannel/DataChannelController';
16
+ import { PeerConnectionController } from '../PeerConnectionController/PeerConnectionController';
17
+ import { KeyboardController } from '../Inputs/KeyboardController';
18
+ import { AggregatedStats } from '../PeerConnectionController/AggregatedStats';
19
+ import {
20
+ Config,
21
+ Flags,
22
+ ControlSchemeType,
23
+ TextParameters,
24
+ OptionParameters,
25
+ NumericParameters
26
+ } from '../Config/Config';
27
+ import {
28
+ EncoderSettings,
29
+ InitialSettings,
30
+ WebRTCSettings
31
+ } from '../DataChannel/InitialSettings';
32
+ import { LatencyTestResults } from '../DataChannel/LatencyTestResults';
33
+ import { Logger } from '../Logger/Logger';
34
+ import { FileTemplate, FileUtil } from '../Util/FileUtil';
35
+ import { InputClassesFactory } from '../Inputs/InputClassesFactory';
36
+ import { VideoPlayer } from '../VideoPlayer/VideoPlayer';
37
+ import {
38
+ StreamMessageController,
39
+ MessageDirection
40
+ } from '../UeInstanceMessage/StreamMessageController';
41
+ import { ResponseController } from '../UeInstanceMessage/ResponseController';
42
+ import * as MessageReceive from '../WebSockets/MessageReceive';
43
+ import { MessageOnScreenKeyboard } from '../WebSockets/MessageReceive';
44
+ import { SendMessageController } from '../UeInstanceMessage/SendMessageController';
45
+ import { ToStreamerMessagesController } from '../UeInstanceMessage/ToStreamerMessagesController';
46
+ import { MouseController } from '../Inputs/MouseController';
47
+ import { GamePadController } from '../Inputs/GamepadController';
48
+ import { DataChannelSender } from '../DataChannel/DataChannelSender';
49
+ import {
50
+ CoordinateConverter,
51
+ UnquantizedDenormalizedUnsignedCoord
52
+ } from '../Util/CoordinateConverter';
53
+ import { PixelStreaming } from '../PixelStreaming/PixelStreaming';
54
+ import { ITouchController } from '../Inputs/ITouchController';
55
+ import {
56
+ DataChannelCloseEvent,
57
+ DataChannelErrorEvent,
58
+ DataChannelOpenEvent,
59
+ HideFreezeFrameEvent,
60
+ LoadFreezeFrameEvent,
61
+ PlayStreamErrorEvent,
62
+ PlayStreamEvent,
63
+ PlayStreamRejectedEvent,
64
+ StreamerListMessageEvent
65
+ } from '../Util/EventEmitter';
66
+ import {
67
+ DataChannelLatencyTestRequest,
68
+ DataChannelLatencyTestResponse
69
+ } from "../DataChannel/DataChannelLatencyTestResults";
70
+ /**
71
+ * Entry point for the WebRTC Player
72
+ */
73
+ export class WebRtcPlayerController {
74
+ config: Config;
75
+ responseController: ResponseController;
76
+ sdpConstraints: RTCOfferOptions;
77
+ webSocketController: WebSocketController;
78
+ // The primary data channel. This is bidirectional when p2p and send only when using an SFU
79
+ sendrecvDataChannelController: DataChannelController;
80
+ // A recv only data channel required when using an SFU
81
+ recvDataChannelController: DataChannelController;
82
+ dataChannelSender: DataChannelSender;
83
+ datachannelOptions: RTCDataChannelInit;
84
+ videoPlayer: VideoPlayer;
85
+ streamController: StreamController;
86
+ peerConnectionController: PeerConnectionController;
87
+ inputClassesFactory: InputClassesFactory;
88
+ freezeFrameController: FreezeFrameController;
89
+ shouldShowPlayOverlay = true;
90
+ afkController: AFKController;
91
+ videoElementParentClientRect: DOMRect;
92
+ latencyStartTime: number;
93
+ pixelStreaming: PixelStreaming;
94
+ streamMessageController: StreamMessageController;
95
+ sendMessageController: SendMessageController;
96
+ toStreamerMessagesController: ToStreamerMessagesController;
97
+ keyboardController: KeyboardController;
98
+ mouseController: MouseController;
99
+ touchController: ITouchController;
100
+ gamePadController: GamePadController;
101
+ coordinateConverter: CoordinateConverter;
102
+ isUsingSFU: boolean;
103
+ isQualityController: boolean;
104
+ statsTimerHandle: number;
105
+ file: FileTemplate;
106
+ preferredCodec: string;
107
+ peerConfig: RTCConfiguration;
108
+ videoAvgQp: number;
109
+ locallyClosed: boolean;
110
+ shouldReconnect: boolean;
111
+ isReconnecting: boolean;
112
+ reconnectAttempt: number;
113
+ disconnectMessage: string;
114
+ subscribedStream: string;
115
+ signallingUrlBuilder: () => string;
116
+ autoJoinTimer: ReturnType<typeof setTimeout> = undefined;
117
+
118
+ /**
119
+ *
120
+ * @param config - the frontend config object
121
+ * @param pixelStreaming - the PixelStreaming object
122
+ */
123
+ constructor(config: Config, pixelStreaming: PixelStreaming) {
124
+ this.config = config;
125
+ this.pixelStreaming = pixelStreaming;
126
+ this.responseController = new ResponseController();
127
+ this.file = new FileTemplate();
128
+
129
+ this.sdpConstraints = {
130
+ offerToReceiveAudio: true,
131
+ offerToReceiveVideo: true
132
+ };
133
+
134
+ // set up the afk logic class and connect up its method for closing the signaling server
135
+ this.afkController = new AFKController(
136
+ this.config,
137
+ this.pixelStreaming,
138
+ this.onAfkTriggered.bind(this)
139
+ );
140
+ this.afkController.onAFKTimedOutCallback = () => {
141
+ this.closeSignalingServer('You have been disconnected due to inactivity');
142
+ };
143
+
144
+ this.freezeFrameController = new FreezeFrameController(
145
+ this.pixelStreaming.videoElementParent
146
+ );
147
+
148
+ this.videoPlayer = new VideoPlayer(
149
+ this.pixelStreaming.videoElementParent,
150
+ this.config
151
+ );
152
+ this.videoPlayer.onVideoInitialized = () =>
153
+ this.handleVideoInitialized();
154
+
155
+ // When in match viewport resolution mode, when the browser viewport is resized we send a resize command back to UE.
156
+ this.videoPlayer.onMatchViewportResolutionCallback = (
157
+ width: number,
158
+ height: number
159
+ ) => {
160
+ const descriptor = {
161
+ 'Resolution.Width': width,
162
+ 'Resolution.Height': height
163
+ };
164
+
165
+ this.streamMessageController.toStreamerHandlers.get(
166
+ 'Command'
167
+ )([JSON.stringify(descriptor)]);
168
+ };
169
+
170
+ // Every time video player is resized in browser we need to reinitialize the mouse coordinate conversion and freeze frame sizing logic.
171
+ this.videoPlayer.onResizePlayerCallback = () => {
172
+ this.setUpMouseAndFreezeFrame();
173
+ };
174
+
175
+ this.streamController = new StreamController(this.videoPlayer);
176
+
177
+ this.coordinateConverter = new CoordinateConverter(this.videoPlayer);
178
+
179
+ this.sendrecvDataChannelController = new DataChannelController();
180
+ this.recvDataChannelController = new DataChannelController();
181
+ this.registerDataChannelEventEmitters(
182
+ this.sendrecvDataChannelController
183
+ );
184
+ this.registerDataChannelEventEmitters(this.recvDataChannelController);
185
+ this.dataChannelSender = new DataChannelSender(
186
+ this.sendrecvDataChannelController
187
+ );
188
+ this.dataChannelSender.resetAfkWarningTimerOnDataSend = () =>
189
+ this.afkController.resetAfkWarningTimer();
190
+
191
+ this.streamMessageController = new StreamMessageController();
192
+
193
+ // 设置websocket方法
194
+ this.webSocketController = new WebSocketController();
195
+
196
+ this.webSocketController.onConfig = (
197
+ messageConfig: MessageReceive.MessageConfig
198
+ ) => this.handleOnConfigMessage(messageConfig);
199
+
200
+ this.webSocketController.onStreamerList = (
201
+ messageList: MessageReceive.MessageStreamerList
202
+ ) => this.handleStreamerListMessage(messageList);
203
+
204
+ this.webSocketController.onPlayerCount = (playerCount: MessageReceive.MessagePlayerCount) => {
205
+ this.pixelStreaming._onPlayerCount(playerCount.count);
206
+ };
207
+
208
+ this.webSocketController.onOpen.addEventListener('open', () => {
209
+ const BrowserSendsOffer = this.config.isFlagEnabled(
210
+ Flags.BrowserSendOffer
211
+ );
212
+ if (!BrowserSendsOffer) {
213
+ // console.log(this.config.useUrlParams, '=====');
214
+
215
+ // 发送当前连接 所有像素流 TODO:无法判断是固定的什么项目的像素流
216
+ // this.webSocketController.requestStreamerList();
217
+ // this.webSocketController.requestStreamerObject(window.streamerName());
218
+ this.webSocketController.requestStreamerObject(sessionStorage.getItem('streamerName'));
219
+
220
+ // this.webSocketController.onStreamerList = (
221
+ // messageList: MessageReceive.MessageStreamerList
222
+ // ) => {
223
+ // }
224
+ }
225
+ });
226
+
227
+ this.webSocketController.onClose.addEventListener('close', (event: CustomEvent) => {
228
+ // when we refresh the page during a stream we get the going away code.
229
+ // in that case we don't want to reconnect since we're navigating away.
230
+ // https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code
231
+ // lists all the codes.
232
+ const CODE_GOING_AWAY = 1001;
233
+
234
+ const willTryReconnect = this.shouldReconnect
235
+ && event.detail.code != CODE_GOING_AWAY
236
+ && this.config.getNumericSettingValue(NumericParameters.MaxReconnectAttempts) > 0
237
+
238
+ const disconnectMessage = this.disconnectMessage ? this.disconnectMessage : event.detail.reason;
239
+ this.pixelStreaming._onDisconnect(disconnectMessage, !willTryReconnect && !this.isReconnecting);
240
+
241
+ this.afkController.stopAfkWarningTimer();
242
+
243
+ // stop sending stats on interval if we have closed our connection
244
+ if (this.statsTimerHandle && this.statsTimerHandle !== undefined) {
245
+ window.clearInterval(this.statsTimerHandle);
246
+ }
247
+
248
+ // reset the stream quality icon.
249
+ this.setVideoEncoderAvgQP(0);
250
+
251
+ // unregister all input device event handlers on disconnect
252
+ this.setTouchInputEnabled(false);
253
+ this.setMouseInputEnabled(false);
254
+ this.setKeyboardInputEnabled(false);
255
+ this.setGamePadInputEnabled(false);
256
+
257
+ if (willTryReconnect) {
258
+ // need a small delay here to prevent reconnect spamming
259
+ setTimeout(() => {
260
+ this.isReconnecting = true;
261
+ this.reconnectAttempt++;
262
+ this.tryReconnect(event.detail.reason);
263
+ }, 2000);
264
+ }
265
+ });
266
+
267
+ // 在应用中设置webRtc播放器控制器的最后几个方法,以便激活连接
268
+ this.sendMessageController = new SendMessageController(
269
+ this.dataChannelSender,
270
+ this.streamMessageController
271
+ );
272
+ this.toStreamerMessagesController = new ToStreamerMessagesController(
273
+ this.sendMessageController
274
+ );
275
+ this.registerMessageHandlers();
276
+ this.streamMessageController.populateDefaultProtocol();
277
+
278
+ this.inputClassesFactory = new InputClassesFactory(
279
+ this.streamMessageController,
280
+ this.videoPlayer,
281
+ this.coordinateConverter
282
+ );
283
+
284
+ this.isUsingSFU = false;
285
+ this.isQualityController = false;
286
+ this.preferredCodec = '';
287
+ this.shouldReconnect = true;
288
+ this.isReconnecting = false;
289
+ this.reconnectAttempt = 0;
290
+
291
+ this.config._addOnOptionSettingChangedListener(
292
+ OptionParameters.StreamerId,
293
+ (streamerid) => {
294
+ if (streamerid === "") {
295
+ return;
296
+ }
297
+
298
+ // 关闭当前端连接并创建一个新的连接
299
+ this.peerConnectionController.peerConnection.close();
300
+ this.peerConnectionController.createPeerConnection(
301
+ this.peerConfig,
302
+ this.preferredCodec
303
+ );
304
+ this.subscribedStream = streamerid;
305
+ this.webSocketController.sendSubscribe(streamerid);
306
+ }
307
+ );
308
+
309
+ this.setVideoEncoderAvgQP(-1);
310
+
311
+ this.signallingUrlBuilder = () => {
312
+ let signallingServerUrl = this.config.getTextSettingValue(
313
+ TextParameters.SignallingServerUrl
314
+ );
315
+
316
+ // If we are connecting to the SFU add a special url parameter to the url
317
+ if (this.config.isFlagEnabled(Flags.BrowserSendOffer)) {
318
+ signallingServerUrl += '?' + Flags.BrowserSendOffer + '=true';
319
+ }
320
+
321
+ // This code is no longer needed, but is a good example for how subsequent config flags can be appended
322
+ // if (this.config.isFlagEnabled(Flags.BrowserSendOffer)) {
323
+ // signallingServerUrl += (signallingServerUrl.includes('?') ? '&' : '?') + Flags.BrowserSendOffer + '=true';
324
+ // }
325
+
326
+ return signallingServerUrl;
327
+ }
328
+ }
329
+
330
+ /**
331
+ * Make a request to UnquantizedAndDenormalizeUnsigned coordinates
332
+ * @param x x axis coordinate
333
+ * @param y y axis coordinate
334
+ */
335
+ requestUnquantizedAndDenormalizeUnsigned(
336
+ x: number,
337
+ y: number
338
+ ): UnquantizedDenormalizedUnsignedCoord {
339
+ return this.coordinateConverter.unquantizeAndDenormalizeUnsigned(x, y);
340
+ }
341
+
342
+ /**
343
+ * Handles when a message is received
344
+ * @param event - Message Event
345
+ */
346
+ handleOnMessage(event: MessageEvent) {
347
+ const message = new Uint8Array(event.data);
348
+ Logger.Log(Logger.GetStackTrace(), 'Message incoming:' + message, 6);
349
+
350
+ //try {
351
+ const messageType =
352
+ this.streamMessageController.fromStreamerMessages.get(
353
+ message[0]
354
+ );
355
+ this.streamMessageController.fromStreamerHandlers.get(messageType)(
356
+ event.data
357
+ );
358
+ //} catch (e) {
359
+ //Logger.Error(Logger.GetStackTrace(), `Custom data channel message with message type that is unknown to the Pixel Streaming protocol. Does your PixelStreamingProtocol need updating? The message type was: ${message[0]}`);
360
+ //}
361
+ }
362
+
363
+ /**
364
+ * Register message all handlers
365
+ */
366
+ registerMessageHandlers() {
367
+ // From Streamer
368
+ // Message events from the streamer have a data type of ArrayBuffer as we force this type in the DatachannelController
369
+ this.streamMessageController.registerMessageHandler(
370
+ MessageDirection.FromStreamer,
371
+ 'QualityControlOwnership',
372
+ (data: ArrayBuffer) => this.onQualityControlOwnership(data)
373
+ );
374
+ this.streamMessageController.registerMessageHandler(
375
+ MessageDirection.FromStreamer,
376
+ 'Response',
377
+ (data: ArrayBuffer) => this.responseController.onResponse(data)
378
+ );
379
+ this.streamMessageController.registerMessageHandler(
380
+ MessageDirection.FromStreamer,
381
+ 'Command',
382
+ (data: ArrayBuffer) => {
383
+ this.onCommand(data);
384
+ }
385
+ );
386
+ this.streamMessageController.registerMessageHandler(
387
+ MessageDirection.FromStreamer,
388
+ 'FreezeFrame',
389
+ (data: ArrayBuffer) => this.onFreezeFrameMessage(data)
390
+ );
391
+ this.streamMessageController.registerMessageHandler(
392
+ MessageDirection.FromStreamer,
393
+ 'UnfreezeFrame',
394
+ () => this.invalidateFreezeFrameAndEnableVideo()
395
+ );
396
+ this.streamMessageController.registerMessageHandler(
397
+ MessageDirection.FromStreamer,
398
+ 'VideoEncoderAvgQP',
399
+ (data: ArrayBuffer) => this.handleVideoEncoderAvgQP(data)
400
+ );
401
+ this.streamMessageController.registerMessageHandler(
402
+ MessageDirection.FromStreamer,
403
+ 'LatencyTest',
404
+ (data: ArrayBuffer) => this.handleLatencyTestResult(data)
405
+ );
406
+ this.streamMessageController.registerMessageHandler(
407
+ MessageDirection.FromStreamer,
408
+ 'DataChannelLatencyTest',
409
+ (data: ArrayBuffer) => this.handleDataChannelLatencyTestResponse(data)
410
+ )
411
+ this.streamMessageController.registerMessageHandler(
412
+ MessageDirection.FromStreamer,
413
+ 'InitialSettings',
414
+ (data: ArrayBuffer) => this.handleInitialSettings(data)
415
+ );
416
+ this.streamMessageController.registerMessageHandler(
417
+ MessageDirection.FromStreamer,
418
+ 'FileExtension',
419
+ (data: ArrayBuffer) => this.onFileExtension(data)
420
+ );
421
+ this.streamMessageController.registerMessageHandler(
422
+ MessageDirection.FromStreamer,
423
+ 'FileMimeType',
424
+ (data: ArrayBuffer) => this.onFileMimeType(data)
425
+ );
426
+ this.streamMessageController.registerMessageHandler(
427
+ MessageDirection.FromStreamer,
428
+ 'FileContents',
429
+ (data: ArrayBuffer) => this.onFileContents(data)
430
+ );
431
+ this.streamMessageController.registerMessageHandler(
432
+ MessageDirection.FromStreamer,
433
+ 'TestEcho',
434
+ () => {
435
+ /* Do nothing */
436
+ }
437
+ );
438
+ this.streamMessageController.registerMessageHandler(
439
+ MessageDirection.FromStreamer,
440
+ 'InputControlOwnership',
441
+ (data: ArrayBuffer) => this.onInputControlOwnership(data)
442
+ );
443
+ this.streamMessageController.registerMessageHandler(
444
+ MessageDirection.FromStreamer,
445
+ 'GamepadResponse',
446
+ (data: ArrayBuffer) => this.onGamepadResponse(data)
447
+ );
448
+ this.streamMessageController.registerMessageHandler(
449
+ MessageDirection.FromStreamer,
450
+ 'Protocol',
451
+ (data: ArrayBuffer) => this.onProtocolMessage(data)
452
+ );
453
+
454
+ // To Streamer
455
+ this.streamMessageController.registerMessageHandler(
456
+ MessageDirection.ToStreamer,
457
+ 'IFrameRequest',
458
+ () =>
459
+ this.sendMessageController.sendMessageToStreamer(
460
+ 'IFrameRequest'
461
+ )
462
+ );
463
+ this.streamMessageController.registerMessageHandler(
464
+ MessageDirection.ToStreamer,
465
+ 'RequestQualityControl',
466
+ () =>
467
+ this.sendMessageController.sendMessageToStreamer(
468
+ 'RequestQualityControl'
469
+ )
470
+ );
471
+ this.streamMessageController.registerMessageHandler(
472
+ MessageDirection.ToStreamer,
473
+ 'FpsRequest',
474
+ () => this.sendMessageController.sendMessageToStreamer('FpsRequest')
475
+ );
476
+ this.streamMessageController.registerMessageHandler(
477
+ MessageDirection.ToStreamer,
478
+ 'AverageBitrateRequest',
479
+ () =>
480
+ this.sendMessageController.sendMessageToStreamer(
481
+ 'AverageBitrateRequest'
482
+ )
483
+ );
484
+ this.streamMessageController.registerMessageHandler(
485
+ MessageDirection.ToStreamer,
486
+ 'StartStreaming',
487
+ () =>
488
+ this.sendMessageController.sendMessageToStreamer(
489
+ 'StartStreaming'
490
+ )
491
+ );
492
+ this.streamMessageController.registerMessageHandler(
493
+ MessageDirection.ToStreamer,
494
+ 'StopStreaming',
495
+ () =>
496
+ this.sendMessageController.sendMessageToStreamer(
497
+ 'StopStreaming'
498
+ )
499
+ );
500
+ this.streamMessageController.registerMessageHandler(
501
+ MessageDirection.ToStreamer,
502
+ 'LatencyTest',
503
+ (data: Array<number | string>) =>
504
+ this.sendMessageController.sendMessageToStreamer(
505
+ 'LatencyTest', data
506
+ )
507
+ );
508
+ this.streamMessageController.registerMessageHandler(
509
+ MessageDirection.ToStreamer,
510
+ 'RequestInitialSettings',
511
+ () =>
512
+ this.sendMessageController.sendMessageToStreamer(
513
+ 'RequestInitialSettings'
514
+ )
515
+ );
516
+ this.streamMessageController.registerMessageHandler(
517
+ MessageDirection.ToStreamer,
518
+ 'TestEcho',
519
+ () => {
520
+ /* Do nothing */
521
+ }
522
+ );
523
+ this.streamMessageController.registerMessageHandler(
524
+ MessageDirection.ToStreamer,
525
+ 'UIInteraction',
526
+ (data: Array<number | string>) =>
527
+ this.sendMessageController.sendMessageToStreamer(
528
+ 'UIInteraction', data
529
+ )
530
+ );
531
+ this.streamMessageController.registerMessageHandler(
532
+ MessageDirection.ToStreamer,
533
+ 'Command',
534
+ (data: Array<number | string>) =>
535
+ this.sendMessageController.sendMessageToStreamer(
536
+ 'Command', data
537
+ )
538
+ );
539
+ this.streamMessageController.registerMessageHandler(
540
+ MessageDirection.ToStreamer,
541
+ 'TextboxEntry',
542
+ (data: Array<number | string>) =>
543
+ this.sendMessageController.sendMessageToStreamer(
544
+ 'TextboxEntry', data
545
+ )
546
+ );
547
+ this.streamMessageController.registerMessageHandler(
548
+ MessageDirection.ToStreamer,
549
+ 'KeyDown',
550
+ (data: Array<number | string>) =>
551
+ this.sendMessageController.sendMessageToStreamer(
552
+ 'KeyDown',
553
+ data
554
+ )
555
+ );
556
+ this.streamMessageController.registerMessageHandler(
557
+ MessageDirection.ToStreamer,
558
+ 'KeyUp',
559
+ (data: Array<number | string>) =>
560
+ this.sendMessageController.sendMessageToStreamer('KeyUp', data)
561
+ );
562
+ this.streamMessageController.registerMessageHandler(
563
+ MessageDirection.ToStreamer,
564
+ 'KeyPress',
565
+ (data: Array<number | string>) =>
566
+ this.sendMessageController.sendMessageToStreamer(
567
+ 'KeyPress',
568
+ data
569
+ )
570
+ );
571
+ this.streamMessageController.registerMessageHandler(
572
+ MessageDirection.ToStreamer,
573
+ 'MouseEnter',
574
+ (data: Array<number | string>) =>
575
+ this.sendMessageController.sendMessageToStreamer(
576
+ 'MouseEnter',
577
+ data
578
+ )
579
+ );
580
+ this.streamMessageController.registerMessageHandler(
581
+ MessageDirection.ToStreamer,
582
+ 'MouseLeave',
583
+ (data: Array<number | string>) =>
584
+ this.sendMessageController.sendMessageToStreamer(
585
+ 'MouseLeave',
586
+ data
587
+ )
588
+ );
589
+ this.streamMessageController.registerMessageHandler(
590
+ MessageDirection.ToStreamer,
591
+ 'MouseDown',
592
+ (data: Array<number | string>) =>
593
+ this.sendMessageController.sendMessageToStreamer(
594
+ 'MouseDown',
595
+ data
596
+ )
597
+ );
598
+ this.streamMessageController.registerMessageHandler(
599
+ MessageDirection.ToStreamer,
600
+ 'MouseUp',
601
+ (data: Array<number | string>) =>
602
+ this.sendMessageController.sendMessageToStreamer(
603
+ 'MouseUp',
604
+ data
605
+ )
606
+ );
607
+ this.streamMessageController.registerMessageHandler(
608
+ MessageDirection.ToStreamer,
609
+ 'MouseMove',
610
+ (data: Array<number | string>) =>
611
+ this.sendMessageController.sendMessageToStreamer(
612
+ 'MouseMove',
613
+ data
614
+ )
615
+ );
616
+ this.streamMessageController.registerMessageHandler(
617
+ MessageDirection.ToStreamer,
618
+ 'MouseWheel',
619
+ (data: Array<number | string>) =>
620
+ this.sendMessageController.sendMessageToStreamer(
621
+ 'MouseWheel',
622
+ data
623
+ )
624
+ );
625
+ this.streamMessageController.registerMessageHandler(
626
+ MessageDirection.ToStreamer,
627
+ 'MouseDouble',
628
+ (data: Array<number | string>) =>
629
+ this.sendMessageController.sendMessageToStreamer(
630
+ 'MouseDouble',
631
+ data
632
+ )
633
+ );
634
+ this.streamMessageController.registerMessageHandler(
635
+ MessageDirection.ToStreamer,
636
+ 'TouchStart',
637
+ (data: Array<number | string>) =>
638
+ this.sendMessageController.sendMessageToStreamer(
639
+ 'TouchStart',
640
+ data
641
+ )
642
+ );
643
+ this.streamMessageController.registerMessageHandler(
644
+ MessageDirection.ToStreamer,
645
+ 'TouchEnd',
646
+ (data: Array<number | string>) =>
647
+ this.sendMessageController.sendMessageToStreamer(
648
+ 'TouchEnd',
649
+ data
650
+ )
651
+ );
652
+ this.streamMessageController.registerMessageHandler(
653
+ MessageDirection.ToStreamer,
654
+ 'TouchMove',
655
+ (data: Array<number | string>) =>
656
+ this.sendMessageController.sendMessageToStreamer(
657
+ 'TouchMove',
658
+ data
659
+ )
660
+ );
661
+ this.streamMessageController.registerMessageHandler(
662
+ MessageDirection.ToStreamer,
663
+ 'GamepadConnected',
664
+ () =>
665
+ this.sendMessageController.sendMessageToStreamer(
666
+ 'GamepadConnected'
667
+ )
668
+ );
669
+ this.streamMessageController.registerMessageHandler(
670
+ MessageDirection.ToStreamer,
671
+ 'GamepadButtonPressed',
672
+ (data: Array<number | string>) =>
673
+ this.sendMessageController.sendMessageToStreamer(
674
+ 'GamepadButtonPressed',
675
+ data
676
+ )
677
+ );
678
+ this.streamMessageController.registerMessageHandler(
679
+ MessageDirection.ToStreamer,
680
+ 'GamepadButtonReleased',
681
+ (data: Array<number | string>) =>
682
+ this.sendMessageController.sendMessageToStreamer(
683
+ 'GamepadButtonReleased',
684
+ data
685
+ )
686
+ );
687
+ this.streamMessageController.registerMessageHandler(
688
+ MessageDirection.ToStreamer,
689
+ 'GamepadAnalog',
690
+ (data: Array<number | string>) =>
691
+ this.sendMessageController.sendMessageToStreamer(
692
+ 'GamepadAnalog',
693
+ data
694
+ )
695
+ );
696
+ this.streamMessageController.registerMessageHandler(
697
+ MessageDirection.ToStreamer,
698
+ 'GamepadDisconnected',
699
+ (data: Array<number | string>) =>
700
+ this.sendMessageController.sendMessageToStreamer(
701
+ 'GamepadDisconnected',
702
+ data
703
+ )
704
+ );
705
+ this.streamMessageController.registerMessageHandler(
706
+ MessageDirection.ToStreamer,
707
+ 'XRHMDTransform',
708
+ (data: Array<number | string>) =>
709
+ this.sendMessageController.sendMessageToStreamer(
710
+ 'XRHMDTransform',
711
+ data
712
+ )
713
+ );
714
+ this.streamMessageController.registerMessageHandler(
715
+ MessageDirection.ToStreamer,
716
+ 'XRControllerTransform',
717
+ (data: Array<number | string>) =>
718
+ this.sendMessageController.sendMessageToStreamer(
719
+ 'XRControllerTransform',
720
+ data
721
+ )
722
+ );
723
+ this.streamMessageController.registerMessageHandler(
724
+ MessageDirection.ToStreamer,
725
+ 'XRSystem',
726
+ (data: Array<number | string>) =>
727
+ this.sendMessageController.sendMessageToStreamer(
728
+ 'XRSystem',
729
+ data
730
+ )
731
+ );
732
+ this.streamMessageController.registerMessageHandler(
733
+ MessageDirection.ToStreamer,
734
+ 'XRButtonTouched',
735
+ (data: Array<number | string>) =>
736
+ this.sendMessageController.sendMessageToStreamer(
737
+ 'XRButtonTouched',
738
+ data
739
+ )
740
+ );
741
+ this.streamMessageController.registerMessageHandler(
742
+ MessageDirection.ToStreamer,
743
+ 'XRButtonPressed',
744
+ (data: Array<number | string>) =>
745
+ this.sendMessageController.sendMessageToStreamer(
746
+ 'XRButtonPressed',
747
+ data
748
+ )
749
+ );
750
+ this.streamMessageController.registerMessageHandler(
751
+ MessageDirection.ToStreamer,
752
+ 'XRButtonReleased',
753
+ (data: Array<number | string>) =>
754
+ this.sendMessageController.sendMessageToStreamer(
755
+ 'XRButtonReleased',
756
+ data
757
+ )
758
+ );
759
+ this.streamMessageController.registerMessageHandler(
760
+ MessageDirection.ToStreamer,
761
+ 'XRAnalog',
762
+ (data: Array<number | string>) =>
763
+ this.sendMessageController.sendMessageToStreamer(
764
+ 'XRAnalog',
765
+ data
766
+ )
767
+ );
768
+ }
769
+
770
+ /**
771
+ * Activate the logic associated with a command from UE
772
+ * @param message
773
+ */
774
+ onCommand(message: ArrayBuffer) {
775
+ Logger.Log(
776
+ Logger.GetStackTrace(),
777
+ 'DataChannelReceiveMessageType.Command',
778
+ 6
779
+ );
780
+ const commandAsString = new TextDecoder('utf-16').decode(
781
+ message.slice(1)
782
+ );
783
+
784
+ Logger.Log(
785
+ Logger.GetStackTrace(),
786
+ 'Data Channel Command: ' + commandAsString,
787
+ 6
788
+ );
789
+ const command: MessageOnScreenKeyboard = JSON.parse(commandAsString);
790
+ if (command.command === 'onScreenKeyboard') {
791
+ this.pixelStreaming._activateOnScreenKeyboard(command);
792
+ }
793
+ }
794
+
795
+ /**
796
+ * Handles a protocol message received from the streamer
797
+ * @param message the message data from the streamer
798
+ */
799
+ onProtocolMessage(message: ArrayBuffer) {
800
+ try {
801
+ const protocolString = new TextDecoder('utf-16').decode(
802
+ message.slice(1)
803
+ );
804
+ const protocolJSON = JSON.parse(protocolString);
805
+ if (
806
+ !Object.prototype.hasOwnProperty.call(protocolJSON, 'Direction')
807
+ ) {
808
+ Logger.Error(
809
+ Logger.GetStackTrace(),
810
+ 'Malformed protocol received. Ensure the protocol message contains a direction'
811
+ );
812
+ }
813
+ const direction = protocolJSON.Direction;
814
+ delete protocolJSON.Direction;
815
+ Logger.Log(
816
+ Logger.GetStackTrace(),
817
+ `Received new ${direction == MessageDirection.FromStreamer
818
+ ? 'FromStreamer'
819
+ : 'ToStreamer'
820
+ } protocol. Updating existing protocol...(更新现有协议)`
821
+ );
822
+ Object.keys(protocolJSON).forEach((messageType) => {
823
+ const message = protocolJSON[messageType];
824
+ switch (direction) {
825
+ case MessageDirection.ToStreamer:
826
+ // Check that the message contains all the relevant params
827
+ if (
828
+ !Object.prototype.hasOwnProperty.call(
829
+ message,
830
+ 'id'
831
+ )
832
+ ) {
833
+ Logger.Error(
834
+ Logger.GetStackTrace(),
835
+ `ToStreamer->${messageType} protocol definition was malformed as it didn't contain at least an id\n
836
+ Definition was: ${JSON.stringify(
837
+ message,
838
+ null,
839
+ 2
840
+ )}`
841
+ );
842
+ // return in a forEach is equivalent to a continue in a normal for loop
843
+ return;
844
+ }
845
+
846
+ // UE5.1 and UE5.2 don't send a structure for these message types, but they actually do have a structure so ignore updating them
847
+ if ((messageType === "UIInteraction" || messageType === "Command" || messageType === "LatencyTest")) {
848
+ return;
849
+ }
850
+
851
+ if (
852
+ this.streamMessageController.toStreamerHandlers.get(
853
+ messageType
854
+ )
855
+ ) {
856
+ // If we've registered a handler for this message type we can add it to our supported messages. ie registerMessageHandler(...)
857
+ this.streamMessageController.toStreamerMessages.set(
858
+ messageType,
859
+ message
860
+ );
861
+ } else {
862
+ Logger.Error(
863
+ Logger.GetStackTrace(),
864
+ `There was no registered handler for "${messageType}" - try adding one using registerMessageHandler(MessageDirection.ToStreamer, "${messageType}", myHandler)`
865
+ );
866
+ }
867
+ break;
868
+ case MessageDirection.FromStreamer:
869
+ // Check that the message contains all the relevant params
870
+ if (
871
+ !Object.prototype.hasOwnProperty.call(message, 'id')
872
+ ) {
873
+ Logger.Error(
874
+ Logger.GetStackTrace(),
875
+ `FromStreamer->${messageType} protocol definition was malformed as it didn't contain at least an id\n
876
+ Definition was: ${JSON.stringify(message, null, 2)}`
877
+ );
878
+ // return in a forEach is equivalent to a continue in a normal for loop
879
+ return;
880
+ }
881
+ if (
882
+ this.streamMessageController.fromStreamerHandlers.get(
883
+ messageType
884
+ )
885
+ ) {
886
+ // If we've registered a handler for this message type. ie registerMessageHandler(...)
887
+ this.streamMessageController.fromStreamerMessages.set(
888
+ message.id,
889
+ messageType
890
+ );
891
+ } else {
892
+ Logger.Error(
893
+ Logger.GetStackTrace(),
894
+ `There was no registered handler for "${message}" - try adding one using registerMessageHandler(MessageDirection.FromStreamer, "${messageType}", myHandler)`
895
+ );
896
+ }
897
+ break;
898
+ default:
899
+ Logger.Error(
900
+ Logger.GetStackTrace(),
901
+ `Unknown direction: ${direction}`
902
+ );
903
+ }
904
+ });
905
+
906
+ // Once the protocol has been received, we can send our control messages
907
+ this.toStreamerMessagesController.SendRequestInitialSettings();
908
+ this.toStreamerMessagesController.SendRequestQualityControl();
909
+ } catch (e) {
910
+ Logger.Log(Logger.GetStackTrace(), e);
911
+ }
912
+ }
913
+
914
+ /**
915
+ * Handles an input control message when it is received from the streamer
916
+ * @param message The input control message
917
+ */
918
+ onInputControlOwnership(message: ArrayBuffer) {
919
+ const view = new Uint8Array(message);
920
+ Logger.Log(
921
+ Logger.GetStackTrace(),
922
+ 'DataChannelReceiveMessageType.InputControlOwnership',
923
+ 6
924
+ );
925
+ const inputControlOwnership = new Boolean(view[1]).valueOf();
926
+ Logger.Log(
927
+ Logger.GetStackTrace(),
928
+ `Received input controller message - will your input control the stream: ${inputControlOwnership}`
929
+ );
930
+ this.pixelStreaming._onInputControlOwnership(inputControlOwnership);
931
+ }
932
+
933
+ /**
934
+ *
935
+ * @param message
936
+ */
937
+ onGamepadResponse(message: ArrayBuffer) {
938
+ const responseString = new TextDecoder('utf-16').decode(message.slice(1));
939
+ const responseJSON = JSON.parse(responseString);
940
+ this.gamePadController.onGamepadResponseReceived(responseJSON.controllerId);
941
+ }
942
+
943
+ onAfkTriggered(): void {
944
+ this.afkController.onAfkClick();
945
+
946
+ // if the stream is paused play it, if we can
947
+ if (this.videoPlayer.isPaused() && this.videoPlayer.hasVideoSource()) {
948
+ this.playStream();
949
+ }
950
+ }
951
+
952
+ /**
953
+ * Set whether we should timeout when afk.
954
+ * @param afkEnabled If true we timeout when idle for some given amount of time.
955
+ */
956
+ setAfkEnabled(afkEnabled: boolean): void {
957
+ if (afkEnabled) {
958
+ this.onAfkTriggered();
959
+ } else {
960
+ this.afkController.stopAfkWarningTimer();
961
+ }
962
+ }
963
+
964
+ /**
965
+ * 尝试重新连接到信令服务器
966
+ */
967
+ tryReconnect(message: string) {
968
+ // 如果没有webSocketController,立即返回,否则将不起作用
969
+ if (!this.webSocketController) {
970
+ Logger.Log(
971
+ Logger.GetStackTrace(),
972
+ 'The Web Socket Controller does not exist so this will not work right now.'
973
+ );
974
+ return;
975
+ }
976
+
977
+ // 如果连接是打开的,首先关闭它。等待一段时间再试一次
978
+ this.isReconnecting = true;
979
+ if (this.webSocketController.webSocket && this.webSocketController.webSocket.readyState != WebSocket.CLOSED) {
980
+ this.closeSignalingServer(`${message} Restarting stream...`);
981
+ setTimeout(() => {
982
+ this.tryReconnect(message);
983
+ }, 3000);
984
+ } else {
985
+ this.pixelStreaming._onWebRtcAutoConnect();
986
+ this.connectToSignallingServer();
987
+ }
988
+ }
989
+
990
+ /**
991
+ * 如果需要,加载一个定格帧,否则显示播放覆盖
992
+ */
993
+ loadFreezeFrameOrShowPlayOverlay() {
994
+ this.pixelStreaming.dispatchEvent(
995
+ new LoadFreezeFrameEvent({
996
+ shouldShowPlayOverlay: this.shouldShowPlayOverlay,
997
+ isValid: this.freezeFrameController.valid,
998
+ jpegData: this.freezeFrameController.jpeg
999
+ })
1000
+ );
1001
+ if (this.shouldShowPlayOverlay === true) {
1002
+ Logger.Log(Logger.GetStackTrace(), 'showing play overlay');
1003
+ this.resizePlayerStyle();
1004
+ } else {
1005
+ Logger.Log(Logger.GetStackTrace(), 'showing freeze frame');
1006
+ this.freezeFrameController.showFreezeFrame();
1007
+ }
1008
+ setTimeout(() => {
1009
+ this.videoPlayer.setVideoEnabled(false);
1010
+ }, this.freezeFrameController.freezeFrameDelay);
1011
+ }
1012
+
1013
+ /**
1014
+ * Process the freeze frame and load it
1015
+ * @param message The freeze frame data in bytes
1016
+ */
1017
+ onFreezeFrameMessage(message: ArrayBuffer) {
1018
+ Logger.Log(
1019
+ Logger.GetStackTrace(),
1020
+ 'DataChannelReceiveMessageType.FreezeFrame',
1021
+ 6
1022
+ );
1023
+ const view = new Uint8Array(message);
1024
+ this.freezeFrameController.processFreezeFrameMessage(view, () =>
1025
+ this.loadFreezeFrameOrShowPlayOverlay()
1026
+ );
1027
+ }
1028
+
1029
+ /**
1030
+ * Enable the video after hiding a freeze frame
1031
+ */
1032
+ invalidateFreezeFrameAndEnableVideo() {
1033
+ Logger.Log(
1034
+ Logger.GetStackTrace(),
1035
+ 'DataChannelReceiveMessageType.FreezeFrame',
1036
+ 6
1037
+ );
1038
+ setTimeout(() => {
1039
+ this.pixelStreaming.dispatchEvent(
1040
+ new HideFreezeFrameEvent()
1041
+ );
1042
+ this.freezeFrameController.hideFreezeFrame();
1043
+ }, this.freezeFrameController.freezeFrameDelay);
1044
+ if (this.videoPlayer.getVideoElement()) {
1045
+ this.videoPlayer.setVideoEnabled(true);
1046
+ }
1047
+ }
1048
+
1049
+ /**
1050
+ * Prep datachannel data for processing file extension
1051
+ * @param data the file extension data
1052
+ */
1053
+ onFileExtension(data: ArrayBuffer) {
1054
+ const view = new Uint8Array(data);
1055
+ FileUtil.setExtensionFromBytes(view, this.file);
1056
+ }
1057
+
1058
+ /**
1059
+ * Prep datachannel data for processing the file mime type
1060
+ * @param data the file mime type data
1061
+ */
1062
+ onFileMimeType(data: ArrayBuffer) {
1063
+ const view = new Uint8Array(data);
1064
+ FileUtil.setMimeTypeFromBytes(view, this.file);
1065
+ }
1066
+
1067
+ /**
1068
+ * Prep datachannel data for processing the file contents
1069
+ * @param data the file contents data
1070
+ */
1071
+ onFileContents(data: ArrayBuffer) {
1072
+ const view = new Uint8Array(data);
1073
+ FileUtil.setContentsFromBytes(view, this.file);
1074
+ }
1075
+
1076
+ /**
1077
+ * 播放流音频和视频源,并在流启动时设置其他片段
1078
+ */
1079
+ playStream() {
1080
+ if (!this.videoPlayer.getVideoElement()) {
1081
+ const message =
1082
+ 'Could not play video stream because the video player was not initialized correctly.';
1083
+ this.pixelStreaming.dispatchEvent(
1084
+ new PlayStreamErrorEvent({ message })
1085
+ );
1086
+ Logger.Error(Logger.GetStackTrace(), message);
1087
+
1088
+ // close the connection
1089
+ this.closeSignalingServer('Stream not initialized correctly');
1090
+ return;
1091
+ }
1092
+
1093
+ if (!this.videoPlayer.hasVideoSource()) {
1094
+ Logger.Warning(
1095
+ Logger.GetStackTrace(),
1096
+ 'Cannot play stream, the video element has no srcObject to play.'
1097
+ );
1098
+ return;
1099
+ }
1100
+
1101
+ this.setTouchInputEnabled(this.config.isFlagEnabled(Flags.TouchInput));
1102
+ this.pixelStreaming.dispatchEvent(new PlayStreamEvent());
1103
+
1104
+ if (this.streamController.audioElement.srcObject) {
1105
+ const startMuted = this.config.isFlagEnabled(Flags.StartVideoMuted)
1106
+ this.streamController.audioElement.muted = startMuted;
1107
+
1108
+ if (startMuted) {
1109
+ this.playVideo();
1110
+ } else {
1111
+ this.streamController.audioElement
1112
+ .play()
1113
+ .then(() => {
1114
+ this.playVideo();
1115
+ })
1116
+ .catch((onRejectedReason) => {
1117
+ Logger.Log(Logger.GetStackTrace(), onRejectedReason);
1118
+ Logger.Log(
1119
+ Logger.GetStackTrace(),
1120
+ 'Browser does not support autoplaying video without interaction - to resolve this we are going to show the play button overlay.'
1121
+ );
1122
+ this.pixelStreaming.dispatchEvent(
1123
+ new PlayStreamRejectedEvent({
1124
+ reason: onRejectedReason
1125
+ })
1126
+ );
1127
+ });
1128
+ }
1129
+ } else {
1130
+ this.playVideo();
1131
+ }
1132
+
1133
+ this.shouldShowPlayOverlay = false;
1134
+ this.freezeFrameController.showFreezeFrame();
1135
+ }
1136
+
1137
+ /**
1138
+ * Plays the video stream
1139
+ */
1140
+ private playVideo() {
1141
+ // handle play() with promise as it is an asynchronous call
1142
+ this.videoPlayer.play().catch((onRejectedReason: string) => {
1143
+ if (this.streamController.audioElement.srcObject) {
1144
+ this.streamController.audioElement.pause();
1145
+ }
1146
+ Logger.Log(Logger.GetStackTrace(), onRejectedReason);
1147
+ Logger.Log(
1148
+ Logger.GetStackTrace(),
1149
+ 'Browser does not support autoplaying video without interaction - to resolve this we are going to show the play button overlay.'
1150
+ );
1151
+ this.pixelStreaming.dispatchEvent(
1152
+ new PlayStreamRejectedEvent({ reason: onRejectedReason })
1153
+ );
1154
+ });
1155
+ }
1156
+
1157
+ /**
1158
+ * Enable the video to play automatically if enableAutoplay is true
1159
+ */
1160
+ autoPlayVideoOrSetUpPlayOverlay() {
1161
+ if (this.config.isFlagEnabled(Flags.AutoPlayVideo)) {
1162
+ // attempt to play the video
1163
+ this.playStream();
1164
+ }
1165
+ this.resizePlayerStyle();
1166
+ }
1167
+
1168
+ /**
1169
+ * 连接发信服务器
1170
+ */
1171
+ connectToSignallingServer() {
1172
+ this.locallyClosed = false;
1173
+ this.shouldReconnect = true;
1174
+ this.disconnectMessage = null;
1175
+ const signallingUrl = this.signallingUrlBuilder();
1176
+ this.webSocketController.connect(signallingUrl);
1177
+ }
1178
+
1179
+ /**
1180
+ * This will start the handshake to the signalling server
1181
+ * @param peerConfig - RTC Configuration Options from the Signaling server
1182
+ * @remark RTC Peer Connection on Ice Candidate event have it handled by handle Send Ice Candidate
1183
+ */
1184
+ startSession(peerConfig: RTCConfiguration) {
1185
+ this.peerConfig = peerConfig;
1186
+ // check for forcing turn
1187
+ if (this.config.isFlagEnabled(Flags.ForceTURN)) {
1188
+ // check for a turn server
1189
+ const hasTurnServer = this.checkTurnServerAvailability(peerConfig);
1190
+
1191
+ // close and error if turn is forced and there is no turn server
1192
+ if (!hasTurnServer) {
1193
+ Logger.Info(
1194
+ Logger.GetStackTrace(),
1195
+ 'No turn server was found in the Peer Connection Options. TURN cannot be forced, closing connection. Please use STUN instead'
1196
+ );
1197
+ this.closeSignalingServer('TURN cannot be forced, closing connection. Please use STUN instead.');
1198
+ return;
1199
+ }
1200
+ }
1201
+
1202
+ // set up the peer connection controller
1203
+ this.peerConnectionController = new PeerConnectionController(
1204
+ this.peerConfig,
1205
+ this.config,
1206
+ this.preferredCodec
1207
+ );
1208
+
1209
+ // set up peer connection controller video stats
1210
+ this.peerConnectionController.onVideoStats = (event: AggregatedStats) =>
1211
+ this.handleVideoStats(event);
1212
+
1213
+ /* When the Peer Connection wants to send an offer have it handled */
1214
+ this.peerConnectionController.onSendWebRTCOffer = (
1215
+ offer: RTCSessionDescriptionInit
1216
+ ) => this.handleSendWebRTCOffer(offer);
1217
+
1218
+ /* When the Peer Connection wants to send an answer have it handled */
1219
+ this.peerConnectionController.onSendWebRTCAnswer = (
1220
+ offer: RTCSessionDescriptionInit
1221
+ ) => this.handleSendWebRTCAnswer(offer);
1222
+
1223
+ /* When the Peer Connection ice candidate is added have it handled */
1224
+ this.peerConnectionController.onPeerIceCandidate = (
1225
+ peerConnectionIceEvent: RTCPeerConnectionIceEvent
1226
+ ) => this.handleSendIceCandidate(peerConnectionIceEvent);
1227
+
1228
+ /* When the Peer Connection has a data channel created for it by the browser, handle it */
1229
+ this.peerConnectionController.onDataChannel = (
1230
+ datachannelEvent: RTCDataChannelEvent
1231
+ ) => this.handleDataChannel(datachannelEvent);
1232
+
1233
+ // 设置webRtc的文本覆盖层
1234
+ this.peerConnectionController.showTextOverlayConnecting = () =>
1235
+ this.pixelStreaming._onWebRtcConnecting();
1236
+ this.peerConnectionController.showTextOverlaySetupFailure = () =>
1237
+ this.pixelStreaming._onWebRtcFailed();
1238
+ let webRtcConnectedSent = false;
1239
+ this.peerConnectionController.onIceConnectionStateChange = () => {
1240
+ // Browsers emit "connected" when getting first connection and "completed" when finishing
1241
+ // candidate checking. However, sometimes browsers can skip "connected" and only emit "completed".
1242
+ // Therefore need to check both cases and emit onWebRtcConnected only once on the first hit.
1243
+ if (!webRtcConnectedSent &&
1244
+ ["connected", "completed"].includes(this.peerConnectionController.peerConnection.iceConnectionState)) {
1245
+ this.pixelStreaming._onWebRtcConnected();
1246
+ webRtcConnectedSent = true;
1247
+ }
1248
+ };
1249
+
1250
+ /* RTC Peer Connection on Track event -> handle on track */
1251
+ this.peerConnectionController.onTrack = (trackEvent: RTCTrackEvent) =>
1252
+ this.streamController.handleOnTrack(trackEvent);
1253
+
1254
+ /* Start the Hand shake process by creating an Offer */
1255
+ const BrowserSendsOffer = this.config.isFlagEnabled(
1256
+ Flags.BrowserSendOffer
1257
+ );
1258
+ if (BrowserSendsOffer) {
1259
+ // If browser is sending the offer, create an offer and send it to the streamer
1260
+ this.sendrecvDataChannelController.createDataChannel(
1261
+ this.peerConnectionController.peerConnection,
1262
+ 'cirrus',
1263
+ this.datachannelOptions
1264
+ );
1265
+ this.sendrecvDataChannelController.handleOnMessage = (
1266
+ ev: MessageEvent<ArrayBuffer>
1267
+ ) => this.handleOnMessage(ev);
1268
+ this.peerConnectionController.createOffer(
1269
+ this.sdpConstraints,
1270
+ this.config
1271
+ );
1272
+ }
1273
+ }
1274
+
1275
+ /**
1276
+ * Checks the peer connection options for a turn server and returns true or false
1277
+ */
1278
+ checkTurnServerAvailability(options: RTCConfiguration) {
1279
+ // if iceServers is empty return false this should not be the general use case but is here incase
1280
+ if (!options.iceServers) {
1281
+ Logger.Info(Logger.GetStackTrace(), 'A turn sever was not found');
1282
+ return false;
1283
+ }
1284
+
1285
+ // loop through the ice servers to check for a turn url
1286
+ for (const iceServer of options.iceServers) {
1287
+ for (const url of iceServer.urls) {
1288
+ if (url.includes('turn')) {
1289
+ Logger.Log(
1290
+ Logger.GetStackTrace(),
1291
+ `A turn sever was found at ${url}`
1292
+ );
1293
+ return true;
1294
+ }
1295
+ }
1296
+ }
1297
+
1298
+ Logger.Info(Logger.GetStackTrace(), 'A turn sever was not found');
1299
+ return false;
1300
+ }
1301
+
1302
+ /**
1303
+ * 接收到配置消息时的处理包含所需的对等连接选项(STUN和TURN服务器信息)
1304
+ * @param messageConfig—从发信服务器接收到的配置消息
1305
+ */
1306
+ handleOnConfigMessage(messageConfig: MessageConfig) {
1307
+ this.resizePlayerStyle();
1308
+
1309
+ // 告诉WebRtcController使用发信服务器发送的对等点选项启动会话
1310
+ this.startSession(messageConfig.peerConnectionOptions);
1311
+
1312
+ // 发信服务器通过websocket连接发送WebRTC应答时,让WebRtcController处理消息
1313
+ this.webSocketController.onWebRtcAnswer = (
1314
+ messageAnswer: MessageReceive.MessageAnswer
1315
+ ) => this.handleWebRtcAnswer(messageAnswer);
1316
+
1317
+ this.webSocketController.onWebRtcOffer = (
1318
+ messageOffer: MessageReceive.MessageOffer
1319
+ ) => this.handleWebRtcOffer(messageOffer);
1320
+
1321
+ this.webSocketController.onWebRtcPeerDataChannels = (
1322
+ messageDataChannels: MessageReceive.MessagePeerDataChannels
1323
+ ) => this.handleWebRtcSFUPeerDatachannels(messageDataChannels);
1324
+
1325
+ // 发信服务器通过websocket连接发送iccandidate时,让WebRtcController处理消息
1326
+ this.webSocketController.onIceCandidate = (
1327
+ iceCandidate: RTCIceCandidateInit
1328
+ ) => this.handleIceCandidate(iceCandidate);
1329
+ }
1330
+
1331
+ /**
1332
+ * 当信令服务器给我们streamer id列表时处理。
1333
+ */
1334
+ handleStreamerListMessage(messageStreamerList: MessageStreamerList) {
1335
+ console.log(messageStreamerList, '=====');
1336
+
1337
+ Logger.Log(
1338
+ Logger.GetStackTrace(),
1339
+ `Got streamer list ${messageStreamerList.ids}`,
1340
+ 6
1341
+ );
1342
+
1343
+ const streamerBusyList = messageStreamerList.streamerBusyList ?? []
1344
+
1345
+ if (streamerBusyList.length > 0) {
1346
+ console.log(window.location.href, '======');
1347
+ if (window.location.href.indexOf('home') != -1) {
1348
+ return
1349
+ } else {
1350
+ ElMessageBox.confirm(
1351
+ '监测到当前窗口有人在使用,是否强制进入?',
1352
+ '警告',
1353
+ {
1354
+ confirmButtonText: '确定',
1355
+ cancelButtonText: '取消',
1356
+ type: 'warning',
1357
+ }
1358
+ )
1359
+ .then(() => {
1360
+ this.webSocketController.sendSubscribe(streamerBusyList[0].streamerId);
1361
+ })
1362
+ .catch(() => {
1363
+
1364
+ })
1365
+ }
1366
+ }
1367
+
1368
+
1369
+ // 将streamer添加到UI中
1370
+ const settingOptions = [...messageStreamerList.ids]; // 复制原始的messageStreamerList.ids
1371
+ // settingOptions.unshift(''); // 在顶部添加一个空选项
1372
+ console.log(settingOptions);
1373
+
1374
+ this.config.setOptionSettingOptions(
1375
+ OptionParameters.StreamerId,
1376
+ settingOptions
1377
+ );
1378
+
1379
+ let wantedStreamerId: string = null;
1380
+ let autoSelectedStreamerId: string = null;
1381
+
1382
+ const waitForStreamer = this.config.isFlagEnabled(Flags.WaitForStreamer);
1383
+ const reconnectLimit = this.config.getNumericSettingValue(NumericParameters.MaxReconnectAttempts);
1384
+ const reconnectDelay = this.config.getNumericSettingValue(NumericParameters.StreamerAutoJoinInterval);
1385
+
1386
+ // 首先,我们通过各种方式找出一个通缉的主播id
1387
+ const urlParams = new URLSearchParams(window.location.search);
1388
+ if (urlParams.has(OptionParameters.StreamerId)) {
1389
+ // 如果我们已经在url上设置了streamer id,我们只想要那个streamer id
1390
+ wantedStreamerId = urlParams.get(OptionParameters.StreamerId);
1391
+ } else if (this.subscribedStream) {
1392
+ // 我们之前订阅了一个主播,我们想要那个
1393
+ wantedStreamerId = this.subscribedStream;
1394
+ }
1395
+
1396
+ // 现在我们看看能不能选出来。
1397
+ if (wantedStreamerId && messageStreamerList.ids.includes(wantedStreamerId)) {
1398
+ // 如果想要的流在列表中。我们选择它
1399
+ autoSelectedStreamerId = wantedStreamerId;
1400
+ } else if ((!wantedStreamerId || !waitForStreamer) && messageStreamerList.ids.length == 1) {
1401
+ // 否则,如果我们没有等待想要的streamer,而且只有一个streamer,请连接到它
1402
+ autoSelectedStreamerId = messageStreamerList.ids[0];
1403
+ }
1404
+
1405
+ // 如果我们找到了自动选择的streamer id,请选择它
1406
+ if (autoSelectedStreamerId) {
1407
+ this.isReconnecting = false;
1408
+ this.reconnectAttempt = 0;
1409
+ this.config.setOptionSettingValue(
1410
+ OptionParameters.StreamerId,
1411
+ autoSelectedStreamerId
1412
+ );
1413
+ } else {
1414
+ //没有自动选择的streamer。
1415
+ //如果我们正在等待streamer,那么尝试重新连接
1416
+ if (waitForStreamer) {
1417
+ if (this.reconnectAttempt < reconnectLimit) {
1418
+ // still reconnects available
1419
+ this.isReconnecting = true;
1420
+ this.reconnectAttempt++;
1421
+ setTimeout(() => {
1422
+ // console.log(1121);
1423
+ this.webSocketController.requestStreamerList();
1424
+ }, reconnectDelay);
1425
+ } else {
1426
+ // We've exhausted our reconnect attempts, return to main screen
1427
+ this.reconnectAttempt = 0;
1428
+ this.isReconnecting = false;
1429
+ this.shouldReconnect = false;
1430
+ }
1431
+ }
1432
+ }
1433
+
1434
+ // 最后Dispatch这个事件
1435
+ this.pixelStreaming.dispatchEvent(
1436
+ new StreamerListMessageEvent({
1437
+ messageStreamerList,
1438
+ autoSelectedStreamerId,
1439
+ wantedStreamerId
1440
+ })
1441
+ );
1442
+ }
1443
+
1444
+ /**
1445
+ * 处理发信服务器的RTC应答
1446
+ * @param Answer - Answer SDP from the peer.
1447
+ */
1448
+ handleWebRtcAnswer(Answer: MessageAnswer) {
1449
+ Logger.Log(Logger.GetStackTrace(), `Got answer sdp ${Answer.sdp}`, 6);
1450
+
1451
+ const sdpAnswer: RTCSessionDescriptionInit = {
1452
+ sdp: Answer.sdp,
1453
+ type: 'answer'
1454
+ };
1455
+
1456
+ this.peerConnectionController.receiveAnswer(sdpAnswer);
1457
+ this.handlePostWebrtcNegotiation();
1458
+ }
1459
+
1460
+ /**
1461
+ * Handle the RTC offer from a WebRTC peer (received through the signalling server).
1462
+ * @param Offer - Offer SDP from the peer.
1463
+ */
1464
+ handleWebRtcOffer(Offer: MessageOffer) {
1465
+ Logger.Log(Logger.GetStackTrace(), `Got offer sdp ${Offer.sdp}`, 6);
1466
+
1467
+ this.isUsingSFU = Offer.sfu ? Offer.sfu : false;
1468
+ if (this.isUsingSFU) {
1469
+ // Disable negotiating with the sfu as the sfu only supports one codec at a time
1470
+ this.peerConnectionController.preferredCodec = '';
1471
+ }
1472
+
1473
+ const sdpOffer: RTCSessionDescriptionInit = {
1474
+ sdp: Offer.sdp,
1475
+ type: 'offer'
1476
+ };
1477
+
1478
+ this.peerConnectionController.receiveOffer(sdpOffer, this.config);
1479
+ this.handlePostWebrtcNegotiation();
1480
+ }
1481
+
1482
+ /**
1483
+ * Handle when the SFU provides the peer with its data channels
1484
+ * @param DataChannels - The message from the SFU containing the data channels ids
1485
+ */
1486
+ handleWebRtcSFUPeerDatachannels(
1487
+ DataChannels: MessageReceive.MessagePeerDataChannels
1488
+ ) {
1489
+ const SendOptions: RTCDataChannelInit = {
1490
+ ordered: true,
1491
+ negotiated: true,
1492
+ id: DataChannels.sendStreamId
1493
+ };
1494
+
1495
+ const unidirectional =
1496
+ DataChannels.sendStreamId != DataChannels.recvStreamId;
1497
+
1498
+ this.sendrecvDataChannelController.createDataChannel(
1499
+ this.peerConnectionController.peerConnection,
1500
+ unidirectional ? 'send-datachannel' : 'datachannel',
1501
+ SendOptions
1502
+ );
1503
+
1504
+ if (unidirectional) {
1505
+ const RecvOptions: RTCDataChannelInit = {
1506
+ ordered: true,
1507
+ negotiated: true,
1508
+ id: DataChannels.recvStreamId
1509
+ };
1510
+
1511
+ this.recvDataChannelController.createDataChannel(
1512
+ this.peerConnectionController.peerConnection,
1513
+ 'recv-datachannel',
1514
+ RecvOptions
1515
+ );
1516
+ this.recvDataChannelController.handleOnOpen = () =>
1517
+ this.webSocketController.sendSFURecvDataChannelReady();
1518
+ // If we're uni-directional, only the recv data channel should handle incoming messages
1519
+ this.recvDataChannelController.handleOnMessage = (
1520
+ ev: MessageEvent
1521
+ ) => this.handleOnMessage(ev);
1522
+ } else {
1523
+ // else our primary datachannel is send/recv so it can handle incoming messages
1524
+ this.sendrecvDataChannelController.handleOnMessage = (
1525
+ ev: MessageEvent
1526
+ ) => this.handleOnMessage(ev);
1527
+ }
1528
+ }
1529
+
1530
+ handlePostWebrtcNegotiation() {
1531
+ // start the afk warning timer as PS is now running
1532
+ this.afkController.startAfkWarningTimer();
1533
+ // show the overlay that we have negotiated a connection
1534
+ this.pixelStreaming._onWebRtcSdp();
1535
+
1536
+ if (this.statsTimerHandle && this.statsTimerHandle !== undefined) {
1537
+ window.clearInterval(this.statsTimerHandle);
1538
+ }
1539
+
1540
+ this.statsTimerHandle = window.setInterval(() => this.getStats(), 1000);
1541
+
1542
+ /* */
1543
+ this.setMouseInputEnabled(this.config.isFlagEnabled(Flags.MouseInput));
1544
+ this.setKeyboardInputEnabled(this.config.isFlagEnabled(Flags.KeyboardInput));
1545
+ this.setGamePadInputEnabled(this.config.isFlagEnabled(Flags.GamepadInput));
1546
+ }
1547
+
1548
+ /**
1549
+ * When an ice Candidate is received from the Signaling server add it to the Peer Connection Client
1550
+ * @param iceCandidate - Ice Candidate from Server
1551
+ */
1552
+ handleIceCandidate(iceCandidate: RTCIceCandidateInit) {
1553
+ Logger.Log(
1554
+ Logger.GetStackTrace(),
1555
+ 'Web RTC Controller: onWebRtcIce',
1556
+ 6
1557
+ );
1558
+
1559
+ const candidate = new RTCIceCandidate(iceCandidate);
1560
+ this.peerConnectionController.handleOnIce(candidate);
1561
+ }
1562
+
1563
+ /**
1564
+ * Send the ice Candidate to the signaling server via websocket
1565
+ * @param iceEvent - RTC Peer ConnectionIceEvent) {
1566
+ */
1567
+ handleSendIceCandidate(iceEvent: RTCPeerConnectionIceEvent) {
1568
+ Logger.Log(Logger.GetStackTrace(), 'OnIceCandidate', 6);
1569
+ if (iceEvent.candidate && iceEvent.candidate.candidate) {
1570
+ this.webSocketController.sendIceCandidate(iceEvent.candidate);
1571
+ }
1572
+ }
1573
+
1574
+ /**
1575
+ * Send the ice Candidate to the signaling server via websocket
1576
+ * @param iceEvent - RTC Peer ConnectionIceEvent) {
1577
+ */
1578
+ handleDataChannel(datachannelEvent: RTCDataChannelEvent) {
1579
+ Logger.Log(
1580
+ Logger.GetStackTrace(),
1581
+ 'Data channel created for us by browser as we are a receiving peer.',
1582
+ 6
1583
+ );
1584
+ this.sendrecvDataChannelController.dataChannel =
1585
+ datachannelEvent.channel;
1586
+ // Data channel was created for us, so we just need to setup its callbacks and array type
1587
+ this.sendrecvDataChannelController.setupDataChannel();
1588
+ this.sendrecvDataChannelController.handleOnMessage = (
1589
+ ev: MessageEvent<ArrayBuffer>
1590
+ ) => this.handleOnMessage(ev);
1591
+ }
1592
+
1593
+ /**
1594
+ * Send the RTC Offer Session to the Signaling server via websocket
1595
+ * @param offer - RTC Session Description
1596
+ */
1597
+ handleSendWebRTCOffer(offer: RTCSessionDescriptionInit) {
1598
+ Logger.Log(
1599
+ Logger.GetStackTrace(),
1600
+ 'Sending the offer to the Server',
1601
+ 6
1602
+ );
1603
+ this.webSocketController.sendWebRtcOffer(offer);
1604
+ }
1605
+
1606
+ /**
1607
+ * Send the RTC Offer Session to the Signaling server via websocket
1608
+ * @param answer - RTC Session Description
1609
+ */
1610
+ handleSendWebRTCAnswer(answer: RTCSessionDescriptionInit) {
1611
+ Logger.Log(
1612
+ Logger.GetStackTrace(),
1613
+ 'Sending the answer to the Server',
1614
+ 6
1615
+ );
1616
+ this.webSocketController.sendWebRtcAnswer(answer);
1617
+
1618
+ if (this.isUsingSFU) {
1619
+ this.webSocketController.sendWebRtcDatachannelRequest();
1620
+ }
1621
+ }
1622
+
1623
+ /**
1624
+ * Set the freeze frame overlay to the player div
1625
+ */
1626
+ setUpMouseAndFreezeFrame() {
1627
+ // Calculating and normalizing positions depends on the width and height of the player.
1628
+ this.videoElementParentClientRect = this.videoPlayer
1629
+ .getVideoParentElement()
1630
+ .getBoundingClientRect();
1631
+ this.coordinateConverter.setupNormalizeAndQuantize();
1632
+ this.freezeFrameController.freezeFrame.resize();
1633
+ }
1634
+
1635
+ /**
1636
+ * 关闭到发信服务器的连接
1637
+ */
1638
+ closeSignalingServer(message: string) {
1639
+ // We explicitly called close, therefore we don't want to trigger auto reconnect
1640
+ this.locallyClosed = true;
1641
+ this.shouldReconnect = false;
1642
+ this.disconnectMessage = message;
1643
+ this.webSocketController?.close();
1644
+ }
1645
+
1646
+ /**
1647
+ * 关闭对端连接
1648
+ */
1649
+ closePeerConnection() {
1650
+ this.peerConnectionController?.close();
1651
+ }
1652
+
1653
+ /**
1654
+ * 关闭所有连接
1655
+ */
1656
+ close() {
1657
+ this.closeSignalingServer('');
1658
+ this.closePeerConnection();
1659
+ }
1660
+
1661
+ /**
1662
+ * Fires a Video Stats Event in the RTC Peer Connection
1663
+ */
1664
+ getStats() {
1665
+ this.peerConnectionController.generateStats();
1666
+ }
1667
+
1668
+ /**
1669
+ * 向UE实例发送时延测试请求
1670
+ */
1671
+ sendLatencyTest() {
1672
+ this.latencyStartTime = Date.now();
1673
+
1674
+ this.streamMessageController.toStreamerHandlers.get(
1675
+ 'LatencyTest'
1676
+ )([JSON.stringify({
1677
+ StartTime: this.latencyStartTime
1678
+ })]);
1679
+ }
1680
+
1681
+ /**
1682
+ * Send a Data Channel Latency Test Request to the UE Instance
1683
+ */
1684
+ sendDataChannelLatencyTest(descriptor: DataChannelLatencyTestRequest) {
1685
+ this.streamMessageController.toStreamerHandlers.get(
1686
+ 'DataChannelLatencyTest'
1687
+ )([JSON.stringify(descriptor)]);
1688
+ }
1689
+
1690
+ /**
1691
+ * Send the MinQP encoder setting to the UE Instance.
1692
+ * @param minQP - The lower bound for QP when encoding
1693
+ * valid values are (1-51) where:
1694
+ * 1 = Best quality but highest bitrate.
1695
+ * 51 = Worst quality but lowest bitrate.
1696
+ * By default the minQP is 1 meaning the encoder is free
1697
+ * to aim for the best quality it can on the given network link.
1698
+ */
1699
+ sendEncoderMinQP(minQP: number) {
1700
+ Logger.Log(Logger.GetStackTrace(), `MinQP=${minQP}\n`, 6);
1701
+
1702
+ if (minQP != null) {
1703
+ this.streamMessageController.toStreamerHandlers.get(
1704
+ 'Command'
1705
+ )([JSON.stringify({
1706
+ 'Encoder.MinQP': minQP
1707
+ })]);
1708
+ }
1709
+ }
1710
+
1711
+ /**
1712
+ * Send the MaxQP encoder setting to the UE Instance.
1713
+ * @param maxQP - The upper bound for QP when encoding
1714
+ * valid values are (1-51) where:
1715
+ * 1 = Best quality but highest bitrate.
1716
+ * 51 = Worst quality but lowest bitrate.
1717
+ * By default the maxQP is 51 meaning the encoder is free
1718
+ * to drop quality as low as needed on the given network link.
1719
+ */
1720
+ sendEncoderMaxQP(maxQP: number) {
1721
+ Logger.Log(Logger.GetStackTrace(), `MaxQP=${maxQP}\n`, 6);
1722
+
1723
+ if (maxQP != null) {
1724
+ this.streamMessageController.toStreamerHandlers.get(
1725
+ 'Command'
1726
+ )([JSON.stringify({
1727
+ 'Encoder.MaxQP': maxQP
1728
+ })]);
1729
+ }
1730
+ }
1731
+
1732
+ /**
1733
+ * Send the { WebRTC.MinBitrate: SomeNumber }} command to UE to set
1734
+ * the minimum bitrate that we allow WebRTC to use
1735
+ * (note setting this too high in poor networks can be problematic).
1736
+ * @param minBitrate - The minimum bitrate we would like WebRTC to not fall below.
1737
+ */
1738
+ sendWebRTCMinBitrate(minBitrate: number) {
1739
+ Logger.Log(Logger.GetStackTrace(), `WebRTC Min Bitrate=${minBitrate}`, 6);
1740
+ if (minBitrate != null) {
1741
+ this.streamMessageController.toStreamerHandlers.get(
1742
+ 'Command'
1743
+ )([JSON.stringify({
1744
+ 'WebRTC.MinBitrate': minBitrate
1745
+ })]);
1746
+ }
1747
+ }
1748
+
1749
+ /**
1750
+ * Send the { WebRTC.MaxBitrate: SomeNumber }} command to UE to set
1751
+ * the minimum bitrate that we allow WebRTC to use
1752
+ * (note setting this too low could result in blocky video).
1753
+ * @param minBitrate - The minimum bitrate we would like WebRTC to not fall below.
1754
+ */
1755
+ sendWebRTCMaxBitrate(maxBitrate: number) {
1756
+ Logger.Log(Logger.GetStackTrace(), `WebRTC Max Bitrate=${maxBitrate}`, 6);
1757
+ if (maxBitrate != null) {
1758
+ this.streamMessageController.toStreamerHandlers.get(
1759
+ 'Command'
1760
+ )([JSON.stringify({
1761
+ 'WebRTC.MaxBitrate': maxBitrate
1762
+ })]);
1763
+ }
1764
+ }
1765
+
1766
+ /**
1767
+ * Send the { WebRTC.Fps: SomeNumber }} UE 5.0+
1768
+ * and { WebRTC.MaxFps } UE 4.27 command to set
1769
+ * the maximum fps we would like WebRTC to stream at.
1770
+ * @param fps - The maximum stream fps.
1771
+ */
1772
+ sendWebRTCFps(fps: number) {
1773
+ Logger.Log(Logger.GetStackTrace(), `WebRTC FPS=${fps}`, 6);
1774
+ if (fps != null) {
1775
+ this.streamMessageController.toStreamerHandlers.get(
1776
+ 'Command'
1777
+ )([JSON.stringify({ 'WebRTC.Fps': fps })]);
1778
+
1779
+ /* TODO: Remove when UE 4.27 unsupported. */
1780
+ this.streamMessageController.toStreamerHandlers.get(
1781
+ 'Command'
1782
+ )([JSON.stringify({ 'WebRTC.MaxFps': fps })]);
1783
+ }
1784
+ }
1785
+
1786
+ /**
1787
+ * Sends the UI Descriptor `stat fps` to the UE Instance
1788
+ */
1789
+ sendShowFps(): void {
1790
+ Logger.Log(
1791
+ Logger.GetStackTrace(),
1792
+ '---- Sending show stat to UE ----',
1793
+ 6
1794
+ );
1795
+
1796
+ this.streamMessageController.toStreamerHandlers.get(
1797
+ 'Command'
1798
+ )([JSON.stringify({ 'stat.fps': '' })]);
1799
+ }
1800
+
1801
+ /**
1802
+ * Send an Iframe request to the streamer
1803
+ */
1804
+ sendIframeRequest(): void {
1805
+ Logger.Log(
1806
+ Logger.GetStackTrace(),
1807
+ '---- Sending Request for an IFrame ----',
1808
+ 6
1809
+ );
1810
+ this.streamMessageController.toStreamerHandlers.get('IFrameRequest')();
1811
+ }
1812
+
1813
+ /**
1814
+ * Send a UIInteraction message
1815
+ */
1816
+ emitUIInteraction(descriptor: object | string) {
1817
+ Logger.Log(
1818
+ Logger.GetStackTrace(),
1819
+ '---- Sending custom UIInteraction message ----',
1820
+ 6
1821
+ );
1822
+
1823
+ this.streamMessageController.toStreamerHandlers.get(
1824
+ 'UIInteraction'
1825
+ )([JSON.stringify(descriptor)]);
1826
+ }
1827
+
1828
+ /**
1829
+ * Send a Command message
1830
+ */
1831
+ emitCommand(descriptor: object) {
1832
+ Logger.Log(
1833
+ Logger.GetStackTrace(),
1834
+ '---- Sending custom Command message ----',
1835
+ 6
1836
+ );
1837
+
1838
+ this.streamMessageController.toStreamerHandlers.get(
1839
+ 'Command'
1840
+ )([JSON.stringify(descriptor)]);
1841
+ }
1842
+
1843
+ /**
1844
+ * Send a console command message
1845
+ */
1846
+ emitConsoleCommand(command: string) {
1847
+ Logger.Log(
1848
+ Logger.GetStackTrace(),
1849
+ '---- Sending custom Command:ConsoleCommand message ----',
1850
+ 6
1851
+ );
1852
+
1853
+ this.streamMessageController.toStreamerHandlers.get(
1854
+ 'Command'
1855
+ )([JSON.stringify({
1856
+ ConsoleCommand: command,
1857
+ })]);
1858
+ }
1859
+
1860
+ /**
1861
+ * Sends a request to the UE Instance to have ownership of Quality
1862
+ */
1863
+ sendRequestQualityControlOwnership(): void {
1864
+ Logger.Log(
1865
+ Logger.GetStackTrace(),
1866
+ '---- Sending Request to Control Quality ----',
1867
+ 6
1868
+ );
1869
+ this.toStreamerMessagesController.SendRequestQualityControl();
1870
+ }
1871
+
1872
+ /**
1873
+ * Handles when a Latency Test Result are received from the UE Instance
1874
+ * @param message - Latency Test Timings
1875
+ */
1876
+ handleLatencyTestResult(message: ArrayBuffer) {
1877
+ Logger.Log(
1878
+ Logger.GetStackTrace(),
1879
+ 'DataChannelReceiveMessageType.latencyTest',
1880
+ 6
1881
+ );
1882
+ const latencyAsString = new TextDecoder('utf-16').decode(
1883
+ message.slice(1)
1884
+ );
1885
+ const latencyTestResults: LatencyTestResults = new LatencyTestResults();
1886
+ Object.assign(latencyTestResults, JSON.parse(latencyAsString));
1887
+ latencyTestResults.processFields();
1888
+
1889
+ latencyTestResults.testStartTimeMs = this.latencyStartTime;
1890
+ latencyTestResults.browserReceiptTimeMs = Date.now();
1891
+
1892
+ latencyTestResults.latencyExcludingDecode = ~~(
1893
+ latencyTestResults.browserReceiptTimeMs -
1894
+ latencyTestResults.testStartTimeMs
1895
+ );
1896
+ latencyTestResults.testDuration = ~~(
1897
+ latencyTestResults.TransmissionTimeMs -
1898
+ latencyTestResults.ReceiptTimeMs
1899
+ );
1900
+ latencyTestResults.networkLatency = ~~(
1901
+ latencyTestResults.latencyExcludingDecode -
1902
+ latencyTestResults.testDuration
1903
+ );
1904
+
1905
+ if (
1906
+ latencyTestResults.frameDisplayDeltaTimeMs &&
1907
+ latencyTestResults.browserReceiptTimeMs
1908
+ ) {
1909
+ latencyTestResults.endToEndLatency =
1910
+ ~~(latencyTestResults.frameDisplayDeltaTimeMs +
1911
+ latencyTestResults.networkLatency,
1912
+ +latencyTestResults.CaptureToSendMs);
1913
+ }
1914
+ this.pixelStreaming._onLatencyTestResult(latencyTestResults);
1915
+ }
1916
+
1917
+ /**
1918
+ * Handles when a Data Channel Latency Test Response is received from the UE Instance
1919
+ * @param message - Data Channel Latency Test Response
1920
+ */
1921
+ handleDataChannelLatencyTestResponse(message: ArrayBuffer) {
1922
+ Logger.Log(
1923
+ Logger.GetStackTrace(),
1924
+ 'DataChannelReceiveMessageType.dataChannelLatencyResponse',
1925
+ 6
1926
+ );
1927
+ const responseAsString = new TextDecoder('utf-16').decode(
1928
+ message.slice(1)
1929
+ );
1930
+ const latencyTestResponse: DataChannelLatencyTestResponse = JSON.parse(responseAsString);
1931
+ this.pixelStreaming._onDataChannelLatencyTestResponse(latencyTestResponse);
1932
+ }
1933
+
1934
+ /**
1935
+ * Handles when the Encoder and Web RTC Settings are received from the UE Instance
1936
+ * @param message - Initial Encoder and Web RTC Settings
1937
+ */
1938
+ handleInitialSettings(message: ArrayBuffer) {
1939
+ Logger.Log(
1940
+ Logger.GetStackTrace(),
1941
+ 'DataChannelReceiveMessageType.InitialSettings',
1942
+ 6
1943
+ );
1944
+ const payloadAsString = new TextDecoder('utf-16').decode(
1945
+ message.slice(1)
1946
+ );
1947
+ const parsedInitialSettings = JSON.parse(payloadAsString);
1948
+
1949
+ const initialSettings: InitialSettings = new InitialSettings();
1950
+
1951
+ if (parsedInitialSettings.Encoder) {
1952
+ initialSettings.EncoderSettings = parsedInitialSettings.Encoder;
1953
+ }
1954
+
1955
+ if (parsedInitialSettings.WebRTC) {
1956
+ initialSettings.WebRTCSettings = parsedInitialSettings.WebRTC;
1957
+ }
1958
+
1959
+ if (parsedInitialSettings.PixelStreaming) {
1960
+ initialSettings.PixelStreamingSettings =
1961
+ parsedInitialSettings.PixelStreaming;
1962
+ }
1963
+
1964
+ if (parsedInitialSettings.ConfigOptions && parsedInitialSettings.ConfigOptions.DefaultToHover !== undefined) {
1965
+ this.config.setFlagEnabled(
1966
+ Flags.HoveringMouseMode,
1967
+ !!parsedInitialSettings.ConfigOptions.DefaultToHover
1968
+ );
1969
+ }
1970
+
1971
+ initialSettings.ueCompatible();
1972
+ Logger.Log(Logger.GetStackTrace(), payloadAsString, 6);
1973
+
1974
+ this.pixelStreaming._onInitialSettings(initialSettings);
1975
+ }
1976
+
1977
+ /**
1978
+ * Handles when the Quantization Parameter are received from the UE Instance
1979
+ * @param message - Encoders Quantization Parameter
1980
+ */
1981
+ handleVideoEncoderAvgQP(message: ArrayBuffer) {
1982
+ Logger.Log(
1983
+ Logger.GetStackTrace(),
1984
+ 'DataChannelReceiveMessageType.VideoEncoderAvgQP',
1985
+ 6
1986
+ );
1987
+ const AvgQP = Number(
1988
+ new TextDecoder('utf-16').decode(message.slice(1))
1989
+ );
1990
+ this.setVideoEncoderAvgQP(AvgQP);
1991
+ }
1992
+
1993
+ /**
1994
+ * Handles when the video element has been loaded with a srcObject
1995
+ */
1996
+ handleVideoInitialized() {
1997
+ this.pixelStreaming._onVideoInitialized();
1998
+
1999
+ // either autoplay the video or set up the play overlay
2000
+ this.autoPlayVideoOrSetUpPlayOverlay();
2001
+ this.resizePlayerStyle();
2002
+ this.videoPlayer.updateVideoStreamSize();
2003
+ }
2004
+
2005
+ /**
2006
+ * Flag set if the user has Quality Ownership
2007
+ * @param message - Does the current client have Quality Ownership
2008
+ */
2009
+ onQualityControlOwnership(message: ArrayBuffer) {
2010
+ const view = new Uint8Array(message);
2011
+ Logger.Log(
2012
+ Logger.GetStackTrace(),
2013
+ 'DataChannelReceiveMessageType.QualityControlOwnership',
2014
+ 6
2015
+ );
2016
+ this.isQualityController = new Boolean(view[1]).valueOf();
2017
+ Logger.Log(
2018
+ Logger.GetStackTrace(),
2019
+ `Received quality controller message, will control quality: ${this.isQualityController}`
2020
+ );
2021
+ this.pixelStreaming._onQualityControlOwnership(
2022
+ this.isQualityController
2023
+ );
2024
+ }
2025
+
2026
+ /**
2027
+ * Handles when the Aggregated stats are Collected
2028
+ * @param stats - Aggregated Stats
2029
+ */
2030
+ handleVideoStats(stats: AggregatedStats) {
2031
+ this.pixelStreaming._onVideoStats(stats);
2032
+ }
2033
+
2034
+ /**
2035
+ * To Resize the Video Player element
2036
+ */
2037
+ resizePlayerStyle(): void {
2038
+ this.videoPlayer.resizePlayerStyle();
2039
+ }
2040
+
2041
+ setPreferredCodec(codec: string) {
2042
+ this.preferredCodec = codec;
2043
+ if (this.peerConnectionController) {
2044
+ this.peerConnectionController.preferredCodec = codec;
2045
+ this.peerConnectionController.updateCodecSelection = false;
2046
+ }
2047
+ }
2048
+
2049
+ setVideoEncoderAvgQP(avgQP: number) {
2050
+ this.videoAvgQp = avgQP;
2051
+ this.pixelStreaming._onVideoEncoderAvgQP(this.videoAvgQp);
2052
+ }
2053
+
2054
+ /**
2055
+ * enables/disables keyboard event listeners
2056
+ */
2057
+ setKeyboardInputEnabled(isEnabled: boolean) {
2058
+ this.keyboardController?.unregisterKeyBoardEvents();
2059
+ if (isEnabled) {
2060
+ this.keyboardController = this.inputClassesFactory.registerKeyBoard(
2061
+ this.config
2062
+ );
2063
+ }
2064
+ }
2065
+
2066
+ /**
2067
+ * enables/disables mouse event listeners
2068
+ */
2069
+ setMouseInputEnabled(isEnabled: boolean) {
2070
+ this.mouseController?.unregisterMouseEvents();
2071
+ if (isEnabled) {
2072
+ const mouseMode = this.config.isFlagEnabled(Flags.HoveringMouseMode)
2073
+ ? ControlSchemeType.HoveringMouse
2074
+ : ControlSchemeType.LockedMouse;
2075
+ this.mouseController =
2076
+ this.inputClassesFactory.registerMouse(mouseMode);
2077
+ }
2078
+ }
2079
+
2080
+ /**
2081
+ * enables/disables touch event listeners
2082
+ */
2083
+ setTouchInputEnabled(isEnabled: boolean) {
2084
+ this.touchController?.unregisterTouchEvents();
2085
+ if (isEnabled) {
2086
+ this.touchController = this.inputClassesFactory.registerTouch(
2087
+ this.config.isFlagEnabled(Flags.FakeMouseWithTouches),
2088
+ this.videoElementParentClientRect
2089
+ );
2090
+ }
2091
+ }
2092
+
2093
+ /**
2094
+ * enables/disables game pad event listeners
2095
+ */
2096
+ setGamePadInputEnabled(isEnabled: boolean) {
2097
+ this.gamePadController?.unregisterGamePadEvents();
2098
+ if (isEnabled) {
2099
+ this.gamePadController = this.inputClassesFactory.registerGamePad();
2100
+ this.gamePadController.onGamepadConnected = () => {
2101
+ this.streamMessageController.toStreamerHandlers.get('GamepadConnected')();
2102
+ }
2103
+ this.gamePadController.onGamepadDisconnected = (controllerIdx: number) => {
2104
+ this.streamMessageController.toStreamerHandlers.get('GamepadDisconnected')([controllerIdx]);
2105
+ }
2106
+ }
2107
+ }
2108
+
2109
+ registerDataChannelEventEmitters(dataChannel: DataChannelController) {
2110
+ dataChannel.onOpen = (label, event) =>
2111
+ this.pixelStreaming.dispatchEvent(
2112
+ new DataChannelOpenEvent({ label, event })
2113
+ );
2114
+ dataChannel.onClose = (label, event) =>
2115
+ this.pixelStreaming.dispatchEvent(
2116
+ new DataChannelCloseEvent({ label, event })
2117
+ );
2118
+ dataChannel.onError = (label, event) =>
2119
+ this.pixelStreaming.dispatchEvent(
2120
+ new DataChannelErrorEvent({ label, event })
2121
+ );
2122
+ }
2123
+
2124
+ public registerMessageHandler(name: string, direction: MessageDirection, handler?: (data: ArrayBuffer | Array<number | string>) => void) {
2125
+ if (direction === MessageDirection.FromStreamer && typeof handler === 'undefined') {
2126
+ Logger.Warning(
2127
+ Logger.GetStackTrace(),
2128
+ `Unable to register handler for ${name} as no handler was passed`
2129
+ );
2130
+ }
2131
+
2132
+
2133
+ this.streamMessageController.registerMessageHandler(
2134
+ direction,
2135
+ name,
2136
+ (data: Array<number | string>) => (typeof handler === 'undefined' && direction === MessageDirection.ToStreamer) ?
2137
+ this.sendMessageController.sendMessageToStreamer(
2138
+ name,
2139
+ data
2140
+ ) :
2141
+ handler(data)
2142
+ );
2143
+ }
2144
+ }