@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 @@
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("sdp")):"function"==typeof define&&define.amd?define(["sdp"],t):"object"==typeof exports?exports["lib-pixelstreamingfrontend"]=t(require("sdp")):e["lib-pixelstreamingfrontend"]=t(e.sdp)}(this,(e=>(()=>{"use strict";var t={187:e=>{var t,s="object"==typeof Reflect?Reflect:null,n=s&&"function"==typeof s.apply?s.apply:function(e,t,s){return Function.prototype.apply.call(e,t,s)};t=s&&"function"==typeof s.ownKeys?s.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};var r=Number.isNaN||function(e){return e!=e};function i(){i.init.call(this)}e.exports=i,e.exports.once=function(e,t){return new Promise((function(s,n){function r(s){e.removeListener(t,i),n(s)}function i(){"function"==typeof e.removeListener&&e.removeListener("error",r),s([].slice.call(arguments))}p(e,t,i,{once:!0}),"error"!==t&&function(e,t,s){"function"==typeof e.on&&p(e,"error",t,{once:!0})}(e,r)}))},i.EventEmitter=i,i.prototype._events=void 0,i.prototype._eventsCount=0,i.prototype._maxListeners=void 0;var o=10;function a(e){if("function"!=typeof e)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}function l(e){return void 0===e._maxListeners?i.defaultMaxListeners:e._maxListeners}function d(e,t,s,n){var r,i,o,d;if(a(s),void 0===(i=e._events)?(i=e._events=Object.create(null),e._eventsCount=0):(void 0!==i.newListener&&(e.emit("newListener",t,s.listener?s.listener:s),i=e._events),o=i[t]),void 0===o)o=i[t]=s,++e._eventsCount;else if("function"==typeof o?o=i[t]=n?[s,o]:[o,s]:n?o.unshift(s):o.push(s),(r=l(e))>0&&o.length>r&&!o.warned){o.warned=!0;var c=new Error("Possible EventEmitter memory leak detected. "+o.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");c.name="MaxListenersExceededWarning",c.emitter=e,c.type=t,c.count=o.length,d=c,console&&console.warn&&console.warn(d)}return e}function c(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function h(e,t,s){var n={fired:!1,wrapFn:void 0,target:e,type:t,listener:s},r=c.bind(n);return r.listener=s,n.wrapFn=r,r}function u(e,t,s){var n=e._events;if(void 0===n)return[];var r=n[t];return void 0===r?[]:"function"==typeof r?s?[r.listener||r]:[r]:s?function(e){for(var t=new Array(e.length),s=0;s<t.length;++s)t[s]=e[s].listener||e[s];return t}(r):m(r,r.length)}function g(e){var t=this._events;if(void 0!==t){var s=t[e];if("function"==typeof s)return 1;if(void 0!==s)return s.length}return 0}function m(e,t){for(var s=new Array(t),n=0;n<t;++n)s[n]=e[n];return s}function p(e,t,s,n){if("function"==typeof e.on)n.once?e.once(t,s):e.on(t,s);else{if("function"!=typeof e.addEventListener)throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type '+typeof e);e.addEventListener(t,(function r(i){n.once&&e.removeEventListener(t,r),s(i)}))}}Object.defineProperty(i,"defaultMaxListeners",{enumerable:!0,get:function(){return o},set:function(e){if("number"!=typeof e||e<0||r(e))throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received '+e+".");o=e}}),i.init=function(){void 0!==this._events&&this._events!==Object.getPrototypeOf(this)._events||(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0},i.prototype.setMaxListeners=function(e){if("number"!=typeof e||e<0||r(e))throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received '+e+".");return this._maxListeners=e,this},i.prototype.getMaxListeners=function(){return l(this)},i.prototype.emit=function(e){for(var t=[],s=1;s<arguments.length;s++)t.push(arguments[s]);var r="error"===e,i=this._events;if(void 0!==i)r=r&&void 0===i.error;else if(!r)return!1;if(r){var o;if(t.length>0&&(o=t[0]),o instanceof Error)throw o;var a=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw a.context=o,a}var l=i[e];if(void 0===l)return!1;if("function"==typeof l)n(l,this,t);else{var d=l.length,c=m(l,d);for(s=0;s<d;++s)n(c[s],this,t)}return!0},i.prototype.addListener=function(e,t){return d(this,e,t,!1)},i.prototype.on=i.prototype.addListener,i.prototype.prependListener=function(e,t){return d(this,e,t,!0)},i.prototype.once=function(e,t){return a(t),this.on(e,h(this,e,t)),this},i.prototype.prependOnceListener=function(e,t){return a(t),this.prependListener(e,h(this,e,t)),this},i.prototype.removeListener=function(e,t){var s,n,r,i,o;if(a(t),void 0===(n=this._events))return this;if(void 0===(s=n[e]))return this;if(s===t||s.listener===t)0==--this._eventsCount?this._events=Object.create(null):(delete n[e],n.removeListener&&this.emit("removeListener",e,s.listener||t));else if("function"!=typeof s){for(r=-1,i=s.length-1;i>=0;i--)if(s[i]===t||s[i].listener===t){o=s[i].listener,r=i;break}if(r<0)return this;0===r?s.shift():function(e,t){for(;t+1<e.length;t++)e[t]=e[t+1];e.pop()}(s,r),1===s.length&&(n[e]=s[0]),void 0!==n.removeListener&&this.emit("removeListener",e,o||t)}return this},i.prototype.off=i.prototype.removeListener,i.prototype.removeAllListeners=function(e){var t,s,n;if(void 0===(s=this._events))return this;if(void 0===s.removeListener)return 0===arguments.length?(this._events=Object.create(null),this._eventsCount=0):void 0!==s[e]&&(0==--this._eventsCount?this._events=Object.create(null):delete s[e]),this;if(0===arguments.length){var r,i=Object.keys(s);for(n=0;n<i.length;++n)"removeListener"!==(r=i[n])&&this.removeAllListeners(r);return this.removeAllListeners("removeListener"),this._events=Object.create(null),this._eventsCount=0,this}if("function"==typeof(t=s[e]))this.removeListener(e,t);else if(void 0!==t)for(n=t.length-1;n>=0;n--)this.removeListener(e,t[n]);return this},i.prototype.listeners=function(e){return u(this,e,!0)},i.prototype.rawListeners=function(e){return u(this,e,!1)},i.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):g.call(e,t)},i.prototype.listenerCount=g,i.prototype.eventNames=function(){return this._eventsCount>0?t(this._events):[]}},366:t=>{t.exports=e}},s={};function n(e){var r=s[e];if(void 0!==r)return r.exports;var i=s[e]={exports:{}};return t[e](i,i.exports,n),i.exports}n.d=(e,t)=>{for(var s in t)n.o(t,s)&&!n.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};return(()=>{n.r(r),n.d(r,{AfkLogic:()=>Fe,AfkTimedOutEvent:()=>W,AfkWarningActivateEvent:()=>G,AfkWarningDeactivateEvent:()=>H,AfkWarningUpdateEvent:()=>z,AggregatedStats:()=>We,CandidatePairStats:()=>_e,CandidateStat:()=>Be,Config:()=>xe,ControlSchemeType:()=>Ae,DataChannelCloseEvent:()=>J,DataChannelErrorEvent:()=>Y,DataChannelLatencyTestResponseEvent:()=>ge,DataChannelLatencyTestResultEvent:()=>me,DataChannelOpenEvent:()=>j,DataChannelStats:()=>Ue,EncoderSettings:()=>Je,EventEmitter:()=>ye,Flags:()=>Ee,HideFreezeFrameEvent:()=>le,InboundAudioStats:()=>Oe,InboundVideoStats:()=>Ie,InitialSettings:()=>Xe,InitialSettingsEvent:()=>pe,LatencyTestResultEvent:()=>ue,LatencyTestResults:()=>Ze,LoadFreezeFrameEvent:()=>ae,Logger:()=>s,MessageDirection:()=>Qe,MessageReceive:()=>e,MessageSend:()=>t,MessageStreamerList:()=>u,NumericParameters:()=>we,OptionParameters:()=>ke,OutBoundVideoStats:()=>Ge,PixelStreaming:()=>Ot,PlayStreamErrorEvent:()=>re,PlayStreamEvent:()=>ie,PlayStreamRejectedEvent:()=>oe,PlayerCountEvent:()=>Te,SettingBase:()=>O,SettingFlag:()=>I,SettingNumber:()=>U,SettingOption:()=>_,SettingText:()=>B,SettingsChangedEvent:()=>ve,SignallingProtocol:()=>x,StatsReceivedEvent:()=>de,StreamLoadingEvent:()=>ee,StreamPreConnectEvent:()=>te,StreamPreDisconnectEvent:()=>se,StreamReconnectEvent:()=>ne,StreamerIDChangedMessageEvent:()=>he,StreamerListMessageEvent:()=>ce,TextParameters:()=>Re,UnquantizedAndDenormalizeUnsigned:()=>wt,VideoEncoderAvgQPEvent:()=>V,VideoInitializedEvent:()=>Z,WebRTCSettings:()=>Ye,WebRtcAutoConnectEvent:()=>K,WebRtcConnectedEvent:()=>q,WebRtcConnectingEvent:()=>Q,WebRtcDisconnectedEvent:()=>X,WebRtcFailedEvent:()=>$,WebRtcPlayerController:()=>Rt,WebRtcSdpEvent:()=>N,WebSocketTransport:()=>l,WebXRController:()=>xt,XrFrameEvent:()=>fe,XrSessionEndedEvent:()=>Ce,XrSessionStartedEvent:()=>Se});var e={};n.r(e),n.d(e,{MessageAnswer:()=>p,MessageAuthRequired:()=>c,MessageConfig:()=>h,MessageIceCandidate:()=>S,MessageOffer:()=>v,MessageOnScreenKeyboard:()=>f,MessagePeerDataChannels:()=>C,MessagePlayerCount:()=>m,MessageRecv:()=>d,MessageRecvTypes:()=>i,MessageStreamerIDChanged:()=>g,MessageStreamerList:()=>u});var t={};n.r(t),n.d(t,{MessageIceCandidate:()=>L,MessageListStreamers:()=>y,MessagePong:()=>w,MessageSFURecvDataChannelReady:()=>k,MessageSend:()=>T,MessageSendTypes:()=>o,MessageSubscribe:()=>E,MessageUnsubscribe:()=>M,MessageWebRTCAnswer:()=>R,MessageWebRTCDatachannelRequest:()=>P,MessageWebRTCOffer:()=>b});class s{static GetStackTrace(){const e=new Error;let t="No Stack Available for this browser";return e.stack&&(t=e.stack.toString().replace(/Error/g,"")),t}static SetLoggerVerbosity(e){null!=this.verboseLogLevel&&(this.verboseLogLevel=e)}static Log(e,t,s){s>this.verboseLogLevel||this.CommonLog("Log",null,t)}static Info(e,t,s){s>this.verboseLogLevel||this.CommonLog("Info",null,t)}static Error(e,t){this.CommonLog("Error",e,t)}static Warning(e,t){this.CommonLog("Warning",null,t)}static CommonLog(e,t,s){t?console.log(`[${e}] - ${s}\nCaller: ${t}`):console.log(`[${e}] - ${s}`)}}s.verboseLogLevel=5;var i,o,a=n(187);class l{constructor(){this.WS_OPEN_STATE=1,this.events=new a.EventEmitter}sendMessage(e){this.webSocket.send(e.payload())}connect(e){s.Log(s.GetStackTrace(),e,6);try{return this.webSocket=new WebSocket(e),this.webSocket.onopen=e=>this.handleOnOpen(),this.webSocket.onerror=e=>this.handleOnError(),this.webSocket.onclose=e=>this.handleOnClose(e),this.webSocket.onmessage=e=>this.handleOnMessage(e),this.webSocket.onmessagebinary=e=>this.handleOnMessageBinary(e),!0}catch(e){return s.Error(e,e),!1}}disconnect(){this.webSocket.close()}isConnected(){return this.webSocket&&this.webSocket.readyState!=WebSocket.CLOSED}handleOnMessageBinary(e){e&&e.data&&e.data.text().then((e=>{const t=new MessageEvent("messageFromBinary",{data:e});this.handleOnMessage(t)})).catch((e=>{s.Error(s.GetStackTrace(),`Failed to parse binary blob from websocket, reason: ${e}`)}))}handleOnMessage(e){if(e.data&&e.data instanceof Blob)return void this.handleOnMessageBinary(e);const t=JSON.parse(e.data);s.Log(s.GetStackTrace(),"received => \n"+JSON.stringify(JSON.parse(e.data),void 0,4),6),this.onMessage(t)}handleOnOpen(){s.Log(s.GetStackTrace(),"Connected to the signalling server via WebSocket",6),this.events.emit("open")}handleOnError(){this.events.emit("error")}handleOnClose(e){s.Log(s.GetStackTrace(),"Disconnected to the signalling server via WebSocket: "+JSON.stringify(e.code)+" - "+e.reason),this.events.emit("close",e)}close(){var e;null===(e=this.webSocket)||void 0===e||e.close()}}!function(e){e.CONFIG="config",e.STREAMER_LIST="streamerList",e.STREAMER_ID_CHANGED="streamerIDChanged",e.PLAYER_COUNT="playerCount",e.OFFER="offer",e.ANSWER="answer",e.ICE_CANDIDATE="iceCandidate",e.PEER_DATA_CHANNELS="peerDataChannels",e.PING="ping",e.WARNING="warning"}(i||(i={}));class d{}class c extends d{}class h extends d{}class u extends d{}class g extends d{}class m extends d{}class p extends d{}class v extends d{}class S extends d{}class C extends d{}class f{}!function(e){e.LIST_STREAMERS="listStreamers",e.SUBSCRIBE="subscribe",e.UNSUBSCRIBE="unsubscribe",e.ICE_CANDIDATE="iceCandidate",e.OFFER="offer",e.ANSWER="answer",e.DATACHANNELREQUEST="dataChannelRequest",e.SFURECVDATACHANNELREADY="peerDataChannelsReady",e.PONG="pong"}(o||(o={}));class T{sendFilter(e,t){return t}payload(){return s.Log(s.GetStackTrace(),"Sending => \n"+JSON.stringify(this,this.sendFilter,4),6),JSON.stringify(this,this.sendFilter)}}class y extends T{constructor(){super(),this.type=o.LIST_STREAMERS}}class E extends T{constructor(e){super(),this.type=o.SUBSCRIBE,this.streamerId=e}}class M extends T{constructor(){super(),this.type=o.UNSUBSCRIBE}}class w extends T{constructor(e){super(),this.type=o.PONG,this.time=e}}class b extends T{constructor(e,t){super(),this.type=o.OFFER,this.minBitrate=0,this.maxBitrate=0,e&&(this.type=e.type,this.sdp=e.sdp,this.minBitrate=t.minBitrateBps,this.maxBitrate=t.maxBitrateBps)}sendFilter(e,t){if("minBitrate"!=e&&"maxBitrate"!=e||!(t<=0))return t}}class R extends T{constructor(e,t){super(),this.type=o.ANSWER,this.minBitrate=0,this.maxBitrate=0,e&&(this.type=e.type,this.sdp=e.sdp,this.minBitrate=t.minBitrateBps,this.maxBitrate=t.maxBitrateBps)}sendFilter(e,t){if("minBitrate"!=e&&"maxBitrate"!=e||!(t<=0))return t}}class P extends T{constructor(){super(),this.type=o.DATACHANNELREQUEST}}class k extends T{constructor(){super(),this.type=o.SFURECVDATACHANNELREADY}}class L extends T{constructor(e){super(),this.type=o.ICE_CANDIDATE,this.candidate=e}}class x{constructor(e){this.transport=e,this.transportEvents=new a.EventEmitter,this.messageHandlers=new a.EventEmitter,e.events.addListener("open",(()=>this.transportEvents.emit("open"))),e.events.addListener("error",(()=>this.transportEvents.emit("error"))),e.events.addListener("close",(e=>this.transportEvents.emit("close",e))),e.onMessage=t=>{if(t.type==i.PING){const t=new w((new Date).getTime());e.sendMessage(t)}this.messageHandlers.emit(t.type,t)}}connect(e){return this.transport.connect(e)}disconnect(){this.transport.disconnect()}isConnected(){return this.transport.isConnected()}sendMessage(e){this.transport.sendMessage(e)}requestStreamerList(){const e=new y;this.transport.sendMessage(e)}sendSubscribe(e){const t=new E(e);this.transport.sendMessage(t)}sendUnsubscribe(){const e=new M;this.transport.sendMessage(e)}sendWebRtcOffer(e,t){const s=new b(e,t);this.transport.sendMessage(s)}sendWebRtcAnswer(e,t){const s=new R(e,t);this.transport.sendMessage(s)}sendWebRtcDatachannelRequest(){const e=new P;this.transport.sendMessage(e)}sendSFURecvDataChannelReady(){const e=new k;this.transport.sendMessage(e)}sendIceCandidate(e){const t=new L(e);this.transport.sendMessage(t)}}class A{constructor(e){this.videoElementProvider=e,this.audioElement=document.createElement("Audio"),this.videoElementProvider.setAudioElement(this.audioElement)}handleOnTrack(e){s.Log(s.GetStackTrace(),"handleOnTrack "+JSON.stringify(e.streams),6);const t=this.videoElementProvider.getVideoElement();if(e.track&&s.Log(s.GetStackTrace(),"Got track - "+e.track.kind+" id="+e.track.id+" readyState="+e.track.readyState,6),"audio"!=e.track.kind)return"video"==e.track.kind&&t.srcObject!==e.streams[0]?(t.srcObject=e.streams[0],void s.Log(s.GetStackTrace(),"Set video source from video track ontrack.")):void 0;this.CreateAudioTrack(e.streams[0])}CreateAudioTrack(e){const t=this.videoElementProvider.getVideoElement();t.srcObject!=e&&t.srcObject&&t.srcObject!==e&&(this.audioElement.srcObject=e,s.Log(s.GetStackTrace(),"Created new audio element to play separate audio stream."))}}class F{constructor(e){this.freezeFrameHeight=0,this.freezeFrameWidth=0,this.rootDiv=e,this.rootElement=document.createElement("div"),this.rootElement.id="freezeFrame",this.rootElement.style.display="none",this.rootElement.style.pointerEvents="none",this.rootElement.style.position="absolute",this.rootElement.style.zIndex="20",this.imageElement=document.createElement("img"),this.imageElement.style.position="absolute",this.rootElement.appendChild(this.imageElement),this.rootDiv.appendChild(this.rootElement)}setElementForShow(){this.rootElement.style.display="block"}setElementForHide(){this.rootElement.style.display="none"}updateImageElementSource(e){const t=btoa(e.reduce(((e,t)=>e+String.fromCharCode(t)),""));this.imageElement.src="data:image/jpeg;base64,"+t}setDimensionsFromElementAndResize(){this.freezeFrameHeight=this.imageElement.naturalHeight,this.freezeFrameWidth=this.imageElement.naturalWidth,this.resize()}resize(){if(0!==this.freezeFrameWidth&&0!==this.freezeFrameHeight){let e=0,t=0,s=0,n=0;const r=this.rootDiv.clientWidth/this.rootDiv.clientHeight,i=this.freezeFrameWidth/this.freezeFrameHeight;r<i?(e=this.rootDiv.clientWidth,t=Math.floor(this.rootDiv.clientWidth/i),s=Math.floor(.5*(this.rootDiv.clientHeight-t)),n=0):(e=Math.floor(this.rootDiv.clientHeight*i),t=this.rootDiv.clientHeight,s=0,n=Math.floor(.5*(this.rootDiv.clientWidth-e))),this.rootElement.style.width=this.rootDiv.offsetWidth+"px",this.rootElement.style.height=this.rootDiv.offsetHeight+"px",this.rootElement.style.left="0px",this.rootElement.style.top="0px",this.imageElement.style.width=e+"px",this.imageElement.style.height=t+"px",this.imageElement.style.left=n+"px",this.imageElement.style.top=s+"px"}}}class D{constructor(e){this.receiving=!1,this.size=0,this.jpeg=void 0,this.valid=!1,this.freezeFrameDelay=50,this.freezeFrame=new F(e)}showFreezeFrame(){this.valid&&this.freezeFrame.setElementForShow()}hideFreezeFrame(){this.valid=!1,this.freezeFrame.setElementForHide()}updateFreezeFrameAndShow(e,t){this.freezeFrame.updateImageElementSource(e),this.freezeFrame.imageElement.onload=()=>{this.freezeFrame.setDimensionsFromElementAndResize(),t()}}processFreezeFrameMessage(e,t){this.receiving||(this.receiving=!0,this.valid=!1,this.size=0,this.jpeg=void 0),this.size=new DataView(e.slice(1,5).buffer).getInt32(0,!0);const n=e.slice(5);if(this.jpeg){const e=new Uint8Array(this.jpeg.length+n.length);e.set(this.jpeg,0),e.set(n,this.jpeg.length),this.jpeg=e}else this.jpeg=n,this.receiving=!0,s.Log(s.GetStackTrace(),`received first chunk of freeze frame: ${this.jpeg.length}/${this.size}`,6);this.jpeg.length===this.size?(this.receiving=!1,this.valid=!0,s.Log(s.GetStackTrace(),`received complete freeze frame ${this.size}`,6),this.updateFreezeFrameAndShow(this.jpeg,t)):this.jpeg.length>this.size&&(s.Error(s.GetStackTrace(),`received bigger freeze frame than advertised: ${this.jpeg.length}/${this.size}`),this.jpeg=void 0,this.receiving=!1)}}class O{constructor(e,t,s,n,r=(()=>{})){this.onChange=r,this.onChangeEmit=()=>{},this.id=e,this.description=s,this.label=t,this.value=n}set label(e){this._label=e,this.onChangeEmit(this._value)}get label(){return this._label}get value(){return this._value}set value(e){this._value=e,this.onChange(this._value,this),this.onChangeEmit(this._value)}}class I extends O{constructor(e,t,s,n,r,i=(()=>{})){super(e,t,s,n,i);const o=new URLSearchParams(window.location.search);if(r&&o.has(this.id)){const e=this.getUrlParamFlag();this.flag=e}else this.flag=n;this.useUrlParams=r}getUrlParamFlag(){const e=new URLSearchParams(window.location.search);return!!e.has(this.id)&&"false"!==e.get(this.id)&&"False"!==e.get(this.id)}updateURLParams(){if(this.useUrlParams){const e=new URLSearchParams(window.location.search);!0===this.flag?e.set(this.id,"true"):e.set(this.id,"false"),window.history.replaceState({},"",""!==e.toString()?`${location.pathname}?${e}`:`${location.pathname}`)}}enable(){this.flag=!0}get flag(){return!!this.value}set flag(e){this.value=e}}class U extends O{constructor(e,t,s,n,r,i,o,a=(()=>{})){super(e,t,s,i,a),this._min=n,this._max=r;const l=new URLSearchParams(window.location.search);if(o&&l.has(this.id)){const e=Number.parseFloat(l.get(this.id));this.number=Number.isNaN(e)?i:e}else this.number=i;this.useUrlParams=o}updateURLParams(){if(this.useUrlParams){const e=new URLSearchParams(window.location.search);e.set(this.id,this.number.toString()),window.history.replaceState({},"",""!==e.toString()?`${location.pathname}?${e}`:`${location.pathname}`)}}set number(e){this.value=this.clamp(e)}get number(){return this.value}clamp(e){return Math.max(Math.min(this._max,e),this._min)}get min(){return this._min}get max(){return this._max}addOnChangedListener(e){this.onChange=e}}class B extends O{constructor(e,t,s,n,r,i=(()=>{})){super(e,t,s,n,i);const o=new URLSearchParams(window.location.search);if(r&&o.has(this.id)){const e=this.getUrlParamText();this.text=e}else this.text=n;this.useUrlParams=r}getUrlParamText(){var e;const t=new URLSearchParams(window.location.search);return t.has(this.id)&&null!==(e=t.get(this.id))&&void 0!==e?e:""}updateURLParams(){if(this.useUrlParams){const e=new URLSearchParams(window.location.search);e.set(this.id,this.text),window.history.replaceState({},"",""!==e.toString()?`${location.pathname}?${e}`:`${location.pathname}`)}}get text(){return this.value}set text(e){this.value=e}}class _ extends O{constructor(e,t,s,n,r,i,o=(()=>{})){super(e,t,s,[n],o),this.options=r;const a=new URLSearchParams(window.location.search),l=i&&a.has(this.id)?this.getUrlParamText():n;this.selected=l,this.useUrlParams=i}getUrlParamText(){var e;const t=new URLSearchParams(window.location.search);return t.has(this.id)&&null!==(e=t.get(this.id))&&void 0!==e?e:""}updateURLParams(){if(this.useUrlParams){const e=new URLSearchParams(window.location.search);e.set(this.id,this.selected),window.history.replaceState({},"",""!==e.toString()?`${location.pathname}?${e}`:`${location.pathname}`)}}addOnChangedListener(e){this.onChange=e}get options(){return this._options}set options(e){this._options=e,this.onChangeEmit(this.selected)}get selected(){return this.value}set selected(e){let t=this.options.filter((t=>-1!==t.indexOf(e)));t.length?this.value=t[0]:(t=this.options.filter((t=>-1!==t.indexOf(e.split(" ")[0]))),t.length&&(this.value=t[0]))}}class G extends Event{constructor(e){super("afkWarningActivate"),this.data=e}}class z extends Event{constructor(e){super("afkWarningUpdate"),this.data=e}}class H extends Event{constructor(){super("afkWarningDeactivate")}}class W extends Event{constructor(){super("afkTimedOut")}}class V extends Event{constructor(e){super("videoEncoderAvgQP"),this.data=e}}class N extends Event{constructor(){super("webRtcSdp")}}class K extends Event{constructor(){super("webRtcAutoConnect")}}class Q extends Event{constructor(){super("webRtcConnecting")}}class q extends Event{constructor(){super("webRtcConnected")}}class $ extends Event{constructor(){super("webRtcFailed")}}class X extends Event{constructor(e){super("webRtcDisconnected"),this.data=e}}class j extends Event{constructor(e){super("dataChannelOpen"),this.data=e}}class J extends Event{constructor(e){super("dataChannelClose"),this.data=e}}class Y extends Event{constructor(e){super("dataChannelError"),this.data=e}}class Z extends Event{constructor(){super("videoInitialized")}}class ee extends Event{constructor(){super("streamLoading")}}class te extends Event{constructor(){super("streamConnect")}}class se extends Event{constructor(){super("streamDisconnect")}}class ne extends Event{constructor(){super("streamReconnect")}}class re extends Event{constructor(e){super("playStreamError"),this.data=e}}class ie extends Event{constructor(){super("playStream")}}class oe extends Event{constructor(e){super("playStreamRejected"),this.data=e}}class ae extends Event{constructor(e){super("loadFreezeFrame"),this.data=e}}class le extends Event{constructor(){super("hideFreezeFrame")}}class de extends Event{constructor(e){super("statsReceived"),this.data=e}}class ce extends Event{constructor(e){super("streamerListMessage"),this.data=e}}class he extends Event{constructor(e){super("StreamerIDChangedMessage"),this.data=e}}class ue extends Event{constructor(e){super("latencyTestResult"),this.data=e}}class ge extends Event{constructor(e){super("dataChannelLatencyTestResponse"),this.data=e}}class me extends Event{constructor(e){super("dataChannelLatencyTestResult"),this.data=e}}class pe extends Event{constructor(e){super("initialSettings"),this.data=e}}class ve extends Event{constructor(e){super("settingsChanged"),this.data=e}}class Se extends Event{constructor(){super("xrSessionStarted")}}class Ce extends Event{constructor(){super("xrSessionEnded")}}class fe extends Event{constructor(e){super("xrFrame"),this.data=e}}class Te extends Event{constructor(e){super("playerCount"),this.data=e}}class ye extends EventTarget{dispatchEvent(e){return super.dispatchEvent(e)}addEventListener(e,t){super.addEventListener(e,t)}removeEventListener(e,t){super.removeEventListener(e,t)}}class Ee{}Ee.AutoConnect="AutoConnect",Ee.AutoPlayVideo="AutoPlayVideo",Ee.AFKDetection="TimeoutIfIdle",Ee.BrowserSendOffer="OfferToReceive",Ee.HoveringMouseMode="HoveringMouse",Ee.ForceMonoAudio="ForceMonoAudio",Ee.ForceTURN="ForceTURN",Ee.FakeMouseWithTouches="FakeMouseWithTouches",Ee.IsQualityController="ControlsQuality",Ee.MatchViewportResolution="MatchViewportRes",Ee.StartVideoMuted="StartVideoMuted",Ee.SuppressBrowserKeys="SuppressBrowserKeys",Ee.UseMic="UseMic",Ee.KeyboardInput="KeyboardInput",Ee.MouseInput="MouseInput",Ee.TouchInput="TouchInput",Ee.GamepadInput="GamepadInput",Ee.XRControllerInput="XRControllerInput",Ee.WaitForStreamer="WaitForStreamer";const Me=e=>Object.getOwnPropertyNames(Ee).some((t=>Ee[t]===e));class we{}we.AFKTimeoutSecs="AFKTimeout",we.MinQP="MinQP",we.MaxQP="MaxQP",we.WebRTCFPS="WebRTCFPS",we.WebRTCMinBitrate="WebRTCMinBitrate",we.WebRTCMaxBitrate="WebRTCMaxBitrate",we.MaxReconnectAttempts="MaxReconnectAttempts",we.StreamerAutoJoinInterval="StreamerAutoJoinInterval";const be=e=>Object.getOwnPropertyNames(we).some((t=>we[t]===e));class Re{}Re.SignallingServerUrl="ss";const Pe=e=>Object.getOwnPropertyNames(Re).some((t=>Re[t]===e));class ke{}ke.PreferredCodec="PreferredCodec",ke.StreamerId="StreamerId";const Le=e=>Object.getOwnPropertyNames(ke).some((t=>ke[t]===e));class xe{constructor(e={}){this.flags=new Map,this.numericParameters=new Map,this.textParameters=new Map,this.optionParameters=new Map;const{initialSettings:t,useUrlParams:s}=e;this._useUrlParams=!!s,this.populateDefaultSettings(this._useUrlParams,t)}get useUrlParams(){return this._useUrlParams}populateDefaultSettings(e,t){this.textParameters.set(Re.SignallingServerUrl,new B(Re.SignallingServerUrl,"Signalling url","Url of the signalling server",t&&t.hasOwnProperty(Re.SignallingServerUrl)?t[Re.SignallingServerUrl]:("https:"===location.protocol?"wss://":"ws://")+window.location.hostname+("80"===window.location.port||""===window.location.port?"":`:${window.location.port}`),e)),this.optionParameters.set(ke.StreamerId,new _(ke.StreamerId,"Streamer ID","The ID of the streamer to stream.",t&&t.hasOwnProperty(ke.StreamerId)?t[ke.StreamerId]:"",[],e)),this.optionParameters.set(ke.PreferredCodec,new _(ke.PreferredCodec,"Preferred Codec","The preferred codec to be used during codec negotiation","H264 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f",t&&t.hasOwnProperty(ke.PreferredCodec)?[t[ke.PreferredCodec]]:function(){const e=[];if(!RTCRtpReceiver.getCapabilities)return e.push("Only available on Chrome"),e;const t=/(VP\d|H26\d|AV1).*/;return RTCRtpReceiver.getCapabilities("video").codecs.forEach((s=>{const n=s.mimeType.split("/")[1]+" "+(s.sdpFmtpLine||"");null!==t.exec(n)&&e.push(n)})),e}(),e)),this.flags.set(Ee.AutoConnect,new I(Ee.AutoConnect,"Auto connect to stream","Whether we should attempt to auto connect to the signalling server or show a click to start prompt.",!(!t||!t.hasOwnProperty(Ee.AutoConnect))&&t[Ee.AutoConnect],e)),this.flags.set(Ee.AutoPlayVideo,new I(Ee.AutoPlayVideo,"Auto play video","When video is ready automatically start playing it as opposed to showing a play button.",!t||!t.hasOwnProperty(Ee.AutoPlayVideo)||t[Ee.AutoPlayVideo],e)),this.flags.set(Ee.BrowserSendOffer,new I(Ee.BrowserSendOffer,"Browser send offer","Browser will initiate the WebRTC handshake by sending the offer to the streamer",!(!t||!t.hasOwnProperty(Ee.BrowserSendOffer))&&t[Ee.BrowserSendOffer],e)),this.flags.set(Ee.UseMic,new I(Ee.UseMic,"Use microphone","Make browser request microphone access and open an input audio track.",!(!t||!t.hasOwnProperty(Ee.UseMic))&&t[Ee.UseMic],e)),this.flags.set(Ee.StartVideoMuted,new I(Ee.StartVideoMuted,"Start video muted","Video will start muted if true.",!(!t||!t.hasOwnProperty(Ee.StartVideoMuted))&&t[Ee.StartVideoMuted],e)),this.flags.set(Ee.SuppressBrowserKeys,new I(Ee.SuppressBrowserKeys,"Suppress browser keys","Suppress certain browser keys that we use in UE, for example F5 to show shader complexity instead of refresh the page.",!t||!t.hasOwnProperty(Ee.SuppressBrowserKeys)||t[Ee.SuppressBrowserKeys],e)),this.flags.set(Ee.IsQualityController,new I(Ee.IsQualityController,"Is quality controller?","True if this peer controls stream quality",!t||!t.hasOwnProperty(Ee.IsQualityController)||t[Ee.IsQualityController],e)),this.flags.set(Ee.ForceMonoAudio,new I(Ee.ForceMonoAudio,"Force mono audio","Force browser to request mono audio in the SDP",!(!t||!t.hasOwnProperty(Ee.ForceMonoAudio))&&t[Ee.ForceMonoAudio],e)),this.flags.set(Ee.ForceTURN,new I(Ee.ForceTURN,"Force TURN","Only generate TURN/Relayed ICE candidates.",!(!t||!t.hasOwnProperty(Ee.ForceTURN))&&t[Ee.ForceTURN],e)),this.flags.set(Ee.AFKDetection,new I(Ee.AFKDetection,"AFK if idle","Timeout the experience if user is AFK for a period.",!(!t||!t.hasOwnProperty(Ee.AFKDetection))&&t[Ee.AFKDetection],e)),this.flags.set(Ee.MatchViewportResolution,new I(Ee.MatchViewportResolution,"Match viewport resolution","Pixel Streaming will be instructed to dynamically resize the video stream to match the size of the video element.",!(!t||!t.hasOwnProperty(Ee.MatchViewportResolution))&&t[Ee.MatchViewportResolution],e)),this.flags.set(Ee.HoveringMouseMode,new I(Ee.HoveringMouseMode,"Control Scheme: Locked Mouse","Either locked mouse, where the pointer is consumed by the video and locked to it, or hovering mouse, where the mouse is not consumed.",!(!t||!t.hasOwnProperty(Ee.HoveringMouseMode))&&t[Ee.HoveringMouseMode],e,((e,t)=>{t.label=`Control Scheme: ${e?"Hovering":"Locked"} Mouse`}))),this.flags.set(Ee.FakeMouseWithTouches,new I(Ee.FakeMouseWithTouches,"Fake mouse with touches","A single finger touch is converted into a mouse event. This allows a non-touch application to be controlled partially via a touch device.",!t||!t.hasOwnProperty(Ee.FakeMouseWithTouches)||t[Ee.FakeMouseWithTouches],e)),this.flags.set(Ee.KeyboardInput,new I(Ee.KeyboardInput,"Keyboard input","If enabled, send keyboard events to streamer",!t||!t.hasOwnProperty(Ee.KeyboardInput)||t[Ee.KeyboardInput],e)),this.flags.set(Ee.MouseInput,new I(Ee.MouseInput,"Mouse input","If enabled, send mouse events to streamer",!t||!t.hasOwnProperty(Ee.MouseInput)||t[Ee.MouseInput],e)),this.flags.set(Ee.TouchInput,new I(Ee.TouchInput,"Touch input","If enabled, send touch events to streamer",!t||!t.hasOwnProperty(Ee.TouchInput)||t[Ee.TouchInput],e)),this.flags.set(Ee.GamepadInput,new I(Ee.GamepadInput,"Gamepad input","If enabled, send gamepad events to streamer",!t||!t.hasOwnProperty(Ee.GamepadInput)||t[Ee.GamepadInput],e)),this.flags.set(Ee.XRControllerInput,new I(Ee.XRControllerInput,"XR controller input","If enabled, send XR controller events to streamer",!t||!t.hasOwnProperty(Ee.XRControllerInput)||t[Ee.XRControllerInput],e)),this.flags.set(Ee.WaitForStreamer,new I(Ee.WaitForStreamer,"Wait for streamer","Will continue trying to connect to the first streamer available.",!t||!t.hasOwnProperty(Ee.WaitForStreamer)||t[Ee.WaitForStreamer],e)),this.numericParameters.set(we.AFKTimeoutSecs,new U(we.AFKTimeoutSecs,"AFK timeout","The time (in seconds) it takes for the application to time out if AFK timeout is enabled.",0,600,t&&t.hasOwnProperty(we.AFKTimeoutSecs)?t[we.AFKTimeoutSecs]:120,e)),this.numericParameters.set(we.MaxReconnectAttempts,new U(we.MaxReconnectAttempts,"Max Reconnects","Maximum number of reconnects the application will attempt when a streamer disconnects.",0,999,t&&t.hasOwnProperty(we.MaxReconnectAttempts)?t[we.MaxReconnectAttempts]:3,e)),this.numericParameters.set(we.MinQP,new U(we.MinQP,"Min QP","The lower bound for the quantization parameter (QP) of the encoder. 0 = Best quality, 51 = worst quality.",0,51,t&&t.hasOwnProperty(we.MinQP)?t[we.MinQP]:0,e)),this.numericParameters.set(we.MaxQP,new U(we.MaxQP,"Max QP","The upper bound for the quantization parameter (QP) of the encoder. 0 = Best quality, 51 = worst quality.",0,51,t&&t.hasOwnProperty(we.MaxQP)?t[we.MaxQP]:51,e)),this.numericParameters.set(we.WebRTCFPS,new U(we.WebRTCFPS,"Max FPS","The maximum FPS that WebRTC will try to transmit frames at.",1,999,t&&t.hasOwnProperty(we.WebRTCFPS)?t[we.WebRTCFPS]:60,e)),this.numericParameters.set(we.WebRTCMinBitrate,new U(we.WebRTCMinBitrate,"Min Bitrate (kbps)","The minimum bitrate that WebRTC should use.",0,5e5,t&&t.hasOwnProperty(we.WebRTCMinBitrate)?t[we.WebRTCMinBitrate]:0,e)),this.numericParameters.set(we.WebRTCMaxBitrate,new U(we.WebRTCMaxBitrate,"Max Bitrate (kbps)","The maximum bitrate that WebRTC should use.",0,5e5,t&&t.hasOwnProperty(we.WebRTCMaxBitrate)?t[we.WebRTCMaxBitrate]:0,e)),this.numericParameters.set(we.StreamerAutoJoinInterval,new U(we.StreamerAutoJoinInterval,"Streamer Auto Join Interval (ms)","Delay between retries when waiting for an available streamer.",500,9e5,t&&t.hasOwnProperty(we.StreamerAutoJoinInterval)?t[we.StreamerAutoJoinInterval]:3e3,e))}_addOnNumericSettingChangedListener(e,t){this.numericParameters.has(e)&&this.numericParameters.get(e).addOnChangedListener(t)}_addOnOptionSettingChangedListener(e,t){this.optionParameters.has(e)&&this.optionParameters.get(e).addOnChangedListener(t)}getNumericSettingValue(e){if(this.numericParameters.has(e))return this.numericParameters.get(e).number;throw new Error(`There is no numeric setting with the id of ${e}`)}getTextSettingValue(e){if(this.textParameters.has(e))return this.textParameters.get(e).value;throw new Error(`There is no numeric setting with the id of ${e}`)}setNumericSetting(e,t){if(!this.numericParameters.has(e))throw new Error(`There is no numeric setting with the id of ${e}`);this.numericParameters.get(e).number=t}_addOnSettingChangedListener(e,t){this.flags.has(e)&&(this.flags.get(e).onChange=t)}_addOnTextSettingChangedListener(e,t){this.textParameters.has(e)&&(this.textParameters.get(e).onChange=t)}getSettingOption(e){return this.optionParameters.get(e)}isFlagEnabled(e){return this.flags.get(e).flag}setFlagEnabled(e,t){this.flags.has(e)?this.flags.get(e).flag=t:s.Warning(s.GetStackTrace(),`Cannot toggle flag called ${e} - it does not exist in the Config.flags map.`)}setTextSetting(e,t){this.textParameters.has(e)?this.textParameters.get(e).text=t:s.Warning(s.GetStackTrace(),`Cannot set text setting called ${e} - it does not exist in the Config.textParameters map.`)}setOptionSettingOptions(e,t){this.optionParameters.has(e)?this.optionParameters.get(e).options=t:s.Warning(s.GetStackTrace(),`Cannot set text setting called ${e} - it does not exist in the Config.optionParameters map.`)}setOptionSettingValue(e,t){if(this.optionParameters.has(e)){const s=this.optionParameters.get(e),n=s.options;n.includes(t)||(n.push(t),s.options=n),s.selected=t}else s.Warning(s.GetStackTrace(),`Cannot set text setting called ${e} - it does not exist in the Config.enumParameters map.`)}setFlagLabel(e,t){this.flags.has(e)?this.flags.get(e).label=t:s.Warning(s.GetStackTrace(),`Cannot set label for flag called ${e} - it does not exist in the Config.flags map.`)}setSettings(e){for(const t of Object.keys(e))Me(t)?this.setFlagEnabled(t,e[t]):be(t)?this.setNumericSetting(t,e[t]):Pe(t)?this.setTextSetting(t,e[t]):Le(t)&&this.setOptionSettingValue(t,e[t])}getSettings(){const e={};for(const[t,s]of this.flags.entries())e[t]=s.flag;for(const[t,s]of this.numericParameters.entries())e[t]=s.number;for(const[t,s]of this.textParameters.entries())e[t]=s.text;for(const[t,s]of this.optionParameters.entries())e[t]=s.selected;return e}getFlags(){return Array.from(this.flags.values())}getTextSettings(){return Array.from(this.textParameters.values())}getNumericSettings(){return Array.from(this.numericParameters.values())}getOptionSettings(){return Array.from(this.optionParameters.values())}_registerOnChangeEvents(e){for(const t of this.flags.keys()){const s=this.flags.get(t);s&&(s.onChangeEmit=t=>e.dispatchEvent(new ve({id:s.id,type:"flag",value:t,target:s})))}for(const t of this.numericParameters.keys()){const s=this.numericParameters.get(t);s&&(s.onChangeEmit=t=>e.dispatchEvent(new ve({id:s.id,type:"number",value:t,target:s})))}for(const t of this.textParameters.keys()){const s=this.textParameters.get(t);s&&(s.onChangeEmit=t=>e.dispatchEvent(new ve({id:s.id,type:"text",value:t,target:s})))}for(const t of this.optionParameters.keys()){const s=this.optionParameters.get(t);s&&(s.onChangeEmit=t=>e.dispatchEvent(new ve({id:s.id,type:"option",value:t,target:s})))}}}var Ae;!function(e){e[e.LockedMouse=0]="LockedMouse",e[e.HoveringMouse=1]="HoveringMouse"}(Ae||(Ae={}));class Fe{constructor(e,t,s){this.closeTimeout=10,this.active=!1,this.countdownActive=!1,this.warnTimer=void 0,this.countDown=0,this.countDownTimer=void 0,this.config=e,this.pixelStreaming=t,this.onDismissAfk=s,this.onAFKTimedOutCallback=()=>{console.log("AFK timed out, did you want to override this callback?")}}onAfkClick(){clearInterval(this.countDownTimer),(this.active||this.countdownActive)&&(this.startAfkWarningTimer(),this.pixelStreaming.dispatchEvent(new H))}startAfkWarningTimer(){this.config.getNumericSettingValue(we.AFKTimeoutSecs)>0&&this.config.isFlagEnabled(Ee.AFKDetection)?this.active=!0:this.active=!1,this.resetAfkWarningTimer()}stopAfkWarningTimer(){this.active=!1,this.countdownActive=!1,clearTimeout(this.warnTimer),clearInterval(this.countDownTimer)}pauseAfkWarningTimer(){this.active=!1}resetAfkWarningTimer(){this.active&&this.config.isFlagEnabled(Ee.AFKDetection)&&(clearTimeout(this.warnTimer),this.warnTimer=setTimeout((()=>this.activateAfkEvent()),1e3*this.config.getNumericSettingValue(we.AFKTimeoutSecs)))}activateAfkEvent(){this.pauseAfkWarningTimer(),this.pixelStreaming.dispatchEvent(new G({countDown:this.countDown,dismissAfk:this.onDismissAfk})),this.countDown=this.closeTimeout,this.countdownActive=!0,this.pixelStreaming.dispatchEvent(new z({countDown:this.countDown})),this.config.isFlagEnabled(Ee.HoveringMouseMode)||document.exitPointerLock&&document.exitPointerLock(),this.countDownTimer=setInterval((()=>{this.countDown--,0==this.countDown?(this.pixelStreaming.dispatchEvent(new W),this.onAFKTimedOutCallback(),s.Log(s.GetStackTrace(),"You have been disconnected due to inactivity"),this.stopAfkWarningTimer()):this.pixelStreaming.dispatchEvent(new z({countDown:this.countDown}))}),1e3)}}class De{constructor(){this.isReceivingFreezeFrame=!1}getDataChannelInstance(){return this}createDataChannel(e,t,s){this.peerConnection=e,this.label=t,this.datachannelOptions=s,null==s&&(this.datachannelOptions={},this.datachannelOptions.ordered=!0),this.dataChannel=this.peerConnection.createDataChannel(this.label,this.datachannelOptions),this.setupDataChannel()}setupDataChannel(){this.dataChannel.binaryType="arraybuffer",this.dataChannel.onopen=e=>this.handleOnOpen(e),this.dataChannel.onclose=e=>this.handleOnClose(e),this.dataChannel.onmessage=e=>this.handleOnMessage(e),this.dataChannel.onerror=e=>this.handleOnError(e)}handleOnOpen(e){var t;s.Log(s.GetStackTrace(),`Data Channel (${this.label}) opened.`,7),this.onOpen(null===(t=this.dataChannel)||void 0===t?void 0:t.label,e)}handleOnClose(e){var t;s.Log(s.GetStackTrace(),`Data Channel (${this.label}) closed.`,7),this.onClose(null===(t=this.dataChannel)||void 0===t?void 0:t.label,e)}handleOnMessage(e){s.Log(s.GetStackTrace(),`Data Channel (${this.label}) message: ${e}`,8)}handleOnError(e){var t;s.Log(s.GetStackTrace(),`Data Channel (${this.label}) error: ${e}`,7),this.onError(null===(t=this.dataChannel)||void 0===t?void 0:t.label,e)}onOpen(e,t){}onClose(e,t){}onError(e,t){}}class Oe{}class Ie{}class Ue{}class Be{}class _e{}class Ge{}class ze{}class He{}class We{constructor(){this.inboundVideoStats=new Ie,this.inboundAudioStats=new Oe,this.candidatePair=new _e,this.DataChannelStats=new Ue,this.outBoundVideoStats=new Ge,this.sessionStats=new ze,this.streamStats=new He,this.codecs=new Map}processStats(e){this.localCandidates=new Array,this.remoteCandidates=new Array,e.forEach((e=>{switch(e.type){case"candidate-pair":this.handleCandidatePair(e);break;case"certificate":case"media-source":case"media-playout":case"outbound-rtp":case"peer-connection":case"remote-inbound-rtp":case"transport":break;case"codec":this.handleCodec(e);break;case"data-channel":this.handleDataChannel(e);break;case"inbound-rtp":this.handleInBoundRTP(e);break;case"local-candidate":this.handleLocalCandidate(e);break;case"remote-candidate":this.handleRemoteCandidate(e);break;case"remote-outbound-rtp":this.handleRemoteOutBound(e);break;case"track":this.handleTrack(e);break;case"stream":this.handleStream(e);break;default:s.Error(s.GetStackTrace(),"unhandled Stat Type"),s.Log(s.GetStackTrace(),e)}}))}handleStream(e){this.streamStats=e}handleCandidatePair(e){this.candidatePair.bytesReceived=e.bytesReceived,this.candidatePair.bytesSent=e.bytesSent,this.candidatePair.localCandidateId=e.localCandidateId,this.candidatePair.remoteCandidateId=e.remoteCandidateId,this.candidatePair.nominated=e.nominated,this.candidatePair.readable=e.readable,this.candidatePair.selected=e.selected,this.candidatePair.writable=e.writable,this.candidatePair.state=e.state,this.candidatePair.currentRoundTripTime=e.currentRoundTripTime}handleDataChannel(e){this.DataChannelStats.bytesReceived=e.bytesReceived,this.DataChannelStats.bytesSent=e.bytesSent,this.DataChannelStats.dataChannelIdentifier=e.dataChannelIdentifier,this.DataChannelStats.id=e.id,this.DataChannelStats.label=e.label,this.DataChannelStats.messagesReceived=e.messagesReceived,this.DataChannelStats.messagesSent=e.messagesSent,this.DataChannelStats.protocol=e.protocol,this.DataChannelStats.state=e.state,this.DataChannelStats.timestamp=e.timestamp}handleLocalCandidate(e){const t=new Be;t.label="local-candidate",t.address=e.address,t.port=e.port,t.protocol=e.protocol,t.candidateType=e.candidateType,t.id=e.id,this.localCandidates.push(t)}handleRemoteCandidate(e){const t=new Be;t.label="local-candidate",t.address=e.address,t.port=e.port,t.protocol=e.protocol,t.id=e.id,t.candidateType=e.candidateType,this.remoteCandidates.push(t)}handleInBoundRTP(e){switch(e.kind){case"video":this.inboundVideoStats=e,null!=this.lastVideoStats&&(this.inboundVideoStats.bitrate=8*(this.inboundVideoStats.bytesReceived-this.lastVideoStats.bytesReceived)/(this.inboundVideoStats.timestamp-this.lastVideoStats.timestamp),this.inboundVideoStats.bitrate=Math.floor(this.inboundVideoStats.bitrate)),this.lastVideoStats=Object.assign({},this.inboundVideoStats);break;case"audio":this.inboundAudioStats=e,null!=this.lastAudioStats&&(this.inboundAudioStats.bitrate=8*(this.inboundAudioStats.bytesReceived-this.lastAudioStats.bytesReceived)/(this.inboundAudioStats.timestamp-this.lastAudioStats.timestamp),this.inboundAudioStats.bitrate=Math.floor(this.inboundAudioStats.bitrate)),this.lastAudioStats=Object.assign({},this.inboundAudioStats);break;default:s.Log(s.GetStackTrace(),"Kind is not handled")}}handleRemoteOutBound(e){"video"===e.kind&&(this.outBoundVideoStats.bytesSent=e.bytesSent,this.outBoundVideoStats.id=e.id,this.outBoundVideoStats.localId=e.localId,this.outBoundVideoStats.packetsSent=e.packetsSent,this.outBoundVideoStats.remoteTimestamp=e.remoteTimestamp,this.outBoundVideoStats.timestamp=e.timestamp)}handleTrack(e){"track"!==e.type||"video_label"!==e.trackIdentifier&&"video"!==e.kind||(this.inboundVideoStats.framesDropped=e.framesDropped,this.inboundVideoStats.framesReceived=e.framesReceived,this.inboundVideoStats.frameHeight=e.frameHeight,this.inboundVideoStats.frameWidth=e.frameWidth)}handleCodec(e){const t=e.id,s=`${e.mimeType.replace("video/","").replace("audio/","")}${e.sdpFmtpLine?` ${e.sdpFmtpLine}`:""}`;this.codecs.set(t,s)}handleSessionStatistics(e,t,s){const n=Date.now()-e;this.sessionStats.runTime=new Date(n).toISOString().substr(11,8).toString();const r=null===t?"Not sent yet":t?"true":"false";this.sessionStats.controlsStreamInput=r,this.sessionStats.videoEncoderAvgQP=s}isNumber(e){return"number"==typeof e&&isFinite(e)}}var Ve=n(366);class Ne{static isVideoTransciever(e){return this.canTransceiverReceiveVideo(e)||this.canTransceiverSendVideo(e)}static canTransceiverReceiveVideo(e){return!!e&&("sendrecv"===e.direction||"recvonly"===e.direction)&&e.receiver&&e.receiver.track&&"video"===e.receiver.track.kind}static canTransceiverSendVideo(e){return!!e&&("sendrecv"===e.direction||"sendonly"===e.direction)&&e.sender&&e.sender.track&&"video"===e.sender.track.kind}static isAudioTransciever(e){return this.canTransceiverReceiveAudio(e)||this.canTransceiverSendAudio(e)}static canTransceiverReceiveAudio(e){return!!e&&("sendrecv"===e.direction||"recvonly"===e.direction)&&e.receiver&&e.receiver.track&&"audio"===e.receiver.track.kind}static canTransceiverSendAudio(e){return!!e&&("sendrecv"===e.direction||"sendonly"===e.direction)&&e.sender&&e.sender.track&&"audio"===e.sender.track.kind}}var Ke,Qe,qe=function(e,t,s,n){return new(s||(s=Promise))((function(r,i){function o(e){try{l(n.next(e))}catch(e){i(e)}}function a(e){try{l(n.throw(e))}catch(e){i(e)}}function l(e){var t;e.done?r(e.value):(t=e.value,t instanceof s?t:new s((function(e){e(t)}))).then(o,a)}l((n=n.apply(e,t||[])).next())}))};class $e{constructor(e,t,s){this.config=t,this.createPeerConnection(e,s)}createPeerConnection(e,t){this.config.isFlagEnabled(Ee.ForceTURN)&&(e.iceTransportPolicy="relay",s.Log(s.GetStackTrace(),"Forcing TURN usage by setting ICE Transport Policy in peer connection config.")),this.peerConnection=new RTCPeerConnection(e),this.peerConnection.onsignalingstatechange=e=>this.handleSignalStateChange(e),this.peerConnection.oniceconnectionstatechange=e=>this.handleIceConnectionStateChange(e),this.peerConnection.onicegatheringstatechange=e=>this.handleIceGatheringStateChange(e),this.peerConnection.ontrack=e=>this.handleOnTrack(e),this.peerConnection.onicecandidate=e=>this.handleIceCandidate(e),this.peerConnection.ondatachannel=e=>this.handleDataChannel(e),this.aggregatedStats=new We,this.preferredCodec=t,this.updateCodecSelection=!0}createOffer(e,t){return qe(this,void 0,void 0,(function*(){s.Log(s.GetStackTrace(),"Create Offer",6);const n="localhost"===location.hostname||"127.0.0.1"===location.hostname,r="https:"===location.protocol;let i=t.isFlagEnabled(Ee.UseMic);!i||n||r||(i=!1,s.Error(s.GetStackTrace(),"Microphone access in the browser will not work if you are not on HTTPS or localhost. Disabling mic access."),s.Error(s.GetStackTrace(),"For testing you can enable HTTP microphone access Chrome by visiting chrome://flags/ and enabling 'unsafely-treat-insecure-origin-as-secure'")),this.setupTransceiversAsync(i).finally((()=>{var t;null===(t=this.peerConnection)||void 0===t||t.createOffer(e).then((e=>{var t;this.showTextOverlayConnecting(),e.sdp=this.mungeSDP(e.sdp,i),null===(t=this.peerConnection)||void 0===t||t.setLocalDescription(e),this.onSendWebRTCOffer(e)})).catch((()=>{this.showTextOverlaySetupFailure()}))}))}))}receiveOffer(e,t){var n;return qe(this,void 0,void 0,(function*(){s.Log(s.GetStackTrace(),"Receive Offer",6),null===(n=this.peerConnection)||void 0===n||n.setRemoteDescription(e).then((()=>{const e="localhost"===location.hostname||"127.0.0.1"===location.hostname,n="https:"===location.protocol;let r=t.isFlagEnabled(Ee.UseMic);!r||e||n||(r=!1,s.Error(s.GetStackTrace(),"Microphone access in the browser will not work if you are not on HTTPS or localhost. Disabling mic access."),s.Error(s.GetStackTrace(),"For testing you can enable HTTP microphone access Chrome by visiting chrome://flags/ and enabling 'unsafely-treat-insecure-origin-as-secure'")),this.setupTransceiversAsync(r).finally((()=>{var e;null===(e=this.peerConnection)||void 0===e||e.createAnswer().then((e=>{var t;return e.sdp=this.mungeSDP(e.sdp,r),null===(t=this.peerConnection)||void 0===t?void 0:t.setLocalDescription(e)})).then((()=>{var e;this.onSendWebRTCAnswer(null===(e=this.peerConnection)||void 0===e?void 0:e.currentLocalDescription)})).catch((()=>{s.Error(s.GetStackTrace(),"createAnswer() failed")}))}))})),this.config.setOptionSettingOptions(ke.PreferredCodec,this.parseAvailableCodecs(e).filter((e=>this.config.getSettingOption(ke.PreferredCodec).options.includes(e))))}))}receiveAnswer(e){var t;null===(t=this.peerConnection)||void 0===t||t.setRemoteDescription(e),this.config.setOptionSettingOptions(ke.PreferredCodec,this.parseAvailableCodecs(e).filter((e=>this.config.getSettingOption(ke.PreferredCodec).options.includes(e))))}generateStats(){var e;null===(e=this.peerConnection)||void 0===e||e.getStats(null).then((e=>{this.aggregatedStats.processStats(e),this.onVideoStats(this.aggregatedStats),this.updateCodecSelection&&this.aggregatedStats.inboundVideoStats.codecId&&this.config.setOptionSettingValue(ke.PreferredCodec,this.aggregatedStats.codecs.get(this.aggregatedStats.inboundVideoStats.codecId))}))}close(){this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null)}mungeSDP(e,t){let s=e.replace(/(a=fmtp:\d+ .*level-asymmetry-allowed=.*)\r\n/gm,"$1;x-google-start-bitrate=10000;x-google-max-bitrate=100000\r\n"),n="maxaveragebitrate=510000;";return t&&(n+="sprop-maxcapturerate=48000;"),n+=this.config.isFlagEnabled(Ee.ForceMonoAudio)?"stereo=0;":"stereo=1;",n+="useinbandfec=1",s=s.replace("useinbandfec=1",n),s}handleOnIce(e){var t;s.Log(s.GetStackTrace(),"peerconnection handleOnIce",6),this.config.isFlagEnabled(Ee.ForceTURN)&&e.candidate.indexOf("relay")<0?s.Info(s.GetStackTrace(),`Dropping candidate because it was not TURN relay. | Type= ${e.type} | Protocol= ${e.protocol} | Address=${e.address} | Port=${e.port} |`,6):null===(t=this.peerConnection)||void 0===t||t.addIceCandidate(e)}handleSignalStateChange(e){s.Log(s.GetStackTrace(),"signaling state change: "+e,6)}handleIceConnectionStateChange(e){s.Log(s.GetStackTrace(),"ice connection state change: "+e,6),this.onIceConnectionStateChange(e)}handleIceGatheringStateChange(e){s.Log(s.GetStackTrace(),"ice gathering state change: "+JSON.stringify(e),6)}handleOnTrack(e){this.onTrack(e)}handleIceCandidate(e){this.onPeerIceCandidate(e)}handleDataChannel(e){this.onDataChannel(e)}onTrack(e){}onIceConnectionStateChange(e){}onPeerIceCandidate(e){}onDataChannel(e){}setupTransceiversAsync(e){var t,s,n,r,i,o,a,l,d;return qe(this,void 0,void 0,(function*(){const c=(null===(t=this.peerConnection)||void 0===t?void 0:t.getTransceivers().length)>0;if(null===(s=this.peerConnection)||void 0===s||s.addTransceiver("video",{direction:"recvonly"}),RTCRtpReceiver.getCapabilities&&""!=this.preferredCodec)for(const e of null!==(r=null===(n=this.peerConnection)||void 0===n?void 0:n.getTransceivers())&&void 0!==r?r:[])if(e&&e.receiver&&e.receiver.track&&"video"===e.receiver.track.kind&&e.setCodecPreferences){const t=this.preferredCodec.split(" "),s=[{mimeType:"video/"+t[0],clockRate:9e4,sdpFmtpLine:t[1]?t[1]:""}];this.config.getSettingOption(ke.PreferredCodec).options.filter((e=>e!=this.preferredCodec)).forEach((e=>{const t=e.split(" ");s.push({mimeType:"video/"+t[0],clockRate:9e4,sdpFmtpLine:t[1]?t[1]:""})}));for(const e of s)""===e.sdpFmtpLine&&delete e.sdpFmtpLine;e.setCodecPreferences(s)}if(e){const e={video:!1,audio:{autoGainControl:!1,channelCount:1,echoCancellation:!1,latency:0,noiseSuppression:!1,sampleRate:48e3,sampleSize:16,volume:1}},t=yield navigator.mediaDevices.getUserMedia(e);if(t)if(c){for(const e of null!==(a=null===(o=this.peerConnection)||void 0===o?void 0:o.getTransceivers())&&void 0!==a?a:[])if(Ne.canTransceiverReceiveAudio(e))for(const s of t.getTracks())s.kind&&"audio"==s.kind&&(e.sender.replaceTrack(s),e.direction="sendrecv")}else for(const e of t.getTracks())e.kind&&"audio"==e.kind&&(null===(l=this.peerConnection)||void 0===l||l.addTransceiver(e,{direction:"sendrecv"}));else null===(d=this.peerConnection)||void 0===d||d.addTransceiver("audio",{direction:"recvonly"})}else null===(i=this.peerConnection)||void 0===i||i.addTransceiver("audio",{direction:"recvonly"})}))}onVideoStats(e){}onSendWebRTCOffer(e){}onSendWebRTCAnswer(e){}showTextOverlayConnecting(){}showTextOverlaySetupFailure(){}parseAvailableCodecs(e){if(!RTCRtpReceiver.getCapabilities)return["Only available on Chrome"];const t=[],s=(0,Ve.splitSections)(e.sdp);return s.shift(),s.forEach((e=>{const{codecs:s}=(0,Ve.parseRtpParameters)(e),n=/(VP\d|H26\d|AV1).*/;s.forEach((e=>{const s=e.name+" "+Object.keys(e.parameters||{}).map((t=>t+"="+e.parameters[t])).join(";");if(null!==n.exec(s)){"VP9"==e.name&&(e.parameters={"profile-id":"0"});const s=e.name+" "+Object.keys(e.parameters||{}).map((t=>t+"="+e.parameters[t])).join(";");t.push(s)}}))})),t}}class Xe{constructor(){this.PixelStreamingSettings=new je,this.EncoderSettings=new Je,this.WebRTCSettings=new Ye}ueCompatible(){null!=this.WebRTCSettings.MaxFPS&&(this.WebRTCSettings.FPS=this.WebRTCSettings.MaxFPS)}}class je{}class Je{}class Ye{}class Ze{constructor(){this.ReceiptTimeMs=null,this.TransmissionTimeMs=null,this.PreCaptureTimeMs=null,this.PostCaptureTimeMs=null,this.PreEncodeTimeMs=null,this.PostEncodeTimeMs=null,this.EncodeMs=null,this.CaptureToSendMs=null,this.testStartTimeMs=0,this.browserReceiptTimeMs=0,this.latencyExcludingDecode=0,this.testDuration=0,this.networkLatency=0,this.browserSendLatency=0,this.frameDisplayDeltaTimeMs=0,this.endToEndLatency=0,this.encodeLatency=0}setFrameDisplayDeltaTime(e){0==this.frameDisplayDeltaTimeMs&&(this.frameDisplayDeltaTimeMs=Math.round(e))}processFields(){null!=this.EncodeMs||null==this.PreEncodeTimeMs&&null==this.PostEncodeTimeMs||(s.Log(s.GetStackTrace(),`Setting Encode Ms \n ${this.PostEncodeTimeMs} \n ${this.PreEncodeTimeMs}`,6),this.EncodeMs=this.PostEncodeTimeMs-this.PreEncodeTimeMs),null!=this.CaptureToSendMs||null==this.PreCaptureTimeMs&&null==this.PostCaptureTimeMs||(s.Log(s.GetStackTrace(),`Setting CaptureToSendMs Ms \n ${this.PostCaptureTimeMs} \n ${this.PreCaptureTimeMs}`,6),this.CaptureToSendMs=this.PostCaptureTimeMs-this.PreCaptureTimeMs)}}class et{static setExtensionFromBytes(e,t){t.receiving||(t.mimetype="",t.extension="",t.receiving=!0,t.valid=!1,t.size=0,t.data=[],t.timestampStart=(new Date).getTime(),s.Log(s.GetStackTrace(),"Received first chunk of file",6));const n=new TextDecoder("utf-16").decode(e.slice(1));s.Log(s.GetStackTrace(),n,6),t.extension=n}static setMimeTypeFromBytes(e,t){t.receiving||(t.mimetype="",t.extension="",t.receiving=!0,t.valid=!1,t.size=0,t.data=[],t.timestampStart=(new Date).getTime(),s.Log(s.GetStackTrace(),"Received first chunk of file",6));const n=new TextDecoder("utf-16").decode(e.slice(1));s.Log(s.GetStackTrace(),n,6),t.mimetype=n}static setContentsFromBytes(e,t){if(!t.receiving)return;t.size=Math.ceil(new DataView(e.slice(1,5).buffer).getInt32(0,!0)/16379);const n=e.slice(5);if(t.data.push(n),s.Log(s.GetStackTrace(),`Received file chunk: ${t.data.length}/${t.size}`,6),t.data.length===t.size){t.receiving=!1,t.valid=!0,s.Log(s.GetStackTrace(),"Received complete file",6);const e=(new Date).getTime()-t.timestampStart,n=Math.round(16*t.size*1024/e);s.Log(s.GetStackTrace(),`Average transfer bitrate: ${n}kb/s over ${e/1e3} seconds`,6);const r=new Blob(t.data,{type:t.mimetype}),i=document.createElement("a");i.setAttribute("href",URL.createObjectURL(r)),i.setAttribute("download",`transfer.${t.extension}`),document.body.append(i),i.remove()}else t.data.length>t.size&&(t.receiving=!1,s.Error(s.GetStackTrace(),`Received bigger file than advertised: ${t.data.length}/${t.size}`))}}class tt{constructor(){this.mimetype="",this.extension="",this.receiving=!1,this.size=0,this.data=[],this.valid=!1}}class st{}st.mainButton=0,st.auxiliaryButton=1,st.secondaryButton=2,st.fourthButton=3,st.fifthButton=4;class nt{}nt.primaryButton=1,nt.secondaryButton=2,nt.auxiliaryButton=4,nt.fourthButton=8,nt.fifthButton=16;class rt{constructor(){this.unregisterCallbacks=[]}addUnregisterCallback(e){this.unregisterCallbacks.push(e)}unregisterAll(){for(const e of this.unregisterCallbacks)e();this.unregisterCallbacks=[]}}class it{constructor(e,t,s){this.touchEventListenerTracker=new rt,this.toStreamerMessagesProvider=e,this.videoElementProvider=t,this.coordinateConverter=s;const n=e=>this.onTouchStart(e),r=e=>this.onTouchEnd(e),i=e=>this.onTouchMove(e);document.addEventListener("touchstart",n,{passive:!1}),document.addEventListener("touchend",r,{passive:!1}),document.addEventListener("touchmove",i,{passive:!1}),this.touchEventListenerTracker.addUnregisterCallback((()=>document.removeEventListener("touchstart",n))),this.touchEventListenerTracker.addUnregisterCallback((()=>document.removeEventListener("touchend",r))),this.touchEventListenerTracker.addUnregisterCallback((()=>document.removeEventListener("touchmove",i)))}unregisterTouchEvents(){this.touchEventListenerTracker.unregisterAll()}setVideoElementParentClientRect(e){this.videoElementParentClientRect=e}onTouchStart(e){if(this.videoElementProvider.isVideoReady()&&e.target===this.videoElementProvider.getVideoElement()){if(null==this.fakeTouchFinger){const t=e.changedTouches[0];this.fakeTouchFinger=new ot(t.identifier,t.clientX-this.videoElementParentClientRect.left,t.clientY-this.videoElementParentClientRect.top);const s=this.videoElementProvider.getVideoParentElement(),n=new MouseEvent("mouseenter",t);s.dispatchEvent(n);const r=this.coordinateConverter.normalizeAndQuantizeUnsigned(this.fakeTouchFinger.x,this.fakeTouchFinger.y);this.toStreamerMessagesProvider.toStreamerHandlers.get("MouseDown")([st.mainButton,r.x,r.y])}e.preventDefault()}}onTouchEnd(e){if(!this.videoElementProvider.isVideoReady()||null==this.fakeTouchFinger)return;const t=this.videoElementProvider.getVideoParentElement(),s=this.toStreamerMessagesProvider.toStreamerHandlers;for(let n=0;n<e.changedTouches.length;n++){const r=e.changedTouches[n];if(r.identifier===this.fakeTouchFinger.id){const e=r.clientX-this.videoElementParentClientRect.left,n=r.clientY-this.videoElementParentClientRect.top,i=this.coordinateConverter.normalizeAndQuantizeUnsigned(e,n);s.get("MouseUp")([st.mainButton,i.x,i.y]);const o=new MouseEvent("mouseleave",r);t.dispatchEvent(o),this.fakeTouchFinger=null;break}}e.preventDefault()}onTouchMove(e){if(!this.videoElementProvider.isVideoReady()||null==this.fakeTouchFinger)return;const t=this.toStreamerMessagesProvider.toStreamerHandlers;for(let s=0;s<e.touches.length;s++){const n=e.touches[s];if(n.identifier===this.fakeTouchFinger.id){const e=n.clientX-this.videoElementParentClientRect.left,s=n.clientY-this.videoElementParentClientRect.top,r=this.coordinateConverter.normalizeAndQuantizeUnsigned(e,s),i=this.coordinateConverter.normalizeAndQuantizeSigned(e-this.fakeTouchFinger.x,s-this.fakeTouchFinger.y);t.get("MouseMove")([r.x,r.y,i.x,i.y]),this.fakeTouchFinger.x=e,this.fakeTouchFinger.y=s;break}}e.preventDefault()}}class ot{constructor(e,t,s){this.id=e,this.x=t,this.y=s}}class at{}at.backSpace=8,at.shift=16,at.control=17,at.alt=18,at.rightShift=253,at.rightControl=254,at.rightAlt=255;class lt{constructor(e,t,s){this.keyboardEventListenerTracker=new rt,this.CodeToKeyCode={Escape:27,Digit0:48,Digit1:49,Digit2:50,Digit3:51,Digit4:52,Digit5:53,Digit6:54,Digit7:55,Digit8:56,Digit9:57,Minus:173,Equal:187,Backspace:8,Tab:9,KeyQ:81,KeyW:87,KeyE:69,KeyR:82,KeyT:84,KeyY:89,KeyU:85,KeyI:73,KeyO:79,KeyP:80,BracketLeft:219,BracketRight:221,Enter:13,ControlLeft:17,KeyA:65,KeyS:83,KeyD:68,KeyF:70,KeyG:71,KeyH:72,KeyJ:74,KeyK:75,KeyL:76,Semicolon:186,Quote:222,Backquote:192,ShiftLeft:16,Backslash:220,KeyZ:90,KeyX:88,KeyC:67,KeyV:86,KeyB:66,KeyN:78,KeyM:77,Comma:188,Period:190,Slash:191,ShiftRight:253,AltLeft:18,Space:32,CapsLock:20,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123,Pause:19,ScrollLock:145,NumpadDivide:111,NumpadMultiply:106,NumpadSubtract:109,NumpadAdd:107,NumpadDecimal:110,Numpad9:105,Numpad8:104,Numpad7:103,Numpad6:102,Numpad5:101,Numpad4:100,Numpad3:99,Numpad2:98,Numpad1:97,Numpad0:96,NumLock:144,ControlRight:254,AltRight:255,Home:36,End:35,ArrowUp:38,ArrowLeft:37,ArrowRight:39,ArrowDown:40,PageUp:33,PageDown:34,Insert:45,Delete:46,ContextMenu:93},this.toStreamerMessagesProvider=e,this.config=t,this.activeKeysProvider=s}registerKeyBoardEvents(){const e=e=>this.handleOnCompositionEnd(e),t=e=>this.handleOnKeyDown(e),s=e=>this.handleOnKeyUp(e),n=e=>this.handleOnKeyPress(e);document.addEventListener("compositionend",e),document.addEventListener("keydown",t),document.addEventListener("keyup",s),document.addEventListener("keypress",n),this.keyboardEventListenerTracker.addUnregisterCallback((()=>document.removeEventListener("compositionend",e))),this.keyboardEventListenerTracker.addUnregisterCallback((()=>document.removeEventListener("keydown",t))),this.keyboardEventListenerTracker.addUnregisterCallback((()=>document.removeEventListener("keyup",s))),this.keyboardEventListenerTracker.addUnregisterCallback((()=>document.removeEventListener("keypress",n)))}unregisterKeyBoardEvents(){this.keyboardEventListenerTracker.unregisterAll()}handleOnKeyDown(e){const t=this.getKeycode(e);t&&229!==t&&(s.Log(s.GetStackTrace(),`key down ${t}, repeat = ${e.repeat}`,6),this.toStreamerMessagesProvider.toStreamerHandlers.get("KeyDown")([this.getKeycode(e),e.repeat?1:0]),this.activeKeysProvider.getActiveKeys().push(t),t===at.backSpace&&document.dispatchEvent(new KeyboardEvent("keypress",{charCode:at.backSpace})),this.config.isFlagEnabled(Ee.SuppressBrowserKeys)&&this.isKeyCodeBrowserKey(t)&&e.preventDefault())}handleOnKeyUp(e){const t=this.getKeycode(e);t&&(s.Log(s.GetStackTrace(),`key up ${t}`,6),this.toStreamerMessagesProvider.toStreamerHandlers.get("KeyUp")([t]),this.config.isFlagEnabled(Ee.SuppressBrowserKeys)&&this.isKeyCodeBrowserKey(t)&&e.preventDefault())}handleOnKeyPress(e){if(!("charCode"in e))return void s.Warning(s.GetStackTrace(),"KeyboardEvent.charCode is deprecated in this browser, cannot send key press.");const t=e.charCode;s.Log(s.GetStackTrace(),`key press ${t}`,6),this.toStreamerMessagesProvider.toStreamerHandlers.get("KeyPress")([t])}handleOnCompositionEnd(e){e.data&&e.data.length&&e.data.split("").forEach((e=>{this.handleOnKeyDown(new KeyboardEvent("keydown",{keyCode:e.toUpperCase().charCodeAt(0),charCode:e.charCodeAt(0)})),this.handleOnKeyPress(new KeyboardEvent("keypress",{keyCode:e.toUpperCase().charCodeAt(0),charCode:e.charCodeAt(0)})),this.handleOnKeyUp(new KeyboardEvent("keyup",{keyCode:e.toUpperCase().charCodeAt(0),charCode:e.charCodeAt(0)}))}))}getKeycode(e){if(!("keyCode"in e)){const t=e;return t.code in this.CodeToKeyCode?this.CodeToKeyCode[t.code]:(s.Warning(s.GetStackTrace(),`Keyboard code of ${t.code} is not supported in our mapping, ignoring this key.`),null)}return e.keyCode===at.shift&&"ShiftRight"===e.code?at.rightShift:e.keyCode===at.control&&"ControlRight"===e.code?at.rightControl:e.keyCode===at.alt&&"AltRight"===e.code?at.rightAlt:e.keyCode}isKeyCodeBrowserKey(e){return e>=112&&e<=123||9===e}}class dt{constructor(e,t,s){this.x=0,this.y=0,this.updateMouseMovePositionEvent=e=>{this.updateMouseMovePosition(e)},this.mouseEventListenerTracker=new rt,this.videoElementProvider=e,this.mouseController=t,this.activeKeysProvider=s;const n=this.videoElementProvider.getVideoParentElement();this.x=n.getBoundingClientRect().width/2,this.y=n.getBoundingClientRect().height/2,this.coord=this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(this.x,this.y)}unregisterMouseEvents(){this.mouseEventListenerTracker.unregisterAll()}lockStateChange(){const e=this.videoElementProvider.getVideoParentElement(),t=this.mouseController.toStreamerMessagesProvider.toStreamerHandlers;if(document.pointerLockElement===e||document.mozPointerLockElement===e)s.Log(s.GetStackTrace(),"Pointer locked",6),document.addEventListener("mousemove",this.updateMouseMovePositionEvent,!1),this.mouseEventListenerTracker.addUnregisterCallback((()=>document.removeEventListener("mousemove",this.updateMouseMovePositionEvent,!1)));else{s.Log(s.GetStackTrace(),"The pointer lock status is now unlocked",6),document.removeEventListener("mousemove",this.updateMouseMovePositionEvent,!1);let e=this.activeKeysProvider.getActiveKeys();const n=new Set(e),r=[];n.forEach((e=>{r[e]})),r.forEach((e=>{t.get("KeyUp")([e])})),e=[]}}updateMouseMovePosition(e){if(!this.videoElementProvider.isVideoReady())return;const t=this.mouseController.toStreamerMessagesProvider.toStreamerHandlers,s=this.videoElementProvider.getVideoParentElement().clientWidth,n=this.videoElementProvider.getVideoParentElement().clientHeight;this.x+=e.movementX,this.y+=e.movementY,this.x>s&&(this.x-=s),this.y>n&&(this.y-=n),this.x<0&&(this.x=s+this.x),this.y<0&&(this.y=n-this.y),this.coord=this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(this.x,this.y);const r=this.mouseController.coordinateConverter.normalizeAndQuantizeSigned(e.movementX,e.movementY);t.get("MouseMove")([this.coord.x,this.coord.y,r.x,r.y])}handleMouseDown(e){this.videoElementProvider.isVideoReady()&&this.mouseController.toStreamerMessagesProvider.toStreamerHandlers.get("MouseDown")([e.button,this.coord.x,this.coord.y])}handleMouseUp(e){this.videoElementProvider.isVideoReady()&&this.mouseController.toStreamerMessagesProvider.toStreamerHandlers.get("MouseUp")([e.button,this.coord.x,this.coord.y])}handleMouseWheel(e){this.videoElementProvider.isVideoReady()&&this.mouseController.toStreamerMessagesProvider.toStreamerHandlers.get("MouseWheel")([e.wheelDelta,this.coord.x,this.coord.y])}handleMouseDouble(e){this.videoElementProvider.isVideoReady()&&this.mouseController.toStreamerMessagesProvider.toStreamerHandlers.get("MouseDouble")([e.button,this.coord.x,this.coord.y])}handlePressMouseButtons(e){this.videoElementProvider.isVideoReady()&&this.mouseController.pressMouseButtons(e.buttons,this.x,this.y)}handleReleaseMouseButtons(e){this.videoElementProvider.isVideoReady()&&this.mouseController.releaseMouseButtons(e.buttons,this.x,this.y)}}class ct{constructor(e){this.mouseController=e}unregisterMouseEvents(){}updateMouseMovePosition(e){if(!this.mouseController.videoElementProvider.isVideoReady())return;s.Log(s.GetStackTrace(),"MouseMove",6);const t=this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(e.offsetX,e.offsetY),n=this.mouseController.coordinateConverter.normalizeAndQuantizeSigned(e.movementX,e.movementY);this.mouseController.toStreamerMessagesProvider.toStreamerHandlers.get("MouseMove")([t.x,t.y,n.x,n.y]),e.preventDefault()}handleMouseDown(e){if(!this.mouseController.videoElementProvider.isVideoReady())return;s.Log(s.GetStackTrace(),"onMouse Down",6);const t=this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(e.offsetX,e.offsetY);this.mouseController.toStreamerMessagesProvider.toStreamerHandlers.get("MouseDown")([e.button,t.x,t.y]),e.preventDefault()}handleMouseUp(e){if(!this.mouseController.videoElementProvider.isVideoReady())return;s.Log(s.GetStackTrace(),"onMouse Up",6);const t=this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(e.offsetX,e.offsetY);this.mouseController.toStreamerMessagesProvider.toStreamerHandlers.get("MouseUp")([e.button,t.x,t.y]),e.preventDefault()}handleContextMenu(e){this.mouseController.videoElementProvider.isVideoReady()&&e.preventDefault()}handleMouseWheel(e){if(!this.mouseController.videoElementProvider.isVideoReady())return;const t=this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(e.offsetX,e.offsetY);this.mouseController.toStreamerMessagesProvider.toStreamerHandlers.get("MouseWheel")([e.wheelDelta,t.x,t.y]),e.preventDefault()}handleMouseDouble(e){if(!this.mouseController.videoElementProvider.isVideoReady())return;const t=this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(e.offsetX,e.offsetY);this.mouseController.toStreamerMessagesProvider.toStreamerHandlers.get("MouseDouble")([e.button,t.x,t.y])}handlePressMouseButtons(e){this.mouseController.videoElementProvider.isVideoReady()&&(s.Log(s.GetStackTrace(),"onMouse press",6),this.mouseController.pressMouseButtons(e.buttons,e.offsetX,e.offsetY))}handleReleaseMouseButtons(e){this.mouseController.videoElementProvider.isVideoReady()&&(s.Log(s.GetStackTrace(),"onMouse release",6),this.mouseController.releaseMouseButtons(e.buttons,e.offsetX,e.offsetY))}}class ht{constructor(e,t,s,n){this.mouseEventListenerTracker=new rt,this.toStreamerMessagesProvider=e,this.coordinateConverter=s,this.videoElementProvider=t,this.activeKeysProvider=n,this.registerMouseEnterAndLeaveEvents()}unregisterMouseEvents(){this.mouseEventListenerTracker.unregisterAll()}registerLockedMouseEvents(e){const t=this.videoElementProvider.getVideoParentElement(),s=new dt(this.videoElementProvider,e,this.activeKeysProvider);if(t.requestPointerLock=t.requestPointerLock||t.mozRequestPointerLock,document.exitPointerLock=document.exitPointerLock||document.mozExitPointerLock,t.requestPointerLock){const e=()=>{t.requestPointerLock()};t.addEventListener("click",e),this.mouseEventListenerTracker.addUnregisterCallback((()=>t.removeEventListener("click",e)))}const n=()=>s.lockStateChange();document.addEventListener("pointerlockchange",n,!1),document.addEventListener("mozpointerlockchange",n,!1),this.mouseEventListenerTracker.addUnregisterCallback((()=>document.removeEventListener("pointerlockchange",n,!1))),this.mouseEventListenerTracker.addUnregisterCallback((()=>document.removeEventListener("mozpointerlockchange",n,!1)));const r=e=>s.handleMouseDown(e),i=e=>s.handleMouseUp(e),o=e=>s.handleMouseWheel(e),a=e=>s.handleMouseDouble(e);t.addEventListener("mousedown",r),t.addEventListener("mouseup",i),t.addEventListener("wheel",o),t.addEventListener("dblclick",a),this.mouseEventListenerTracker.addUnregisterCallback((()=>t.removeEventListener("mousedown",r))),this.mouseEventListenerTracker.addUnregisterCallback((()=>t.removeEventListener("mouseup",i))),this.mouseEventListenerTracker.addUnregisterCallback((()=>t.removeEventListener("wheel",o))),this.mouseEventListenerTracker.addUnregisterCallback((()=>t.removeEventListener("dblclick",a))),this.mouseEventListenerTracker.addUnregisterCallback((()=>s.unregisterMouseEvents())),this.mouseEventListenerTracker.addUnregisterCallback((()=>{!document.exitPointerLock||document.pointerLockElement!==t&&document.mozPointerLockElement!==t||document.exitPointerLock()}))}registerHoveringMouseEvents(e){const t=this.videoElementProvider.getVideoParentElement(),s=new ct(e),n=e=>s.updateMouseMovePosition(e),r=e=>s.handleMouseDown(e),i=e=>s.handleMouseUp(e),o=e=>s.handleContextMenu(e),a=e=>s.handleMouseWheel(e),l=e=>s.handleMouseDouble(e);t.addEventListener("mousemove",n),t.addEventListener("mousedown",r),t.addEventListener("mouseup",i),t.addEventListener("contextmenu",o),t.addEventListener("wheel",a),t.addEventListener("dblclick",l),this.mouseEventListenerTracker.addUnregisterCallback((()=>t.removeEventListener("mousemove",n))),this.mouseEventListenerTracker.addUnregisterCallback((()=>t.removeEventListener("mousedown",r))),this.mouseEventListenerTracker.addUnregisterCallback((()=>t.removeEventListener("mouseup",i))),this.mouseEventListenerTracker.addUnregisterCallback((()=>t.removeEventListener("contextmenu",o))),this.mouseEventListenerTracker.addUnregisterCallback((()=>t.removeEventListener("wheel",a))),this.mouseEventListenerTracker.addUnregisterCallback((()=>t.removeEventListener("dblclick",l))),this.mouseEventListenerTracker.addUnregisterCallback((()=>s.unregisterMouseEvents()))}registerMouseEnterAndLeaveEvents(){const e=this.videoElementProvider.getVideoParentElement(),t=e=>{this.videoElementProvider.isVideoReady()&&(s.Log(s.GetStackTrace(),"Mouse Entered",6),this.sendMouseEnter(),this.pressMouseButtons(e.buttons,e.x,e.y))},n=e=>{this.videoElementProvider.isVideoReady()&&(s.Log(s.GetStackTrace(),"Mouse Left",6),this.sendMouseLeave(),this.releaseMouseButtons(e.buttons,e.x,e.y))};e.addEventListener("mouseenter",t),e.addEventListener("mouseleave",n),this.mouseEventListenerTracker.addUnregisterCallback((()=>e.removeEventListener("mouseenter",t))),this.mouseEventListenerTracker.addUnregisterCallback((()=>e.removeEventListener("mouseleave",n)))}releaseMouseButtons(e,t,s){const n=this.coordinateConverter.normalizeAndQuantizeUnsigned(t,s);e&nt.primaryButton&&this.sendMouseUp(st.mainButton,n.x,n.y),e&nt.secondaryButton&&this.sendMouseUp(st.secondaryButton,n.x,n.y),e&nt.auxiliaryButton&&this.sendMouseUp(st.auxiliaryButton,n.x,n.y),e&nt.fourthButton&&this.sendMouseUp(st.fourthButton,n.x,n.y),e&nt.fifthButton&&this.sendMouseUp(st.fifthButton,n.x,n.y)}pressMouseButtons(e,t,s){if(!this.videoElementProvider.isVideoReady())return;const n=this.coordinateConverter.normalizeAndQuantizeUnsigned(t,s);e&nt.primaryButton&&this.sendMouseDown(st.mainButton,n.x,n.y),e&nt.secondaryButton&&this.sendMouseDown(st.secondaryButton,n.x,n.y),e&nt.auxiliaryButton&&this.sendMouseDown(st.auxiliaryButton,n.x,n.y),e&nt.fourthButton&&this.sendMouseDown(st.fourthButton,n.x,n.y),e&nt.fifthButton&&this.sendMouseDown(st.fifthButton,n.x,n.y)}sendMouseEnter(){this.videoElementProvider.isVideoReady()&&this.toStreamerMessagesProvider.toStreamerHandlers.get("MouseEnter")()}sendMouseLeave(){this.videoElementProvider.isVideoReady()&&this.toStreamerMessagesProvider.toStreamerHandlers.get("MouseLeave")()}sendMouseDown(e,t,n){this.videoElementProvider.isVideoReady()&&(s.Log(s.GetStackTrace(),`mouse button ${e} down at (${t}, ${n})`,6),this.toStreamerMessagesProvider.toStreamerHandlers.get("MouseDown")([e,t,n]))}sendMouseUp(e,t,n){if(!this.videoElementProvider.isVideoReady())return;s.Log(s.GetStackTrace(),`mouse button ${e} up at (${t}, ${n})`,6);const r=this.coordinateConverter.normalizeAndQuantizeUnsigned(t,n);this.toStreamerMessagesProvider.toStreamerHandlers.get("MouseUp")([e,r.x,r.y])}}class ut{constructor(e,t,n){this.fingers=[9,8,7,6,5,4,3,2,1,0],this.fingerIds=new Map,this.maxByteValue=255,this.touchEventListenerTracker=new rt,this.toStreamerMessagesProvider=e,this.videoElementProvider=t,this.coordinateConverter=n,this.videoElementParent=t.getVideoElement();const r=e=>this.onTouchStart(e),i=e=>this.onTouchEnd(e),o=e=>this.onTouchMove(e);this.videoElementParent.addEventListener("touchstart",r),this.videoElementParent.addEventListener("touchend",i),this.videoElementParent.addEventListener("touchmove",o),this.touchEventListenerTracker.addUnregisterCallback((()=>this.videoElementParent.removeEventListener("touchstart",r))),this.touchEventListenerTracker.addUnregisterCallback((()=>this.videoElementParent.removeEventListener("touchend",i))),this.touchEventListenerTracker.addUnregisterCallback((()=>this.videoElementParent.removeEventListener("touchmove",o))),s.Log(s.GetStackTrace(),"Touch Events Registered",6);const a=e=>{e.preventDefault()};document.addEventListener("touchmove",a),this.touchEventListenerTracker.addUnregisterCallback((()=>document.removeEventListener("touchmove",a)))}unregisterTouchEvents(){this.touchEventListenerTracker.unregisterAll()}rememberTouch(e){const t=this.fingers.pop();void 0===t&&s.Log(s.GetStackTrace(),"exhausted touch identifiers",6),this.fingerIds.set(e.identifier,t)}forgetTouch(e){this.fingers.push(this.fingerIds.get(e.identifier)),this.fingers.sort((function(e,t){return t-e})),this.fingerIds.delete(e.identifier)}onTouchStart(e){if(this.videoElementProvider.isVideoReady()){for(let t=0;t<e.changedTouches.length;t++)this.rememberTouch(e.changedTouches[t]);s.Log(s.GetStackTrace(),"touch start",6),this.emitTouchData("TouchStart",e.changedTouches),e.preventDefault()}}onTouchEnd(e){if(this.videoElementProvider.isVideoReady()){s.Log(s.GetStackTrace(),"touch end",6),this.emitTouchData("TouchEnd",e.changedTouches);for(let t=0;t<e.changedTouches.length;t++)this.forgetTouch(e.changedTouches[t]);e.preventDefault()}}onTouchMove(e){this.videoElementProvider.isVideoReady()&&(s.Log(s.GetStackTrace(),"touch move",6),this.emitTouchData("TouchMove",e.touches),e.preventDefault())}emitTouchData(e,t){if(!this.videoElementProvider.isVideoReady())return;const n=this.videoElementProvider.getVideoParentElement().getBoundingClientRect(),r=this.toStreamerMessagesProvider.toStreamerHandlers;for(let i=0;i<t.length;i++){const o=1,a=t[i],l=a.clientX-n.left,d=a.clientY-n.top;s.Log(s.GetStackTrace(),`F${this.fingerIds.get(a.identifier)}=(${l}, ${d})`,6);const c=this.coordinateConverter.normalizeAndQuantizeUnsigned(l,d);switch(e){case"TouchStart":r.get("TouchStart")([o,c.x,c.y,this.fingerIds.get(a.identifier),this.maxByteValue*a.force,c.inRange?1:0]);break;case"TouchEnd":r.get("TouchEnd")([o,c.x,c.y,this.fingerIds.get(a.identifier),this.maxByteValue*a.force,c.inRange?1:0]);break;case"TouchMove":r.get("TouchMove")([o,c.x,c.y,this.fingerIds.get(a.identifier),this.maxByteValue*a.force,c.inRange?1:0])}}}}class gt{constructor(e){this.gamePadEventListenerTracker=new rt,this.toStreamerMessagesProvider=e,this.requestAnimationFrame=(window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.requestAnimationFrame).bind(window);const t=window;if(window.addEventListener("beforeunload",(e=>this.onBeforeUnload(e))),"GamepadEvent"in t){const e=e=>this.gamePadConnectHandler(e),t=e=>this.gamePadDisconnectHandler(e);window.addEventListener("gamepadconnected",e),window.addEventListener("gamepaddisconnected",t),this.gamePadEventListenerTracker.addUnregisterCallback((()=>window.removeEventListener("gamepadconnected",e))),this.gamePadEventListenerTracker.addUnregisterCallback((()=>window.removeEventListener("gamepaddisconnected",t)))}else if("WebKitGamepadEvent"in t){const e=e=>this.gamePadConnectHandler(e),t=e=>this.gamePadDisconnectHandler(e);window.addEventListener("webkitgamepadconnected",e),window.addEventListener("webkitgamepaddisconnected",t),this.gamePadEventListenerTracker.addUnregisterCallback((()=>window.removeEventListener("webkitgamepadconnected",e))),this.gamePadEventListenerTracker.addUnregisterCallback((()=>window.removeEventListener("webkitgamepaddisconnected",t)))}if(this.controllers=[],navigator.getGamepads)for(const e of navigator.getGamepads())e&&this.gamePadConnectHandler(new GamepadEvent("gamepadconnected",{gamepad:e}))}unregisterGamePadEvents(){this.gamePadEventListenerTracker.unregisterAll();for(const e of this.controllers)void 0!==e.id&&this.onGamepadDisconnected(e.id);this.controllers=[],this.onGamepadConnected=()=>{},this.onGamepadDisconnected=()=>{}}gamePadConnectHandler(e){s.Log(s.GetStackTrace(),"Gamepad connect handler",6);const t=e.gamepad,n={currentState:t,prevState:t,id:void 0};this.controllers.push(n),this.controllers[t.index].currentState=t,this.controllers[t.index].prevState=t,s.Log(s.GetStackTrace(),"gamepad: "+t.id+" connected",6),window.requestAnimationFrame((()=>this.updateStatus())),this.onGamepadConnected()}gamePadDisconnectHandler(e){s.Log(s.GetStackTrace(),"Gamepad disconnect handler",6),s.Log(s.GetStackTrace(),"gamepad: "+e.gamepad.id+" disconnected",6);const t=this.controllers[e.gamepad.index];delete this.controllers[e.gamepad.index],this.controllers=this.controllers.filter((e=>void 0!==e)),this.onGamepadDisconnected(t.id)}scanGamePads(){const e=navigator.getGamepads?navigator.getGamepads():navigator.webkitGetGamepads?navigator.webkitGetGamepads():[];for(let t=0;t<e.length;t++)e[t]&&e[t].index in this.controllers&&(this.controllers[e[t].index].currentState=e[t])}updateStatus(){this.scanGamePads();const e=this.toStreamerMessagesProvider.toStreamerHandlers;for(const t of this.controllers){const s=void 0===t.id?this.controllers.indexOf(t):t.id,n=t.currentState;for(let n=0;n<t.currentState.buttons.length;n++){const r=t.currentState.buttons[n],i=t.prevState.buttons[n];r.pressed?n==Ke.LeftTrigger?e.get("GamepadAnalog")([s,5,r.value]):n==Ke.RightTrigger?e.get("GamepadAnalog")([s,6,r.value]):e.get("GamepadButtonPressed")([s,n,i.pressed?1:0]):!r.pressed&&i.pressed&&(n==Ke.LeftTrigger?e.get("GamepadAnalog")([s,5,0]):n==Ke.RightTrigger?e.get("GamepadAnalog")([s,6,0]):e.get("GamepadButtonReleased")([s,n,0]))}for(let t=0;t<n.axes.length;t+=2){const r=parseFloat(n.axes[t].toFixed(4)),i=-parseFloat(n.axes[t+1].toFixed(4));e.get("GamepadAnalog")([s,t+1,r]),e.get("GamepadAnalog")([s,t+2,i])}this.controllers[s].prevState=n}this.controllers.length>0&&this.requestAnimationFrame((()=>this.updateStatus()))}onGamepadResponseReceived(e){for(const t of this.controllers)if(void 0===t.id){t.id=e;break}}onGamepadConnected(){}onGamepadDisconnected(e){}onBeforeUnload(e){for(const e of this.controllers)this.onGamepadDisconnected(e.id)}}!function(e){e[e.RightClusterBottomButton=0]="RightClusterBottomButton",e[e.RightClusterRightButton=1]="RightClusterRightButton",e[e.RightClusterLeftButton=2]="RightClusterLeftButton",e[e.RightClusterTopButton=3]="RightClusterTopButton",e[e.LeftShoulder=4]="LeftShoulder",e[e.RightShoulder=5]="RightShoulder",e[e.LeftTrigger=6]="LeftTrigger",e[e.RightTrigger=7]="RightTrigger",e[e.SelectOrBack=8]="SelectOrBack",e[e.StartOrForward=9]="StartOrForward",e[e.LeftAnalogPress=10]="LeftAnalogPress",e[e.RightAnalogPress=11]="RightAnalogPress",e[e.LeftClusterTopButton=12]="LeftClusterTopButton",e[e.LeftClusterBottomButton=13]="LeftClusterBottomButton",e[e.LeftClusterLeftButton=14]="LeftClusterLeftButton",e[e.LeftClusterRightButton=15]="LeftClusterRightButton",e[e.CentreButton=16]="CentreButton",e[e.LeftStickHorizontal=0]="LeftStickHorizontal",e[e.LeftStickVertical=1]="LeftStickVertical",e[e.RightStickHorizontal=2]="RightStickHorizontal",e[e.RightStickVertical=3]="RightStickVertical"}(Ke||(Ke={}));class mt{constructor(e,t,s){this.activeKeys=new pt,this.toStreamerMessagesProvider=e,this.videoElementProvider=t,this.coordinateConverter=s}registerKeyBoard(e){s.Log(s.GetStackTrace(),"Register Keyboard Events",7);const t=new lt(this.toStreamerMessagesProvider,e,this.activeKeys);return t.registerKeyBoardEvents(),t}registerMouse(e){s.Log(s.GetStackTrace(),"Register Mouse Events",7);const t=new ht(this.toStreamerMessagesProvider,this.videoElementProvider,this.coordinateConverter,this.activeKeys);switch(e){case Ae.LockedMouse:t.registerLockedMouseEvents(t);break;case Ae.HoveringMouse:t.registerHoveringMouseEvents(t);break;default:s.Info(s.GetStackTrace(),"unknown Control Scheme Type Defaulting to Locked Mouse Events"),t.registerLockedMouseEvents(t)}return t}registerTouch(e,t){if(s.Log(s.GetStackTrace(),"Registering Touch",6),e){const e=new it(this.toStreamerMessagesProvider,this.videoElementProvider,this.coordinateConverter);return e.setVideoElementParentClientRect(t),e}return new ut(this.toStreamerMessagesProvider,this.videoElementProvider,this.coordinateConverter)}registerGamePad(){return s.Log(s.GetStackTrace(),"Register Game Pad",7),new gt(this.toStreamerMessagesProvider)}}class pt{constructor(){this.activeKeys=[],this.activeKeys=[]}getActiveKeys(){return this.activeKeys}}class vt{constructor(e,t){this.lastTimeResized=(new Date).getTime(),this.videoElement=document.createElement("video"),this.config=t,this.videoElement.id="streamingVideo",this.videoElement.disablePictureInPicture=!0,this.videoElement.playsInline=!0,this.videoElement.style.width="100%",this.videoElement.style.height="100%",this.videoElement.style.position="absolute",this.videoElement.style.pointerEvents="all",e.appendChild(this.videoElement),this.onResizePlayerCallback=()=>{console.log("Resolution changed, restyling player, did you forget to override this function?")},this.onMatchViewportResolutionCallback=()=>{console.log("Resolution changed and match viewport resolution is turned on, did you forget to override this function?")},this.videoElement.onclick=()=>{null!=this.audioElement&&this.audioElement.paused&&this.audioElement.play(),this.videoElement.paused&&this.videoElement.play()},this.videoElement.onloadedmetadata=()=>{this.onVideoInitialized()},window.addEventListener("resize",(()=>this.resizePlayerStyle()),!0),window.addEventListener("orientationchange",(()=>this.onOrientationChange()))}setAudioElement(e){this.audioElement=e}play(){return this.videoElement.muted=this.config.isFlagEnabled(Ee.StartVideoMuted),this.videoElement.autoplay=this.config.isFlagEnabled(Ee.AutoPlayVideo),this.videoElement.play()}isPaused(){return this.videoElement.paused}isVideoReady(){return void 0!==this.videoElement.readyState&&this.videoElement.readyState>0}hasVideoSource(){return void 0!==this.videoElement.srcObject&&null!==this.videoElement.srcObject}getVideoElement(){return this.videoElement}getVideoParentElement(){return this.videoElement.parentElement}setVideoEnabled(e){this.videoElement.srcObject.getTracks().forEach((t=>t.enabled=e))}onVideoInitialized(){}onOrientationChange(){clearTimeout(this.orientationChangeTimeout),this.orientationChangeTimeout=window.setTimeout((()=>{this.resizePlayerStyle()}),500)}resizePlayerStyle(){const e=this.getVideoParentElement();e&&(this.updateVideoStreamSize(),e.classList.contains("fixed-size")||this.resizePlayerStyleToFillParentElement(),this.onResizePlayerCallback())}resizePlayerStyleToFillParentElement(){this.getVideoParentElement().setAttribute("style","top: 0px; left: 0px; width: 100%; height: 100%; cursor: default;")}updateVideoStreamSize(){if(this.config.isFlagEnabled(Ee.MatchViewportResolution))if((new Date).getTime()-this.lastTimeResized>300){const e=this.getVideoParentElement();if(!e)return;this.onMatchViewportResolutionCallback(e.clientWidth,e.clientHeight),this.lastTimeResized=(new Date).getTime()}else s.Log(s.GetStackTrace(),"Resizing too often - skipping",6),clearTimeout(this.resizeTimeoutHandle),this.resizeTimeoutHandle=window.setTimeout((()=>this.updateVideoStreamSize()),100)}}class St{constructor(){this.toStreamerHandlers=new Map,this.fromStreamerHandlers=new Map,this.toStreamerMessages=new Map,this.fromStreamerMessages=new Map}populateDefaultProtocol(){this.toStreamerMessages.set("IFrameRequest",{id:0,structure:[]}),this.toStreamerMessages.set("RequestQualityControl",{id:1,structure:[]}),this.toStreamerMessages.set("FpsRequest",{id:2,structure:[]}),this.toStreamerMessages.set("AverageBitrateRequest",{id:3,structure:[]}),this.toStreamerMessages.set("StartStreaming",{id:4,structure:[]}),this.toStreamerMessages.set("StopStreaming",{id:5,structure:[]}),this.toStreamerMessages.set("LatencyTest",{id:6,structure:["string"]}),this.toStreamerMessages.set("RequestInitialSettings",{id:7,structure:[]}),this.toStreamerMessages.set("TestEcho",{id:8,structure:[]}),this.toStreamerMessages.set("DataChannelLatencyTest",{id:9,structure:[]}),this.toStreamerMessages.set("UIInteraction",{id:50,structure:["string"]}),this.toStreamerMessages.set("Command",{id:51,structure:["string"]}),this.toStreamerMessages.set("KeyDown",{id:60,structure:["uint8","uint8"]}),this.toStreamerMessages.set("KeyUp",{id:61,structure:["uint8"]}),this.toStreamerMessages.set("KeyPress",{id:62,structure:["uint16"]}),this.toStreamerMessages.set("MouseEnter",{id:70,structure:[]}),this.toStreamerMessages.set("MouseLeave",{id:71,structure:[]}),this.toStreamerMessages.set("MouseDown",{id:72,structure:["uint8","uint16","uint16"]}),this.toStreamerMessages.set("MouseUp",{id:73,structure:["uint8","uint16","uint16"]}),this.toStreamerMessages.set("MouseMove",{id:74,structure:["uint16","uint16","int16","int16"]}),this.toStreamerMessages.set("MouseWheel",{id:75,structure:["int16","uint16","uint16"]}),this.toStreamerMessages.set("MouseDouble",{id:76,structure:["uint8","uint16","uint16"]}),this.toStreamerMessages.set("TouchStart",{id:80,structure:["uint8","uint16","uint16","uint8","uint8","uint8"]}),this.toStreamerMessages.set("TouchEnd",{id:81,structure:["uint8","uint16","uint16","uint8","uint8","uint8"]}),this.toStreamerMessages.set("TouchMove",{id:82,structure:["uint8","uint16","uint16","uint8","uint8","uint8"]}),this.toStreamerMessages.set("GamepadConnected",{id:93,structure:[]}),this.toStreamerMessages.set("GamepadButtonPressed",{id:90,structure:["uint8","uint8","uint8"]}),this.toStreamerMessages.set("GamepadButtonReleased",{id:91,structure:["uint8","uint8","uint8"]}),this.toStreamerMessages.set("GamepadAnalog",{id:92,structure:["uint8","uint8","double"]}),this.toStreamerMessages.set("GamepadDisconnected",{id:94,structure:["uint8"]}),this.fromStreamerMessages.set(0,"QualityControlOwnership"),this.fromStreamerMessages.set(1,"Response"),this.fromStreamerMessages.set(2,"Command"),this.fromStreamerMessages.set(3,"FreezeFrame"),this.fromStreamerMessages.set(4,"UnfreezeFrame"),this.fromStreamerMessages.set(5,"VideoEncoderAvgQP"),this.fromStreamerMessages.set(6,"LatencyTest"),this.fromStreamerMessages.set(7,"InitialSettings"),this.fromStreamerMessages.set(8,"FileExtension"),this.fromStreamerMessages.set(9,"FileMimeType"),this.fromStreamerMessages.set(10,"FileContents"),this.fromStreamerMessages.set(11,"TestEcho"),this.fromStreamerMessages.set(12,"InputControlOwnership"),this.fromStreamerMessages.set(13,"GamepadResponse"),this.fromStreamerMessages.set(14,"DataChannelLatencyTest"),this.fromStreamerMessages.set(255,"Protocol")}registerMessageHandler(e,t,n){switch(e){case Qe.ToStreamer:this.toStreamerHandlers.set(t,n);break;case Qe.FromStreamer:this.fromStreamerHandlers.set(t,n);break;default:s.Log(s.GetStackTrace(),`Unknown message direction ${e}`)}}}!function(e){e[e.ToStreamer=0]="ToStreamer",e[e.FromStreamer=1]="FromStreamer"}(Qe||(Qe={}));class Ct{constructor(){this.responseEventListeners=new Map}addResponseEventListener(e,t){this.responseEventListeners.set(e,t)}removeResponseEventListener(e){this.responseEventListeners.delete(e)}onResponse(e){s.Log(s.GetStackTrace(),"DataChannelReceiveMessageType.Response",6);const t=new TextDecoder("utf-16").decode(e.slice(1));s.Log(s.GetStackTrace(),t,6),this.responseEventListeners.forEach((e=>{e(t)}))}}class ft{constructor(e,t){this.dataChannelSender=e,this.toStreamerMessagesMapProvider=t}sendMessageToStreamer(e,t){void 0===t&&(t=[]);const n=this.toStreamerMessagesMapProvider.toStreamerMessages.get(e);if(void 0===n)return void s.Error(s.GetStackTrace(),`Attempted to send a message to the streamer with message type: ${e}, but the frontend hasn't been configured to send such a message. Check you've added the message type in your cpp`);if(n.structure&&t&&n.structure.length!==t.length)return void s.Error(s.GetStackTrace(),`Provided message data doesn't match expected layout. Expected [ ${n.structure.map((e=>{switch(e){case"uint8":case"uint16":case"int16":case"float":case"double":return"number";case"string":return"string"}})).toString()} ] but received [ ${t.map((e=>typeof e)).toString()} ]`);let r=0;const i=new TextEncoder;t.forEach(((e,t)=>{switch(n.structure[t]){case"uint8":r+=1;break;case"uint16":case"int16":r+=2;break;case"float":r+=4;break;case"double":r+=8;break;case"string":r+=2,r+=2*i.encode(e).length}}));const o=new DataView(new ArrayBuffer(r+1));o.setUint8(0,n.id);let a=1;t.forEach(((e,t)=>{switch(n.structure[t]){case"uint8":o.setUint8(a,e),a+=1;break;case"uint16":o.setUint16(a,e,!0),a+=2;break;case"int16":o.setInt16(a,e,!0),a+=2;break;case"float":o.setFloat32(a,e,!0),a+=4;break;case"double":o.setFloat64(a,e,!0),a+=8;break;case"string":o.setUint16(a,e.length,!0),a+=2;for(let t=0;t<e.length;t++)o.setUint16(a,e.charCodeAt(t),!0),a+=2}})),this.dataChannelSender.canSend()?this.dataChannelSender.sendData(o.buffer):s.Info(s.GetStackTrace(),`Data channel cannot send yet, skipping sending message: ${e} - ${new Uint8Array(o.buffer)}`)}}class Tt{constructor(e){this.sendMessageController=e}SendRequestQualityControl(){this.sendMessageController.sendMessageToStreamer("RequestQualityControl")}SendMaxFpsRequest(){this.sendMessageController.sendMessageToStreamer("FpsRequest")}SendAverageBitrateRequest(){this.sendMessageController.sendMessageToStreamer("AverageBitrateRequest")}SendStartStreaming(){this.sendMessageController.sendMessageToStreamer("StartStreaming")}SendStopStreaming(){this.sendMessageController.sendMessageToStreamer("StopStreaming")}SendRequestInitialSettings(){this.sendMessageController.sendMessageToStreamer("RequestInitialSettings")}}class yt{constructor(e){this.dataChannelProvider=e}canSend(){return void 0!==this.dataChannelProvider.getDataChannelInstance().dataChannel&&"open"==this.dataChannelProvider.getDataChannelInstance().dataChannel.readyState}sendData(e){const t=this.dataChannelProvider.getDataChannelInstance();"open"==t.dataChannel.readyState?(t.dataChannel.send(e),s.Log(s.GetStackTrace(),`Message Sent: ${new Uint8Array(e)}`,6),this.resetAfkWarningTimerOnDataSend()):s.Error(s.GetStackTrace(),`Message Failed: ${new Uint8Array(e)}`)}resetAfkWarningTimerOnDataSend(){}}class Et{constructor(e){this.videoElementProvider=e,this.normalizeAndQuantizeUnsignedFunc=()=>{throw new Error("Normalize and quantize unsigned, method not implemented.")},this.normalizeAndQuantizeSignedFunc=()=>{throw new Error("Normalize and unquantize signed, method not implemented.")},this.denormalizeAndUnquantizeUnsignedFunc=()=>{throw new Error("Denormalize and unquantize unsigned, method not implemented.")}}normalizeAndQuantizeUnsigned(e,t){return this.normalizeAndQuantizeUnsignedFunc(e,t)}unquantizeAndDenormalizeUnsigned(e,t){return this.denormalizeAndUnquantizeUnsignedFunc(e,t)}normalizeAndQuantizeSigned(e,t){return this.normalizeAndQuantizeSignedFunc(e,t)}setupNormalizeAndQuantize(){if(this.videoElementParent=this.videoElementProvider.getVideoParentElement(),this.videoElement=this.videoElementProvider.getVideoElement(),this.videoElementParent&&this.videoElement){const e=this.videoElementParent.clientHeight/this.videoElementParent.clientWidth,t=this.videoElement.videoHeight/this.videoElement.videoWidth;e>t?(s.Log(s.GetStackTrace(),"Setup Normalize and Quantize for playerAspectRatio > videoAspectRatio",6),this.ratio=e/t,this.normalizeAndQuantizeUnsignedFunc=(e,t)=>this.normalizeAndQuantizeUnsignedPlayerBigger(e,t),this.normalizeAndQuantizeSignedFunc=(e,t)=>this.normalizeAndQuantizeSignedPlayerBigger(e,t),this.denormalizeAndUnquantizeUnsignedFunc=(e,t)=>this.denormalizeAndUnquantizeUnsignedPlayerBigger(e,t)):(s.Log(s.GetStackTrace(),"Setup Normalize and Quantize for playerAspectRatio <= videoAspectRatio",6),this.ratio=t/e,this.normalizeAndQuantizeUnsignedFunc=(e,t)=>this.normalizeAndQuantizeUnsignedPlayerSmaller(e,t),this.normalizeAndQuantizeSignedFunc=(e,t)=>this.normalizeAndQuantizeSignedPlayerSmaller(e,t),this.denormalizeAndUnquantizeUnsignedFunc=(e,t)=>this.denormalizeAndUnquantizeUnsignedPlayerSmaller(e,t))}}normalizeAndQuantizeUnsignedPlayerBigger(e,t){const s=e/this.videoElementParent.clientWidth,n=this.ratio*(t/this.videoElementParent.clientHeight-.5)+.5;return s<0||s>1||n<0||n>1?new Mt(!1,65535,65535):new Mt(!0,65536*s,65536*n)}denormalizeAndUnquantizeUnsignedPlayerBigger(e,t){const s=e/65536,n=(t/65536-.5)/this.ratio+.5;return new wt(s*this.videoElementParent.clientWidth,n*this.videoElementParent.clientHeight)}normalizeAndQuantizeSignedPlayerBigger(e,t){const s=e/(.5*this.videoElementParent.clientWidth),n=this.ratio*t/(.5*this.videoElementParent.clientHeight);return new bt(32767*s,32767*n)}normalizeAndQuantizeUnsignedPlayerSmaller(e,t){const s=this.ratio*(e/this.videoElementParent.clientWidth-.5)+.5,n=t/this.videoElementParent.clientHeight;return s<0||s>1||n<0||n>1?new Mt(!1,65535,65535):new Mt(!0,65536*s,65536*n)}denormalizeAndUnquantizeUnsignedPlayerSmaller(e,t){const s=(e/65536-.5)/this.ratio+.5,n=t/65536;return new wt(s*this.videoElementParent.clientWidth,n*this.videoElementParent.clientHeight)}normalizeAndQuantizeSignedPlayerSmaller(e,t){const s=this.ratio*e/(.5*this.videoElementParent.clientWidth),n=t/(.5*this.videoElementParent.clientHeight);return new bt(32767*s,32767*n)}}class Mt{constructor(e,t,s){this.inRange=e,this.x=t,this.y=s}}class wt{constructor(e,t){this.x=e,this.y=t}}class bt{constructor(e,t){this.x=e,this.y=t}}class Rt{constructor(e,t){this.shouldShowPlayOverlay=!0,this.autoJoinTimer=void 0,this.config=e,this.pixelStreaming=t,this.responseController=new Ct,this.file=new tt,this.sdpConstraints={offerToReceiveAudio:!0,offerToReceiveVideo:!0},this.afkController=new Fe(this.config,this.pixelStreaming,this.onAfkTriggered.bind(this)),this.afkController.onAFKTimedOutCallback=()=>{this.closeSignalingServer("You have been disconnected due to inactivity")},this.freezeFrameController=new D(this.pixelStreaming.videoElementParent),this.videoPlayer=new vt(this.pixelStreaming.videoElementParent,this.config),this.videoPlayer.onVideoInitialized=()=>this.handleVideoInitialized(),this.videoPlayer.onMatchViewportResolutionCallback=(e,t)=>{const s={"Resolution.Width":e,"Resolution.Height":t};this.streamMessageController.toStreamerHandlers.get("Command")([JSON.stringify(s)])},this.videoPlayer.onResizePlayerCallback=()=>{this.setUpMouseAndFreezeFrame()},this.streamController=new A(this.videoPlayer),this.coordinateConverter=new Et(this.videoPlayer),this.sendrecvDataChannelController=new De,this.recvDataChannelController=new De,this.registerDataChannelEventEmitters(this.sendrecvDataChannelController),this.registerDataChannelEventEmitters(this.recvDataChannelController),this.dataChannelSender=new yt(this.sendrecvDataChannelController),this.dataChannelSender.resetAfkWarningTimerOnDataSend=()=>this.afkController.resetAfkWarningTimer(),this.streamMessageController=new St,this.transport=new l,this.protocol=new x(this.transport),this.protocol.messageHandlers.addListener(i.CONFIG,(e=>this.handleOnConfigMessage(e))),this.protocol.messageHandlers.addListener(i.STREAMER_LIST,(e=>this.handleStreamerListMessage(e))),this.protocol.messageHandlers.addListener(i.STREAMER_ID_CHANGED,(e=>this.handleStreamerIDChangedMessage(e))),this.protocol.messageHandlers.addListener(i.PLAYER_COUNT,(e=>{const t=e;this.pixelStreaming._onPlayerCount(t.count)})),this.protocol.messageHandlers.addListener(i.ANSWER,(e=>this.handleWebRtcAnswer(e))),this.protocol.messageHandlers.addListener(i.OFFER,(e=>this.handleWebRtcOffer(e))),this.protocol.messageHandlers.addListener(i.PEER_DATA_CHANNELS,(e=>this.handleWebRtcSFUPeerDatachannels(e))),this.protocol.messageHandlers.addListener(i.ICE_CANDIDATE,(e=>{const t=e;this.handleIceCandidate(t.candidate)})),this.protocol.transportEvents.addListener("open",(()=>{this.config.isFlagEnabled(Ee.BrowserSendOffer)||this.protocol.sendMessage(new y)})),this.protocol.transportEvents.addListener("error",(()=>{s.Error(s.GetStackTrace(),"Got a transport error.")})),this.protocol.transportEvents.addListener("close",(e=>{const t=this.shouldReconnect&&1001!=e.code&&this.config.getNumericSettingValue(we.MaxReconnectAttempts)>0,s=this.disconnectMessage?this.disconnectMessage:e.reason;this.pixelStreaming._onDisconnect(s,!t&&!this.isReconnecting),this.afkController.stopAfkWarningTimer(),this.statsTimerHandle&&void 0!==this.statsTimerHandle&&window.clearInterval(this.statsTimerHandle),this.setVideoEncoderAvgQP(0),this.setTouchInputEnabled(!1),this.setMouseInputEnabled(!1),this.setKeyboardInputEnabled(!1),this.setGamePadInputEnabled(!1),t&&setTimeout((()=>{this.isReconnecting=!0,this.reconnectAttempt++,this.tryReconnect(e.reason)}),2e3)})),this.sendMessageController=new ft(this.dataChannelSender,this.streamMessageController),this.toStreamerMessagesController=new Tt(this.sendMessageController),this.registerMessageHandlers(),this.streamMessageController.populateDefaultProtocol(),this.inputClassesFactory=new mt(this.streamMessageController,this.videoPlayer,this.coordinateConverter),this.isUsingSFU=!1,this.isQualityController=!1,this.preferredCodec="",this.shouldReconnect=!0,this.isReconnecting=!1,this.reconnectAttempt=0,this.config._addOnOptionSettingChangedListener(ke.StreamerId,(e=>{""!==e&&(this.peerConnectionController.peerConnection.close(),this.peerConnectionController.createPeerConnection(this.peerConfig,this.preferredCodec),this.subscribedStream=e,this.protocol.sendMessage(new E(e)))})),this.setVideoEncoderAvgQP(-1),this.signallingUrlBuilder=()=>{let e=this.config.getTextSettingValue(Re.SignallingServerUrl);return this.config.isFlagEnabled(Ee.BrowserSendOffer)&&(e+="?"+Ee.BrowserSendOffer+"=true"),e}}requestUnquantizedAndDenormalizeUnsigned(e,t){return this.coordinateConverter.unquantizeAndDenormalizeUnsigned(e,t)}handleOnMessage(e){const t=new Uint8Array(e.data);s.Log(s.GetStackTrace(),"Message incoming:"+t,6);const n=this.streamMessageController.fromStreamerMessages.get(t[0]);this.streamMessageController.fromStreamerHandlers.get(n)(e.data)}registerMessageHandlers(){this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"QualityControlOwnership",(e=>this.onQualityControlOwnership(e))),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"Response",(e=>this.responseController.onResponse(e))),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"Command",(e=>{this.onCommand(e)})),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"FreezeFrame",(e=>this.onFreezeFrameMessage(e))),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"UnfreezeFrame",(()=>this.invalidateFreezeFrameAndEnableVideo())),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"VideoEncoderAvgQP",(e=>this.handleVideoEncoderAvgQP(e))),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"LatencyTest",(e=>this.handleLatencyTestResult(e))),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"DataChannelLatencyTest",(e=>this.handleDataChannelLatencyTestResponse(e))),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"InitialSettings",(e=>this.handleInitialSettings(e))),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"FileExtension",(e=>this.onFileExtension(e))),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"FileMimeType",(e=>this.onFileMimeType(e))),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"FileContents",(e=>this.onFileContents(e))),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"TestEcho",(()=>{})),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"InputControlOwnership",(e=>this.onInputControlOwnership(e))),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"GamepadResponse",(e=>this.onGamepadResponse(e))),this.streamMessageController.registerMessageHandler(Qe.FromStreamer,"Protocol",(e=>this.onProtocolMessage(e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"IFrameRequest",(()=>this.sendMessageController.sendMessageToStreamer("IFrameRequest"))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"RequestQualityControl",(()=>this.sendMessageController.sendMessageToStreamer("RequestQualityControl"))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"FpsRequest",(()=>this.sendMessageController.sendMessageToStreamer("FpsRequest"))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"AverageBitrateRequest",(()=>this.sendMessageController.sendMessageToStreamer("AverageBitrateRequest"))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"StartStreaming",(()=>this.sendMessageController.sendMessageToStreamer("StartStreaming"))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"StopStreaming",(()=>this.sendMessageController.sendMessageToStreamer("StopStreaming"))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"LatencyTest",(e=>this.sendMessageController.sendMessageToStreamer("LatencyTest",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"RequestInitialSettings",(()=>this.sendMessageController.sendMessageToStreamer("RequestInitialSettings"))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"TestEcho",(()=>{})),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"UIInteraction",(e=>this.sendMessageController.sendMessageToStreamer("UIInteraction",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"Command",(e=>this.sendMessageController.sendMessageToStreamer("Command",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"TextboxEntry",(e=>this.sendMessageController.sendMessageToStreamer("TextboxEntry",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"KeyDown",(e=>this.sendMessageController.sendMessageToStreamer("KeyDown",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"KeyUp",(e=>this.sendMessageController.sendMessageToStreamer("KeyUp",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"KeyPress",(e=>this.sendMessageController.sendMessageToStreamer("KeyPress",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"MouseEnter",(e=>this.sendMessageController.sendMessageToStreamer("MouseEnter",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"MouseLeave",(e=>this.sendMessageController.sendMessageToStreamer("MouseLeave",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"MouseDown",(e=>this.sendMessageController.sendMessageToStreamer("MouseDown",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"MouseUp",(e=>this.sendMessageController.sendMessageToStreamer("MouseUp",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"MouseMove",(e=>this.sendMessageController.sendMessageToStreamer("MouseMove",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"MouseWheel",(e=>this.sendMessageController.sendMessageToStreamer("MouseWheel",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"MouseDouble",(e=>this.sendMessageController.sendMessageToStreamer("MouseDouble",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"TouchStart",(e=>this.sendMessageController.sendMessageToStreamer("TouchStart",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"TouchEnd",(e=>this.sendMessageController.sendMessageToStreamer("TouchEnd",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"TouchMove",(e=>this.sendMessageController.sendMessageToStreamer("TouchMove",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"GamepadConnected",(()=>this.sendMessageController.sendMessageToStreamer("GamepadConnected"))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"GamepadButtonPressed",(e=>this.sendMessageController.sendMessageToStreamer("GamepadButtonPressed",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"GamepadButtonReleased",(e=>this.sendMessageController.sendMessageToStreamer("GamepadButtonReleased",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"GamepadAnalog",(e=>this.sendMessageController.sendMessageToStreamer("GamepadAnalog",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"GamepadDisconnected",(e=>this.sendMessageController.sendMessageToStreamer("GamepadDisconnected",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"XRHMDTransform",(e=>this.sendMessageController.sendMessageToStreamer("XRHMDTransform",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"XRControllerTransform",(e=>this.sendMessageController.sendMessageToStreamer("XRControllerTransform",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"XRSystem",(e=>this.sendMessageController.sendMessageToStreamer("XRSystem",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"XRButtonTouched",(e=>this.sendMessageController.sendMessageToStreamer("XRButtonTouched",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"XRButtonPressed",(e=>this.sendMessageController.sendMessageToStreamer("XRButtonPressed",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"XRButtonReleased",(e=>this.sendMessageController.sendMessageToStreamer("XRButtonReleased",e))),this.streamMessageController.registerMessageHandler(Qe.ToStreamer,"XRAnalog",(e=>this.sendMessageController.sendMessageToStreamer("XRAnalog",e)))}onCommand(e){s.Log(s.GetStackTrace(),"DataChannelReceiveMessageType.Command",6);const t=new TextDecoder("utf-16").decode(e.slice(1));s.Log(s.GetStackTrace(),"Data Channel Command: "+t,6);const n=JSON.parse(t);"onScreenKeyboard"===n.command&&this.pixelStreaming._activateOnScreenKeyboard(n)}onProtocolMessage(e){try{const t=new TextDecoder("utf-16").decode(e.slice(1)),n=JSON.parse(t);Object.prototype.hasOwnProperty.call(n,"Direction")||s.Error(s.GetStackTrace(),"Malformed protocol received. Ensure the protocol message contains a direction");const r=n.Direction;delete n.Direction,s.Log(s.GetStackTrace(),`Received new ${r==Qe.FromStreamer?"FromStreamer":"ToStreamer"} protocol. Updating existing protocol...`),Object.keys(n).forEach((e=>{const t=n[e];switch(r){case Qe.ToStreamer:if(!Object.prototype.hasOwnProperty.call(t,"id"))return void s.Error(s.GetStackTrace(),`ToStreamer->${e} protocol definition was malformed as it didn't contain at least an id\n\n Definition was: ${JSON.stringify(t,null,2)}`);if("UIInteraction"===e||"Command"===e||"LatencyTest"===e)return;this.streamMessageController.toStreamerHandlers.get(e)?this.streamMessageController.toStreamerMessages.set(e,t):s.Error(s.GetStackTrace(),`There was no registered handler for "${e}" - try adding one using registerMessageHandler(MessageDirection.ToStreamer, "${e}", myHandler)`);break;case Qe.FromStreamer:if(!Object.prototype.hasOwnProperty.call(t,"id"))return void s.Error(s.GetStackTrace(),`FromStreamer->${e} protocol definition was malformed as it didn't contain at least an id\n\n Definition was: ${JSON.stringify(t,null,2)}`);this.streamMessageController.fromStreamerHandlers.get(e)?this.streamMessageController.fromStreamerMessages.set(t.id,e):s.Error(s.GetStackTrace(),`There was no registered handler for "${t}" - try adding one using registerMessageHandler(MessageDirection.FromStreamer, "${e}", myHandler)`);break;default:s.Error(s.GetStackTrace(),`Unknown direction: ${r}`)}})),this.toStreamerMessagesController.SendRequestInitialSettings(),this.toStreamerMessagesController.SendRequestQualityControl()}catch(e){s.Log(s.GetStackTrace(),e)}}onInputControlOwnership(e){const t=new Uint8Array(e);s.Log(s.GetStackTrace(),"DataChannelReceiveMessageType.InputControlOwnership",6);const n=new Boolean(t[1]).valueOf();s.Log(s.GetStackTrace(),`Received input controller message - will your input control the stream: ${n}`),this.pixelStreaming._onInputControlOwnership(n)}onGamepadResponse(e){const t=new TextDecoder("utf-16").decode(e.slice(1)),s=JSON.parse(t);this.gamePadController.onGamepadResponseReceived(s.controllerId)}onAfkTriggered(){this.afkController.onAfkClick(),this.videoPlayer.isPaused()&&this.videoPlayer.hasVideoSource()&&this.playStream()}setAfkEnabled(e){e?this.onAfkTriggered():this.afkController.stopAfkWarningTimer()}tryReconnect(e){this.protocol?(this.isReconnecting=!0,this.protocol.isConnected()?(this.closeSignalingServer(`${e} Restarting stream...`),setTimeout((()=>{this.tryReconnect(e)}),3e3)):(this.pixelStreaming._onWebRtcAutoConnect(),this.connectToSignallingServer())):s.Log(s.GetStackTrace(),"This player has no protocol connection.")}loadFreezeFrameOrShowPlayOverlay(){this.pixelStreaming.dispatchEvent(new ae({shouldShowPlayOverlay:this.shouldShowPlayOverlay,isValid:this.freezeFrameController.valid,jpegData:this.freezeFrameController.jpeg})),!0===this.shouldShowPlayOverlay?(s.Log(s.GetStackTrace(),"showing play overlay"),this.resizePlayerStyle()):(s.Log(s.GetStackTrace(),"showing freeze frame"),this.freezeFrameController.showFreezeFrame()),setTimeout((()=>{this.videoPlayer.setVideoEnabled(!1)}),this.freezeFrameController.freezeFrameDelay)}onFreezeFrameMessage(e){s.Log(s.GetStackTrace(),"DataChannelReceiveMessageType.FreezeFrame",6);const t=new Uint8Array(e);this.freezeFrameController.processFreezeFrameMessage(t,(()=>this.loadFreezeFrameOrShowPlayOverlay()))}invalidateFreezeFrameAndEnableVideo(){s.Log(s.GetStackTrace(),"DataChannelReceiveMessageType.FreezeFrame",6),setTimeout((()=>{this.pixelStreaming.dispatchEvent(new le),this.freezeFrameController.hideFreezeFrame()}),this.freezeFrameController.freezeFrameDelay),this.videoPlayer.getVideoElement()&&this.videoPlayer.setVideoEnabled(!0)}onFileExtension(e){const t=new Uint8Array(e);et.setExtensionFromBytes(t,this.file)}onFileMimeType(e){const t=new Uint8Array(e);et.setMimeTypeFromBytes(t,this.file)}onFileContents(e){const t=new Uint8Array(e);et.setContentsFromBytes(t,this.file)}playStream(){if(!this.videoPlayer.getVideoElement()){const e="Could not play video stream because the video player was not initialized correctly.";return this.pixelStreaming.dispatchEvent(new re({message:e})),s.Error(s.GetStackTrace(),e),void this.closeSignalingServer("Stream not initialized correctly")}if(this.videoPlayer.hasVideoSource()){if(this.setTouchInputEnabled(this.config.isFlagEnabled(Ee.TouchInput)),this.pixelStreaming.dispatchEvent(new ie),this.streamController.audioElement.srcObject){const e=this.config.isFlagEnabled(Ee.StartVideoMuted);this.streamController.audioElement.muted=e,e?this.playVideo():this.streamController.audioElement.play().then((()=>{this.playVideo()})).catch((e=>{s.Log(s.GetStackTrace(),e),s.Log(s.GetStackTrace(),"Browser does not support autoplaying video without interaction - to resolve this we are going to show the play button overlay."),this.pixelStreaming.dispatchEvent(new oe({reason:e}))}))}else this.playVideo();this.shouldShowPlayOverlay=!1,this.freezeFrameController.showFreezeFrame()}else s.Warning(s.GetStackTrace(),"Cannot play stream, the video element has no srcObject to play.")}playVideo(){this.videoPlayer.play().catch((e=>{this.streamController.audioElement.srcObject&&this.streamController.audioElement.pause(),s.Log(s.GetStackTrace(),e),s.Log(s.GetStackTrace(),"Browser does not support autoplaying video without interaction - to resolve this we are going to show the play button overlay."),this.pixelStreaming.dispatchEvent(new oe({reason:e}))}))}autoPlayVideoOrSetUpPlayOverlay(){this.config.isFlagEnabled(Ee.AutoPlayVideo)&&this.playStream(),this.resizePlayerStyle()}connectToSignallingServer(){this.locallyClosed=!1,this.shouldReconnect=!0,this.disconnectMessage=null;const e=this.signallingUrlBuilder();this.protocol.connect(e)}startSession(e){if(this.peerConfig=e,this.config.isFlagEnabled(Ee.ForceTURN)&&!this.checkTurnServerAvailability(e))return s.Info(s.GetStackTrace(),"No turn server was found in the Peer Connection Options. TURN cannot be forced, closing connection. Please use STUN instead"),void this.closeSignalingServer("TURN cannot be forced, closing connection. Please use STUN instead.");this.peerConnectionController=new $e(this.peerConfig,this.config,this.preferredCodec),this.peerConnectionController.onVideoStats=e=>this.handleVideoStats(e),this.peerConnectionController.onSendWebRTCOffer=e=>this.handleSendWebRTCOffer(e),this.peerConnectionController.onSendWebRTCAnswer=e=>this.handleSendWebRTCAnswer(e),this.peerConnectionController.onPeerIceCandidate=e=>this.handleSendIceCandidate(e),this.peerConnectionController.onDataChannel=e=>this.handleDataChannel(e),this.peerConnectionController.showTextOverlayConnecting=()=>this.pixelStreaming._onWebRtcConnecting(),this.peerConnectionController.showTextOverlaySetupFailure=()=>this.pixelStreaming._onWebRtcFailed();let t=!1;this.peerConnectionController.onIceConnectionStateChange=()=>{!t&&["connected","completed"].includes(this.peerConnectionController.peerConnection.iceConnectionState)&&(this.pixelStreaming._onWebRtcConnected(),t=!0)},this.peerConnectionController.onTrack=e=>this.streamController.handleOnTrack(e),this.config.isFlagEnabled(Ee.BrowserSendOffer)&&(this.sendrecvDataChannelController.createDataChannel(this.peerConnectionController.peerConnection,"cirrus",this.datachannelOptions),this.sendrecvDataChannelController.handleOnMessage=e=>this.handleOnMessage(e),this.peerConnectionController.createOffer(this.sdpConstraints,this.config))}checkTurnServerAvailability(e){if(!e.iceServers)return s.Info(s.GetStackTrace(),"A turn sever was not found"),!1;for(const t of e.iceServers)for(const e of t.urls)if(e.includes("turn"))return s.Log(s.GetStackTrace(),`A turn sever was found at ${e}`),!0;return s.Info(s.GetStackTrace(),"A turn sever was not found"),!1}handleOnConfigMessage(e){this.resizePlayerStyle(),this.startSession(e.peerConnectionOptions)}handleStreamerListMessage(e){s.Log(s.GetStackTrace(),`Got streamer list ${e.ids}`,6);let t=null;const n=this.config.getSettingOption(ke.StreamerId);n.selected.toString().trim()&&(t=n.selected);const r=[...e.ids];r.unshift(""),this.config.setOptionSettingOptions(ke.StreamerId,r);let i=null;const o=this.config.isFlagEnabled(Ee.WaitForStreamer),a=this.config.getNumericSettingValue(we.MaxReconnectAttempts),l=this.config.getNumericSettingValue(we.StreamerAutoJoinInterval),d=this.config.useUrlParams,c=new URLSearchParams(window.location.search);d&&c.has(ke.StreamerId)?t=c.get(ke.StreamerId):this.subscribedStream&&(t=this.subscribedStream),t&&e.ids.includes(t)?i=t:t&&o||1!=e.ids.length||(i=e.ids[0]),i?(this.isReconnecting=!1,this.reconnectAttempt=0,this.config.setOptionSettingValue(ke.StreamerId,i)):o&&(this.reconnectAttempt<a?(this.isReconnecting=!0,this.reconnectAttempt++,setTimeout((()=>{this.protocol.requestStreamerList()}),l)):(this.reconnectAttempt=0,this.isReconnecting=!1,this.shouldReconnect=!1)),this.pixelStreaming.dispatchEvent(new ce({messageStreamerList:e,autoSelectedStreamerId:i,wantedStreamerId:t}))}handleStreamerIDChangedMessage(e){const t=e.newID,s=this.config.getSettingOption(ke.StreamerId),n=s.onChange;s.onChange=()=>{};const r=s.options;for(let e=0;e<r.length;++e)if(r[e]==this.subscribedStream){r[e]=t;break}s.options=r,s.selected=t,s.onChange=n,this.subscribedStream=e.newID,this.pixelStreaming.dispatchEvent(new he({newID:t}))}handleWebRtcAnswer(e){s.Log(s.GetStackTrace(),`Got answer sdp ${e.sdp}`,6);const t={sdp:e.sdp,type:"answer"};this.peerConnectionController.receiveAnswer(t),this.handlePostWebrtcNegotiation()}handleWebRtcOffer(e){s.Log(s.GetStackTrace(),`Got offer sdp ${e.sdp}`,6),this.isUsingSFU=!!e.sfu&&e.sfu,this.isUsingSFU&&(this.peerConnectionController.preferredCodec="");const t={sdp:e.sdp,type:"offer"};this.peerConnectionController.receiveOffer(t,this.config),this.handlePostWebrtcNegotiation()}handleWebRtcSFUPeerDatachannels(e){const t={ordered:!0,negotiated:!0,id:e.sendStreamId},s=e.sendStreamId!=e.recvStreamId;if(this.sendrecvDataChannelController.createDataChannel(this.peerConnectionController.peerConnection,s?"send-datachannel":"datachannel",t),s){const t={ordered:!0,negotiated:!0,id:e.recvStreamId};this.recvDataChannelController.createDataChannel(this.peerConnectionController.peerConnection,"recv-datachannel",t),this.recvDataChannelController.handleOnOpen=()=>this.protocol.sendSFURecvDataChannelReady(),this.recvDataChannelController.handleOnMessage=e=>this.handleOnMessage(e)}else this.sendrecvDataChannelController.handleOnMessage=e=>this.handleOnMessage(e)}handlePostWebrtcNegotiation(){this.afkController.startAfkWarningTimer(),this.pixelStreaming._onWebRtcSdp(),this.statsTimerHandle&&void 0!==this.statsTimerHandle&&window.clearInterval(this.statsTimerHandle),this.statsTimerHandle=window.setInterval((()=>this.getStats()),1e3),this.setMouseInputEnabled(this.config.isFlagEnabled(Ee.MouseInput)),this.setKeyboardInputEnabled(this.config.isFlagEnabled(Ee.KeyboardInput)),this.setGamePadInputEnabled(this.config.isFlagEnabled(Ee.GamepadInput))}handleIceCandidate(e){s.Log(s.GetStackTrace(),"Web RTC Controller: onWebRtcIce",6);const t=new RTCIceCandidate(e);this.peerConnectionController.handleOnIce(t)}handleSendIceCandidate(e){s.Log(s.GetStackTrace(),"OnIceCandidate",6),e.candidate&&e.candidate.candidate&&this.protocol.sendIceCandidate(e.candidate)}handleDataChannel(e){s.Log(s.GetStackTrace(),"Data channel created for us by browser as we are a receiving peer.",6),this.sendrecvDataChannelController.dataChannel=e.channel,this.sendrecvDataChannelController.setupDataChannel(),this.sendrecvDataChannelController.handleOnMessage=e=>this.handleOnMessage(e)}handleSendWebRTCOffer(e){s.Log(s.GetStackTrace(),"Sending the offer to the Server",6);const t={minBitrateBps:1e3*this.config.getNumericSettingValue(we.WebRTCMinBitrate),maxBitrateBps:1e3*this.config.getNumericSettingValue(we.WebRTCMaxBitrate)};this.protocol.sendWebRtcOffer(e,t)}handleSendWebRTCAnswer(e){s.Log(s.GetStackTrace(),"Sending the answer to the Server",6);const t={minBitrateBps:1e3*this.config.getNumericSettingValue(we.WebRTCMinBitrate),maxBitrateBps:1e3*this.config.getNumericSettingValue(we.WebRTCMaxBitrate)};this.protocol.sendWebRtcAnswer(e,t),this.isUsingSFU&&this.protocol.sendWebRtcDatachannelRequest()}setUpMouseAndFreezeFrame(){this.videoElementParentClientRect=this.videoPlayer.getVideoParentElement().getBoundingClientRect(),this.coordinateConverter.setupNormalizeAndQuantize(),this.freezeFrameController.freezeFrame.resize()}closeSignalingServer(e){var t;this.locallyClosed=!0,this.shouldReconnect=!1,this.disconnectMessage=e,null===(t=this.protocol)||void 0===t||t.disconnect()}closePeerConnection(){var e;null===(e=this.peerConnectionController)||void 0===e||e.close()}close(){this.closeSignalingServer(""),this.closePeerConnection()}getStats(){this.peerConnectionController.generateStats()}sendLatencyTest(){this.latencyStartTime=Date.now(),this.streamMessageController.toStreamerHandlers.get("LatencyTest")([JSON.stringify({StartTime:this.latencyStartTime})])}sendDataChannelLatencyTest(e){this.streamMessageController.toStreamerHandlers.get("DataChannelLatencyTest")([JSON.stringify(e)])}sendEncoderMinQP(e){s.Log(s.GetStackTrace(),`MinQP=${e}\n`,6),null!=e&&this.streamMessageController.toStreamerHandlers.get("Command")([JSON.stringify({"Encoder.MinQP":e})])}sendEncoderMaxQP(e){s.Log(s.GetStackTrace(),`MaxQP=${e}\n`,6),null!=e&&this.streamMessageController.toStreamerHandlers.get("Command")([JSON.stringify({"Encoder.MaxQP":e})])}sendWebRTCMinBitrate(e){s.Log(s.GetStackTrace(),`WebRTC Min Bitrate=${e}`,6),null!=e&&this.streamMessageController.toStreamerHandlers.get("Command")([JSON.stringify({"WebRTC.MinBitrate":e})])}sendWebRTCMaxBitrate(e){s.Log(s.GetStackTrace(),`WebRTC Max Bitrate=${e}`,6),null!=e&&this.streamMessageController.toStreamerHandlers.get("Command")([JSON.stringify({"WebRTC.MaxBitrate":e})])}sendWebRTCFps(e){s.Log(s.GetStackTrace(),`WebRTC FPS=${e}`,6),null!=e&&(this.streamMessageController.toStreamerHandlers.get("Command")([JSON.stringify({"WebRTC.Fps":e})]),this.streamMessageController.toStreamerHandlers.get("Command")([JSON.stringify({"WebRTC.MaxFps":e})]))}sendShowFps(){s.Log(s.GetStackTrace(),"---- Sending show stat to UE ----",6),this.streamMessageController.toStreamerHandlers.get("Command")([JSON.stringify({"stat.fps":""})])}sendIframeRequest(){s.Log(s.GetStackTrace(),"---- Sending Request for an IFrame ----",6),this.streamMessageController.toStreamerHandlers.get("IFrameRequest")()}emitUIInteraction(e){s.Log(s.GetStackTrace(),"---- Sending custom UIInteraction message ----",6),this.streamMessageController.toStreamerHandlers.get("UIInteraction")([JSON.stringify(e)])}emitCommand(e){s.Log(s.GetStackTrace(),"---- Sending custom Command message ----",6),this.streamMessageController.toStreamerHandlers.get("Command")([JSON.stringify(e)])}emitConsoleCommand(e){s.Log(s.GetStackTrace(),"---- Sending custom Command:ConsoleCommand message ----",6),this.streamMessageController.toStreamerHandlers.get("Command")([JSON.stringify({ConsoleCommand:e})])}sendRequestQualityControlOwnership(){s.Log(s.GetStackTrace(),"---- Sending Request to Control Quality ----",6),this.toStreamerMessagesController.SendRequestQualityControl()}handleLatencyTestResult(e){s.Log(s.GetStackTrace(),"DataChannelReceiveMessageType.latencyTest",6);const t=new TextDecoder("utf-16").decode(e.slice(1)),n=new Ze;Object.assign(n,JSON.parse(t)),n.processFields(),n.testStartTimeMs=this.latencyStartTime,n.browserReceiptTimeMs=Date.now(),n.latencyExcludingDecode=~~(n.browserReceiptTimeMs-n.testStartTimeMs),n.testDuration=~~(n.TransmissionTimeMs-n.ReceiptTimeMs),n.networkLatency=~~(n.latencyExcludingDecode-n.testDuration),n.frameDisplayDeltaTimeMs&&n.browserReceiptTimeMs&&(n.endToEndLatency=(n.frameDisplayDeltaTimeMs,n.networkLatency,~~+n.CaptureToSendMs)),this.pixelStreaming._onLatencyTestResult(n)}handleDataChannelLatencyTestResponse(e){s.Log(s.GetStackTrace(),"DataChannelReceiveMessageType.dataChannelLatencyResponse",6);const t=new TextDecoder("utf-16").decode(e.slice(1)),n=JSON.parse(t);this.pixelStreaming._onDataChannelLatencyTestResponse(n)}handleInitialSettings(e){s.Log(s.GetStackTrace(),"DataChannelReceiveMessageType.InitialSettings",6);const t=new TextDecoder("utf-16").decode(e.slice(1)),n=JSON.parse(t),r=new Xe;n.Encoder&&(r.EncoderSettings=n.Encoder),n.WebRTC&&(r.WebRTCSettings=n.WebRTC),n.PixelStreaming&&(r.PixelStreamingSettings=n.PixelStreaming),n.ConfigOptions&&void 0!==n.ConfigOptions.DefaultToHover&&this.config.setFlagEnabled(Ee.HoveringMouseMode,!!n.ConfigOptions.DefaultToHover),r.ueCompatible(),s.Log(s.GetStackTrace(),t,6),this.pixelStreaming._onInitialSettings(r)}handleVideoEncoderAvgQP(e){s.Log(s.GetStackTrace(),"DataChannelReceiveMessageType.VideoEncoderAvgQP",6);const t=Number(new TextDecoder("utf-16").decode(e.slice(1)));this.setVideoEncoderAvgQP(t)}handleVideoInitialized(){this.pixelStreaming._onVideoInitialized(),this.autoPlayVideoOrSetUpPlayOverlay(),this.resizePlayerStyle(),this.videoPlayer.updateVideoStreamSize()}onQualityControlOwnership(e){const t=new Uint8Array(e);s.Log(s.GetStackTrace(),"DataChannelReceiveMessageType.QualityControlOwnership",6),this.isQualityController=new Boolean(t[1]).valueOf(),s.Log(s.GetStackTrace(),`Received quality controller message, will control quality: ${this.isQualityController}`),this.pixelStreaming._onQualityControlOwnership(this.isQualityController)}handleVideoStats(e){this.pixelStreaming._onVideoStats(e)}resizePlayerStyle(){this.videoPlayer.resizePlayerStyle()}setPreferredCodec(e){this.preferredCodec=e,this.peerConnectionController&&(this.peerConnectionController.preferredCodec=e,this.peerConnectionController.updateCodecSelection=!1)}setVideoEncoderAvgQP(e){this.videoAvgQp=e,this.pixelStreaming._onVideoEncoderAvgQP(this.videoAvgQp)}setKeyboardInputEnabled(e){var t;null===(t=this.keyboardController)||void 0===t||t.unregisterKeyBoardEvents(),e&&(this.keyboardController=this.inputClassesFactory.registerKeyBoard(this.config))}setMouseInputEnabled(e){var t;if(null===(t=this.mouseController)||void 0===t||t.unregisterMouseEvents(),e){const e=this.config.isFlagEnabled(Ee.HoveringMouseMode)?Ae.HoveringMouse:Ae.LockedMouse;this.mouseController=this.inputClassesFactory.registerMouse(e)}}setTouchInputEnabled(e){var t;null===(t=this.touchController)||void 0===t||t.unregisterTouchEvents(),e&&(this.touchController=this.inputClassesFactory.registerTouch(this.config.isFlagEnabled(Ee.FakeMouseWithTouches),this.videoElementParentClientRect))}setGamePadInputEnabled(e){var t;null===(t=this.gamePadController)||void 0===t||t.unregisterGamePadEvents(),e&&(this.gamePadController=this.inputClassesFactory.registerGamePad(),this.gamePadController.onGamepadConnected=()=>{this.streamMessageController.toStreamerHandlers.get("GamepadConnected")()},this.gamePadController.onGamepadDisconnected=e=>{this.streamMessageController.toStreamerHandlers.get("GamepadDisconnected")([e])})}registerDataChannelEventEmitters(e){e.onOpen=(e,t)=>this.pixelStreaming.dispatchEvent(new j({label:e,event:t})),e.onClose=(e,t)=>this.pixelStreaming.dispatchEvent(new J({label:e,event:t})),e.onError=(e,t)=>this.pixelStreaming.dispatchEvent(new Y({label:e,event:t}))}registerMessageHandler(e,t,n){t===Qe.FromStreamer&&void 0===n&&s.Warning(s.GetStackTrace(),`Unable to register handler for ${e} as no handler was passed`),this.streamMessageController.registerMessageHandler(t,e,(s=>void 0===n&&t===Qe.ToStreamer?this.sendMessageController.sendMessageToStreamer(e,s):n(s)))}}class Pt{static vertexShader(){return"\n\t\tattribute vec2 a_position;\n\t\tattribute vec2 a_texCoord;\n\n\t\t// input\n\t\tuniform vec2 u_resolution;\n\t\tuniform vec4 u_offset;\n\n\t\t//\n\t\tvarying vec2 v_texCoord;\n\n\t\tvoid main() {\n\t\t // convert the rectangle from pixels to 0.0 to 1.0\n\t\t vec2 zeroToOne = a_position / u_resolution;\n\n\t\t // convert from 0->1 to 0->2\n\t\t vec2 zeroToTwo = zeroToOne * 2.0;\n\n\t\t // convert from 0->2 to -1->+1 (clipspace)\n\t\t vec2 clipSpace = zeroToTwo - 1.0;\n\n\t\t gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);\n\t\t // pass the texCoord to the fragment shader\n\t\t // The GPU will interpolate this value between points.\n\t\t v_texCoord = (a_texCoord * u_offset.xy) + u_offset.zw;\n\t\t}\n\t\t"}static fragmentShader(){return"\n\t\tprecision mediump float;\n\n\t\t// our texture\n\t\tuniform sampler2D u_image;\n\n\t\t// the texCoords passed in from the vertex shader.\n\t\tvarying vec2 v_texCoord;\n\n\t\tvoid main() {\n\t\t gl_FragColor = texture2D(u_image, v_texCoord);\n\t\t}\n\t\t"}}class kt{static deepCopyGamepad(e){return JSON.parse(JSON.stringify({buttons:e.buttons.map((e=>JSON.parse(JSON.stringify({pressed:e.pressed,touched:e.touched})))),axes:e.axes}))}}class Lt{constructor(e){this.toStreamerMessagesProvider=e,this.controllers=[]}updateStatus(e,t,s){if(e.gamepad){const n=t.getPose(e.gripSpace,s);if(!n)return;let r=0;e.profiles.includes("htc-vive")?r=1:e.profiles.includes("oculus-touch")&&(r=2),this.toStreamerMessagesProvider.toStreamerHandlers.get("XRSystem")([r]);let i=2;switch(e.handedness){case"left":i=0;break;case"right":i=1}const o=n.transform.matrix,a=[];for(let e=0;e<16;e++)a[e]=new Float32Array([o[e]])[0];this.toStreamerMessagesProvider.toStreamerHandlers.get("XRControllerTransform")([a[0],a[4],a[8],a[12],a[1],a[5],a[9],a[13],a[2],a[6],a[10],a[14],a[3],a[7],a[11],a[15],i]),void 0===this.controllers[i]&&(this.controllers[i]={prevState:void 0,currentState:void 0,id:void 0},this.controllers[i].prevState=kt.deepCopyGamepad(e.gamepad)),this.controllers[i].currentState=kt.deepCopyGamepad(e.gamepad);const l=this.controllers[i],d=l.currentState,c=l.prevState;for(let e=0;e<d.buttons.length;e++){const t=d.buttons[e],s=c.buttons[e];t.pressed?this.toStreamerMessagesProvider.toStreamerHandlers.get("XRButtonPressed")([i,e,s.pressed?1:0]):!t.pressed&&s.pressed&&this.toStreamerMessagesProvider.toStreamerHandlers.get("XRButtonReleased")([i,e,0]),t.touched&&!t.pressed?this.toStreamerMessagesProvider.toStreamerHandlers.get("XRButtonPressed")([i,3,s.touched?1:0]):!t.touched&&s.touched&&this.toStreamerMessagesProvider.toStreamerHandlers.get("XRButtonReleased")([i,3,0])}for(let e=0;e<d.axes.length;e++)this.toStreamerMessagesProvider.toStreamerHandlers.get("XRAnalog")([i,e,d.axes[e]]);this.controllers[i].prevState=d}}}class xt{constructor(e){this.xrSession=null,this.webRtcController=e,this.xrControllers=[],this.xrGamepadController=new Lt(this.webRtcController.streamMessageController),this.onSessionEnded=new EventTarget,this.onSessionStarted=new EventTarget,this.onFrame=new EventTarget}xrClicked(){this.xrSession?this.xrSession.end():navigator.xr.requestSession("immersive-vr").then((e=>{this.onXrSessionStarted(e)}))}onXrSessionEnded(){s.Log(s.GetStackTrace(),"XR Session ended"),this.xrSession=null,this.onSessionEnded.dispatchEvent(new Event("xrSessionEnded"))}onXrSessionStarted(e){s.Log(s.GetStackTrace(),"XR Session started"),this.xrSession=e,this.xrSession.addEventListener("end",(()=>{this.onXrSessionEnded()}));const t=document.createElement("canvas");this.gl=t.getContext("webgl2",{xrCompatible:!0}),this.xrSession.updateRenderState({baseLayer:new XRWebGLLayer(this.xrSession,this.gl)});const n=this.gl.createShader(this.gl.VERTEX_SHADER);this.gl.shaderSource(n,Pt.vertexShader()),this.gl.compileShader(n);const r=this.gl.createShader(this.gl.FRAGMENT_SHADER);this.gl.shaderSource(r,Pt.fragmentShader()),this.gl.compileShader(r);const i=this.gl.createProgram();this.gl.attachShader(i,n),this.gl.attachShader(i,r),this.gl.linkProgram(i),this.gl.useProgram(i),this.positionLocation=this.gl.getAttribLocation(i,"a_position"),this.texcoordLocation=this.gl.getAttribLocation(i,"a_texCoord"),this.positionBuffer=this.gl.createBuffer(),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),this.gl.enableVertexAttribArray(this.positionLocation);const o=this.gl.createTexture();this.gl.bindTexture(this.gl.TEXTURE_2D,o),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.NEAREST),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.NEAREST),this.texcoordBuffer=this.gl.createBuffer(),this.resolutionLocation=this.gl.getUniformLocation(i,"u_resolution"),this.offsetLocation=this.gl.getUniformLocation(i,"u_offset"),e.requestReferenceSpace("local").then((e=>{this.xrRefSpace=e,this.xrSession.requestAnimationFrame(((e,t)=>this.onXrFrame(e,t)))})),this.onSessionStarted.dispatchEvent(new Event("xrSessionStarted"))}onXrFrame(e,t){const s=t.getViewerPose(this.xrRefSpace);if(s){const e=s.transform.matrix,t=[];for(let s=0;s<16;s++)t[s]=new Float32Array([e[s]])[0];this.webRtcController.streamMessageController.toStreamerHandlers.get("XRHMDTransform")([t[0],t[4],t[8],t[12],t[1],t[5],t[9],t[13],t[2],t[6],t[10],t[14],t[3],t[7],t[11],t[15]]);const n=this.xrSession.renderState.baseLayer;this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,n.framebuffer),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,this.webRtcController.videoPlayer.getVideoElement()),this.render(this.webRtcController.videoPlayer.getVideoElement())}this.webRtcController.config.isFlagEnabled(Ee.XRControllerInput)&&this.xrSession.inputSources.forEach(((e,s,n)=>{this.xrGamepadController.updateStatus(e,t,this.xrRefSpace)}),this),this.xrSession.requestAnimationFrame(((e,t)=>this.onXrFrame(e,t))),this.onFrame.dispatchEvent(new fe({time:e,frame:t}))}render(e){if(!this.gl)return;const t=this.xrSession.renderState.baseLayer;let s,n,r,i,o;this.gl.viewport(0,0,t.framebufferWidth,t.framebufferHeight),this.gl.uniform4f(this.offsetLocation,1,1,0,0),this.gl.bufferData(this.gl.ARRAY_BUFFER,new Float32Array([0,0,e.videoWidth,0,0,e.videoHeight,0,e.videoHeight,e.videoWidth,0,e.videoWidth,e.videoHeight]),this.gl.STATIC_DRAW),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.texcoordBuffer),this.gl.bufferData(this.gl.ARRAY_BUFFER,new Float32Array([0,0,1,0,0,1,0,1,1,0,1,1]),this.gl.STATIC_DRAW),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.positionBuffer),s=2,n=this.gl.FLOAT,r=!1,i=0,o=0,this.gl.vertexAttribPointer(this.positionLocation,s,n,r,i,o),this.gl.enableVertexAttribArray(this.texcoordLocation),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.texcoordBuffer),s=2,n=this.gl.FLOAT,r=!1,i=0,o=0,this.gl.vertexAttribPointer(this.texcoordLocation,s,n,r,i,o),this.gl.uniform2f(this.resolutionLocation,e.videoWidth,e.videoHeight);const a=this.gl.TRIANGLES;o=0,this.gl.drawArrays(a,o,6)}static isSessionSupported(e){return navigator.xr?navigator.xr.isSessionSupported(e):new Promise((()=>!1))}}class At{constructor(e){this.editTextButton=null,this.hiddenInput=null,"ontouchstart"in document.documentElement&&this.createOnScreenKeyboardHelpers(e)}unquantizeAndDenormalizeUnsigned(e,t){return null}createOnScreenKeyboardHelpers(e){this.hiddenInput||(this.hiddenInput=document.createElement("input"),this.hiddenInput.id="hiddenInput",this.hiddenInput.maxLength=0,e.appendChild(this.hiddenInput)),this.editTextButton||(this.editTextButton=document.createElement("button"),this.editTextButton.id="editTextButton",this.editTextButton.innerHTML="edit text",e.appendChild(this.editTextButton),this.editTextButton.classList.add("hiddenState"),this.editTextButton.addEventListener("touchend",(e=>{this.hiddenInput.focus(),e.preventDefault()})))}showOnScreenKeyboard(e){if(e.showOnScreenKeyboard){this.editTextButton.classList.remove("hiddenState");const t=this.unquantizeAndDenormalizeUnsigned(e.x,e.y);this.editTextButton.style.top=t.y.toString()+"px",this.editTextButton.style.left=(t.x-40).toString()+"px"}else this.editTextButton.classList.add("hiddenState"),this.hiddenInput.blur()}}class Ft{constructor(e){this.seq=e.Seq,this.playerSentTimestamp=Date.now(),this.requestFillerSize=e.Filler?e.Filler.length:0}update(e){this.playerReceivedTimestamp=Date.now(),this.streamerReceivedTimestamp=e.ReceivedTimestamp,this.streamerSentTimestamp=e.SentTimestamp,this.responseFillerSize=e.Filler?e.Filler.length:0}}class Dt{constructor(e,t){this.sink=e,this.callback=t,this.records=new Map,this.seq=0}start(e){return!this.isRunning()&&(this.startTime=Date.now(),this.records.clear(),this.interval=setInterval((()=>{Date.now()-this.startTime>=e.duration?this.stop():this.sendRequest(e.requestSize,e.responseSize)}).bind(this),Math.floor(1e3/e.rps)),!0)}stop(){this.interval&&(clearInterval(this.interval),this.interval=void 0,this.callback(this.produceResult()))}produceResult(){const e=new Map(this.records);return{records:e,dataChannelRtt:Math.ceil(Array.from(this.records.values()).reduce(((e,t)=>e+(t.playerReceivedTimestamp-t.playerSentTimestamp)),0)/this.records.size),playerToStreamerTime:Math.ceil(Array.from(this.records.values()).reduce(((e,t)=>e+(t.streamerReceivedTimestamp-t.playerSentTimestamp)),0)/this.records.size),streamerToPlayerTime:Math.ceil(Array.from(this.records.values()).reduce(((e,t)=>e+(t.playerReceivedTimestamp-t.streamerSentTimestamp)),0)/this.records.size),exportLatencyAsCSV:()=>{let t="Timestamp;RTT;PlayerToStreamer;StreamerToPlayer;\n";return e.forEach((e=>{t+=e.playerSentTimestamp+";",t+=e.playerReceivedTimestamp-e.playerSentTimestamp+";",t+=e.streamerReceivedTimestamp-e.playerSentTimestamp+";",t+=e.playerReceivedTimestamp-e.streamerSentTimestamp+";",t+="\n"})),t}}}isRunning(){return!!this.interval}receive(e){if(!this.isRunning())return;if(!e)return void s.Error(s.GetStackTrace(),"Undefined response from server");let t=this.records.get(e.Seq);t&&t.update(e)}sendRequest(e,t){let s=this.createRequest(e,t),n=new Ft(s);this.records.set(n.seq,n),this.sink(s)}createRequest(e,t){return{Seq:this.seq++,FillResponseSize:t,Filler:e?"A".repeat(e):""}}}class Ot{constructor(e,t){this.allowConsoleCommands=!1,this.config=e,(null==t?void 0:t.videoElementParent)&&(this._videoElementParent=t.videoElementParent),this._eventEmitter=new ye,this.configureSettings(),this.setWebRtcPlayerController(new Rt(this.config,this)),this.onScreenKeyboardHelper=new At(this.videoElementParent),this.onScreenKeyboardHelper.unquantizeAndDenormalizeUnsigned=(e,t)=>this._webRtcController.requestUnquantizedAndDenormalizeUnsigned(e,t),this._activateOnScreenKeyboard=e=>this.onScreenKeyboardHelper.showOnScreenKeyboard(e),this._webXrController=new xt(this._webRtcController)}get videoElementParent(){return this._videoElementParent||(this._videoElementParent=document.createElement("div"),this._videoElementParent.id="videoElementParent"),this._videoElementParent}configureSettings(){this.config._addOnSettingChangedListener(Ee.IsQualityController,(e=>{!0!==e||this._webRtcController.isQualityController||this._webRtcController.sendRequestQualityControlOwnership()})),this.config._addOnSettingChangedListener(Ee.AFKDetection,(e=>{this._webRtcController.setAfkEnabled(e)})),this.config._addOnSettingChangedListener(Ee.MatchViewportResolution,(()=>{this._webRtcController.videoPlayer.updateVideoStreamSize()})),this.config._addOnSettingChangedListener(Ee.HoveringMouseMode,(e=>{this.config.setFlagLabel(Ee.HoveringMouseMode,`Control Scheme: ${e?"Hovering":"Locked"} Mouse`),this._webRtcController.setMouseInputEnabled(this.config.isFlagEnabled(Ee.MouseInput))})),this.config._addOnSettingChangedListener(Ee.KeyboardInput,(e=>{this._webRtcController.setKeyboardInputEnabled(e)})),this.config._addOnSettingChangedListener(Ee.MouseInput,(e=>{this._webRtcController.setMouseInputEnabled(e)})),this.config._addOnSettingChangedListener(Ee.TouchInput,(e=>{this._webRtcController.setTouchInputEnabled(e)})),this.config._addOnSettingChangedListener(Ee.GamepadInput,(e=>{this._webRtcController.setGamePadInputEnabled(e)})),this.config._addOnNumericSettingChangedListener(we.MinQP,(e=>{s.Log(s.GetStackTrace(),"-------- Sending MinQP --------",7),this._webRtcController.sendEncoderMinQP(e),s.Log(s.GetStackTrace(),"-------------------------------------------",7)})),this.config._addOnNumericSettingChangedListener(we.MaxQP,(e=>{s.Log(s.GetStackTrace(),"-------- Sending encoder settings --------",7),this._webRtcController.sendEncoderMaxQP(e),s.Log(s.GetStackTrace(),"-------------------------------------------",7)})),this.config._addOnNumericSettingChangedListener(we.WebRTCMinBitrate,(e=>{s.Log(s.GetStackTrace(),"-------- Sending web rtc settings --------",7),this._webRtcController.sendWebRTCMinBitrate(1e3*e),s.Log(s.GetStackTrace(),"-------------------------------------------",7)})),this.config._addOnNumericSettingChangedListener(we.WebRTCMaxBitrate,(e=>{s.Log(s.GetStackTrace(),"-------- Sending web rtc settings --------",7),this._webRtcController.sendWebRTCMaxBitrate(1e3*e),s.Log(s.GetStackTrace(),"-------------------------------------------",7)})),this.config._addOnNumericSettingChangedListener(we.WebRTCFPS,(e=>{s.Log(s.GetStackTrace(),"-------- Sending web rtc settings --------",7),this._webRtcController.sendWebRTCFps(e),s.Log(s.GetStackTrace(),"-------------------------------------------",7)})),this.config._addOnOptionSettingChangedListener(ke.PreferredCodec,(e=>{this._webRtcController&&this._webRtcController.setPreferredCodec(e)})),this.config._registerOnChangeEvents(this._eventEmitter)}_activateOnScreenKeyboard(e){throw new Error("Method not implemented.")}_onInputControlOwnership(e){this._inputController=e}setWebRtcPlayerController(e){this._webRtcController=e,this._webRtcController.setPreferredCodec(this.config.getSettingOption(ke.PreferredCodec).selected),this._webRtcController.resizePlayerStyle(),this.checkForAutoConnect()}connect(){this._eventEmitter.dispatchEvent(new te),this._webRtcController.connectToSignallingServer()}reconnect(){this._eventEmitter.dispatchEvent(new ne),this._webRtcController.tryReconnect("Reconnecting...")}disconnect(){this._eventEmitter.dispatchEvent(new se),this._webRtcController.close()}play(){this._onStreamLoading(),this._webRtcController.playStream()}checkForAutoConnect(){this.config.isFlagEnabled(Ee.AutoConnect)&&(this._onWebRtcAutoConnect(),this._webRtcController.connectToSignallingServer())}unmuteMicrophone(e=!1){if(!this.config.isFlagEnabled("UseMic"))return e?(this.config.setFlagEnabled("UseMic",!0),void this.reconnect()):void s.Warning(s.GetStackTrace(),"Trying to unmute mic, but PixelStreaming was initialized with no microphone track. Call with forceEnable == true to re-connect with a mic track.");this.setMicrophoneMuted(!1)}muteMicrophone(){this.config.isFlagEnabled("UseMic")?this.setMicrophoneMuted(!0):s.Info(s.GetStackTrace(),"Trying to mute mic, but PixelStreaming has no microphone track, so sending sound is already disabled.")}setMicrophoneMuted(e){var t,s,n,r;for(const i of null!==(r=null===(n=null===(s=null===(t=this._webRtcController)||void 0===t?void 0:t.peerConnectionController)||void 0===s?void 0:s.peerConnection)||void 0===n?void 0:n.getTransceivers())&&void 0!==r?r:[])Ne.canTransceiverSendAudio(i)&&(i.sender.track.enabled=!e)}_onWebRtcAutoConnect(){this._eventEmitter.dispatchEvent(new K)}_onWebRtcSdp(){this._eventEmitter.dispatchEvent(new N)}_onStreamLoading(){this._eventEmitter.dispatchEvent(new ee)}_onDisconnect(e,t){this._eventEmitter.dispatchEvent(new X({eventString:e,allowClickToReconnect:t}))}_onWebRtcConnecting(){this._eventEmitter.dispatchEvent(new Q)}_onWebRtcConnected(){this._eventEmitter.dispatchEvent(new q)}_onWebRtcFailed(){this._eventEmitter.dispatchEvent(new $)}_onVideoInitialized(){this._eventEmitter.dispatchEvent(new Z),this._videoStartTime=Date.now()}_onLatencyTestResult(e){this._eventEmitter.dispatchEvent(new ue({latencyTimings:e}))}_onDataChannelLatencyTestResponse(e){this._eventEmitter.dispatchEvent(new ge({response:e}))}_onVideoStats(e){this._videoStartTime&&void 0!==this._videoStartTime||(this._videoStartTime=Date.now()),e.handleSessionStatistics(this._videoStartTime,this._inputController,this._webRtcController.videoAvgQp),this._eventEmitter.dispatchEvent(new de({aggregatedStats:e}))}_onVideoEncoderAvgQP(e){this._eventEmitter.dispatchEvent(new V({avgQP:e}))}_onInitialSettings(e){var t;this._eventEmitter.dispatchEvent(new pe({settings:e})),e.PixelStreamingSettings&&(this.allowConsoleCommands=null!==(t=e.PixelStreamingSettings.AllowPixelStreamingCommands)&&void 0!==t&&t,!1===this.allowConsoleCommands&&s.Info(s.GetStackTrace(),"-AllowPixelStreamingCommands=false, sending arbitrary console commands from browser to UE is disabled."));const n=this.config.useUrlParams,r=new URLSearchParams(window.location.search);s.Info(s.GetStackTrace(),`using URL parameters ${n}`),e.EncoderSettings&&(this.config.setNumericSetting(we.MinQP,n&&r.has(we.MinQP)?Number.parseFloat(r.get(we.MinQP)):e.EncoderSettings.MinQP),this.config.setNumericSetting(we.MaxQP,n&&r.has(we.MaxQP)?Number.parseFloat(r.get(we.MaxQP)):e.EncoderSettings.MaxQP)),e.WebRTCSettings&&(this.config.setNumericSetting(we.WebRTCMinBitrate,n&&r.has(we.WebRTCMinBitrate)?Number.parseFloat(r.get(we.WebRTCMinBitrate)):e.WebRTCSettings.MinBitrate/1e3),this.config.setNumericSetting(we.WebRTCMaxBitrate,n&&r.has(we.WebRTCMaxBitrate)?Number.parseFloat(r.get(we.WebRTCMaxBitrate)):e.WebRTCSettings.MaxBitrate/1e3),this.config.setNumericSetting(we.WebRTCFPS,n&&r.has(we.WebRTCFPS)?Number.parseFloat(r.get(we.WebRTCFPS)):e.WebRTCSettings.FPS))}_onQualityControlOwnership(e){this.config.setFlagEnabled(Ee.IsQualityController,e)}_onPlayerCount(e){this._eventEmitter.dispatchEvent(new Te({count:e}))}requestLatencyTest(){return!!this._webRtcController.videoPlayer.isVideoReady()&&(this._webRtcController.sendLatencyTest(),!0)}requestDataChannelLatencyTest(e){return!!this._webRtcController.videoPlayer.isVideoReady()&&(this._dataChannelLatencyTestController||(this._dataChannelLatencyTestController=new Dt(this._webRtcController.sendDataChannelLatencyTest.bind(this._webRtcController),(e=>{this._eventEmitter.dispatchEvent(new me({result:e}))})),this.addEventListener("dataChannelLatencyTestResponse",(({data:{response:e}})=>{this._dataChannelLatencyTestController.receive(e)}))),this._dataChannelLatencyTestController.start(e))}requestShowFps(){return!!this._webRtcController.videoPlayer.isVideoReady()&&(this._webRtcController.sendShowFps(),!0)}requestIframe(){return!!this._webRtcController.videoPlayer.isVideoReady()&&(this._webRtcController.sendIframeRequest(),!0)}emitUIInteraction(e){return!!this._webRtcController.videoPlayer.isVideoReady()&&(this._webRtcController.emitUIInteraction(e),!0)}emitCommand(e){return!(!this._webRtcController.videoPlayer.isVideoReady()||!this.allowConsoleCommands&&"ConsoleCommand"in e||(this._webRtcController.emitCommand(e),0))}emitConsoleCommand(e){return!(!this.allowConsoleCommands||!this._webRtcController.videoPlayer.isVideoReady()||(this._webRtcController.emitConsoleCommand(e),0))}addResponseEventListener(e,t){this._webRtcController.responseController.addResponseEventListener(e,t)}removeResponseEventListener(e){this._webRtcController.responseController.removeResponseEventListener(e)}dispatchEvent(e){return this._eventEmitter.dispatchEvent(e)}addEventListener(e,t){this._eventEmitter.addEventListener(e,t)}removeEventListener(e,t){this._eventEmitter.removeEventListener(e,t)}toggleXR(){this.webXrController.xrClicked()}setSignallingUrlBuilder(e){this._webRtcController.signallingUrlBuilder=e}get signallingProtocol(){return this._webRtcController.protocol}get webXrController(){return this._webXrController}registerMessageHandler(e,t,n){t!==Qe.FromStreamer||void 0!==n?t===Qe.ToStreamer&&void 0===n?this._webRtcController.streamMessageController.registerMessageHandler(t,e,(t=>this._webRtcController.sendMessageController.sendMessageToStreamer(e,t))):this._webRtcController.streamMessageController.registerMessageHandler(t,e,(e=>n(e))):s.Warning(s.GetStackTrace(),`Unable to register an undefined handler for ${e}`)}get toStreamerHandlers(){return this._webRtcController.streamMessageController.toStreamerHandlers}isReconnecting(){return this._webRtcController.isReconnecting}}})(),r})()));
package/jest.config.js ADDED
@@ -0,0 +1,18 @@
1
+ module.exports = {
2
+ preset: "ts-jest/presets/js-with-ts",
3
+ testEnvironment: "jsdom",
4
+ transform: {
5
+ "^.+\\.tsx?$": [
6
+ "ts-jest",
7
+ {
8
+ tsconfig: "tsconfig.jest.json",
9
+ },
10
+ ],
11
+ },
12
+ modulePathIgnorePatterns: ["<rootDir>/build/"],
13
+ testPathIgnorePatterns: ["<rootDir>/build/", "/node_modules/"],
14
+ globals: {
15
+ TextDecoder: TextDecoder,
16
+ TextEncoder: TextEncoder,
17
+ }
18
+ };
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@epicgames-ps/lib-pixelstreamingfrontend-ue5.5",
3
+ "version": "0.0.5",
4
+ "description": "Frontend library for Unreal Engine 5.5 Pixel Streaming",
5
+ "main": "dist/lib-pixelstreamingfrontend.js",
6
+ "module": "dist/lib-pixelstreamingfrontend.esm.js",
7
+ "types": "types/pixelstreamingfrontend.d.ts",
8
+ "sideEffects": false,
9
+ "scripts": {
10
+ "compile": "tsc --build --clean && tsc",
11
+ "build": "webpack --config webpack.prod.js",
12
+ "build-all": "cd ../../Common && npm run build && cd ../Frontend/library && npm link ../../Common && webpack --config webpack.prod.js",
13
+ "build-dev": "cd ../../Common && npm run build && cd ../Frontend/library && npm link ../../Common && webpack --config webpack.dev.js",
14
+ "lint": "eslint . --ext .js,.jsx,.ts,.tsx",
15
+ "test": "jest --detectOpenHandles --coverage=true",
16
+ "spellcheck": "cspell \"{README.md,.github/*.md,src/**/*.ts}\""
17
+ },
18
+ "devDependencies": {
19
+ "@epicgames-ps/lib-pixelstreamingcommon-ue5.5": "^0.0.3",
20
+ "@types/jest": "27.5.1",
21
+ "@types/webxr": "^0.5.1",
22
+ "@typescript-eslint/eslint-plugin": "^5.16.0",
23
+ "@typescript-eslint/parser": "^5.16.0",
24
+ "cspell": "^4.1.0",
25
+ "eslint": "^8.11.0",
26
+ "jest": "^27.5.1",
27
+ "jest-environment-jsdom": "27.5.1",
28
+ "prettier": "2.8.3",
29
+ "ts-jest": "27.1.5",
30
+ "ts-loader": "^9.4.2",
31
+ "typedoc": "^0.23.24",
32
+ "typescript": "^4.9.4",
33
+ "webpack": "^5.75.0",
34
+ "webpack-cli": "^5.0.1"
35
+ },
36
+ "dependencies": {
37
+ "sdp": "^3.1.0"
38
+ },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://github.com/EpicGames/PixelStreamingInfrastructure.git"
42
+ },
43
+ "author": "Epic Games",
44
+ "license": "MIT",
45
+ "publishConfig": {
46
+ "access": "public"
47
+ }
48
+ }
package/readme.md ADDED
@@ -0,0 +1,15 @@
1
+ ## lib-pixelstreamingfrontend
2
+
3
+ The core library for the browser/client side of Pixel Streaming experiences. **This library contains no UI.**
4
+
5
+ See [lib-pixelstreamingfrontend-ui](/Frontend/implementations/typescript) for an example of how to build UI on top of this library.
6
+
7
+ ### Key features
8
+ - Create a websocket connection to communicate with the signalling server.
9
+ - Create a WebRTC player that displays the Unreal Engine video and audio.
10
+ - Handling of input from the user and transmitting it back to Unreal Engine.
11
+ - Opens a datachannel connection sending and receiving custom data (in addition to input).
12
+
13
+ ### Adding it to your project
14
+ `npm i @epicgames-ps/lib-pixelstreamingfrontend-ue5.4`
15
+
@@ -0,0 +1,162 @@
1
+ import { Config, Flags, NumericParameters } from '../Config/Config';
2
+ import { PixelStreaming } from '../PixelStreaming/PixelStreaming';
3
+ import { AfkTimedOutEvent, AfkWarningActivateEvent, AfkWarningUpdateEvent, AfkWarningDeactivateEvent } from '../Util/EventEmitter';
4
+ import { mockRTCRtpReceiver, unmockRTCRtpReceiver } from '../__test__/mockRTCRtpReceiver';
5
+ import {
6
+ AFKController
7
+ } from './AFKController';
8
+
9
+ describe('AFKController', () => {
10
+ let mockPixelStreaming: PixelStreaming;
11
+
12
+ beforeEach(() => {
13
+ mockRTCRtpReceiver();
14
+ jest.useFakeTimers();
15
+ mockPixelStreaming = {
16
+ dispatchEvent: jest.fn()
17
+ } as any as PixelStreaming;
18
+ });
19
+
20
+ afterEach(() => {
21
+ unmockRTCRtpReceiver();
22
+ jest.resetAllMocks();
23
+ });
24
+
25
+ it('should not activate AFK timer if it has been disabled from settings', () => {
26
+ const config = new Config({ initialSettings: { [Flags.AFKDetection]: false } });
27
+ const onDismissAfk = jest.fn();
28
+ const afkController = new AFKController(config, mockPixelStreaming, onDismissAfk);
29
+
30
+ afkController.startAfkWarningTimer();
31
+ expect(afkController.active).toBe(false);
32
+
33
+ jest.advanceTimersByTime(1000000 * 1000);
34
+ expect(mockPixelStreaming.dispatchEvent).not.toHaveBeenCalled();
35
+ });
36
+
37
+ it('should activate AFK timer and trigger it after specified delay if it has been enabled from settings', () => {
38
+ const timeoutSeconds = 100;
39
+
40
+ const config = new Config({ initialSettings: { [Flags.AFKDetection]: true, [NumericParameters.AFKTimeoutSecs]: timeoutSeconds} });
41
+ const onDismissAfk = jest.fn();
42
+ const afkController = new AFKController(config, mockPixelStreaming, onDismissAfk);
43
+
44
+ afkController.startAfkWarningTimer();
45
+ expect(afkController.active).toBe(true);
46
+
47
+ // Advance to 1 second before AFK event:
48
+ jest.advanceTimersByTime((timeoutSeconds - 1) * 1000);
49
+ expect(mockPixelStreaming.dispatchEvent).not.toHaveBeenCalled();
50
+
51
+ // advance 1 more second to trigger AFK warning
52
+ jest.advanceTimersByTime(1000);
53
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningActivateEvent({
54
+ countDown: 0,
55
+ dismissAfk: expect.anything()
56
+ }));
57
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({
58
+ countDown: 10,
59
+ }));
60
+
61
+ // advance 10 more seconds to trigger AFK countdown updates and eventually timeout
62
+ jest.advanceTimersByTime(10 * 1000);
63
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({
64
+ countDown: 9,
65
+ }));
66
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({
67
+ countDown: 8,
68
+ }));
69
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({
70
+ countDown: 7,
71
+ }));
72
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({
73
+ countDown: 6,
74
+ }));
75
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({
76
+ countDown: 5,
77
+ }));
78
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({
79
+ countDown: 4,
80
+ }));
81
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({
82
+ countDown: 3,
83
+ }));
84
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({
85
+ countDown: 2,
86
+ }));
87
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({
88
+ countDown: 1,
89
+ }));
90
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkTimedOutEvent());
91
+ });
92
+
93
+ it('should postpone AFK activation each time resetAfkWarningTimer is called', () => {
94
+ const timeoutSeconds = 100;
95
+
96
+ const config = new Config({ initialSettings: { [Flags.AFKDetection]: true, [NumericParameters.AFKTimeoutSecs]: timeoutSeconds} });
97
+ const onDismissAfk = jest.fn();
98
+ const afkController = new AFKController(config, mockPixelStreaming, onDismissAfk);
99
+
100
+ afkController.startAfkWarningTimer();
101
+
102
+ // Advance to 1 second before AFK event:
103
+ jest.advanceTimersByTime((timeoutSeconds - 1) * 1000);
104
+ expect(mockPixelStreaming.dispatchEvent).not.toHaveBeenCalled();
105
+
106
+ afkController.resetAfkWarningTimer();
107
+
108
+ // advance 1 more second and ensure that AFK warning is not triggered since reset was called
109
+ jest.advanceTimersByTime(1000);
110
+ expect(mockPixelStreaming.dispatchEvent).not.toHaveBeenCalled();
111
+
112
+ // reset AFK timer once more and ensure it is triggered exactly after timeoutSeconds
113
+ afkController.resetAfkWarningTimer();
114
+
115
+ // Advance to 1 second before AFK event:
116
+ jest.advanceTimersByTime((timeoutSeconds - 1) * 1000);
117
+ expect(mockPixelStreaming.dispatchEvent).not.toHaveBeenCalled();
118
+
119
+ // advance 1 more second to trigger AFK warning
120
+ jest.advanceTimersByTime(1000);
121
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningActivateEvent({
122
+ countDown: 0,
123
+ dismissAfk: expect.anything()
124
+ }));
125
+ });
126
+
127
+ it('should dismiss AFK warning countdown if onAfkClick is called', () => {
128
+ const timeoutSeconds = 100;
129
+
130
+ const config = new Config({ initialSettings: { [Flags.AFKDetection]: true, [NumericParameters.AFKTimeoutSecs]: timeoutSeconds} });
131
+ const onDismissAfk = jest.fn();
132
+ const afkController = new AFKController(config, mockPixelStreaming, onDismissAfk);
133
+
134
+ afkController.startAfkWarningTimer();
135
+
136
+ // Advance to AFK event:
137
+ jest.advanceTimersByTime(timeoutSeconds * 1000);
138
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningActivateEvent({
139
+ countDown: 0,
140
+ dismissAfk: expect.anything()
141
+ }));
142
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({
143
+ countDown: 10,
144
+ }));
145
+
146
+ // Advance one more second and call onAfkClick
147
+ jest.advanceTimersByTime(1000);
148
+
149
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningUpdateEvent({
150
+ countDown: 9,
151
+ }));
152
+
153
+ afkController.onAfkClick();
154
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledWith(new AfkWarningDeactivateEvent());
155
+
156
+ // advance 10 more seconds and ensure there are no more countdown/timeout events emitted
157
+ jest.advanceTimersByTime(10 * 1000);
158
+ expect(mockPixelStreaming.dispatchEvent).toHaveBeenCalledTimes(4);
159
+ });
160
+
161
+
162
+ });