@arcware-cloud/pixelstreaming-websdk 1.3.3 → 1.3.6

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.
package/index.cjs.js CHANGED
@@ -23234,27 +23234,28 @@ class ArcwareApplication extends lib_pixelstreamingfrontend_ui_ue5_5_1.Applicati
23234
23234
  });
23235
23235
  }
23236
23236
  applicationResponse(response) {
23237
- var _a, _b;
23238
- let obj = null;
23237
+ var _a, _b, _c, _d;
23238
+ let obj;
23239
23239
  try {
23240
23240
  obj = (0, common_1.parseUnknownToObject)(response, { allowJsonish: true });
23241
23241
  }
23242
- catch (_c) {
23243
- // If not parseable, fall through to generic callback
23242
+ catch (_e) {
23243
+ // not parseable just send to generic handler and bail out
23244
+ (_a = this.responseCallback) === null || _a === void 0 ? void 0 : _a.call(this, response);
23245
+ return;
23244
23246
  }
23245
23247
  const t = (0, common_1.normalizeType)(obj["type"]);
23246
23248
  // route to exactly one callback
23247
23249
  if (t === "event") {
23248
- (_a = this.analyticsEventCallback) === null || _a === void 0 ? void 0 : _a.call(this, response);
23250
+ (_b = this.analyticsEventCallback) === null || _b === void 0 ? void 0 : _b.call(this, response);
23249
23251
  return;
23250
23252
  }
23251
23253
  if (t === "filetransfer" || t === "createscreenshot") {
23252
- (_b = this.fileDownloadCallback) === null || _b === void 0 ? void 0 : _b.call(this, response);
23254
+ (_c = this.fileDownloadCallback) === null || _c === void 0 ? void 0 : _c.call(this, response);
23253
23255
  return;
23254
23256
  }
23255
- if (this.responseCallback) {
23256
- this.responseCallback(response);
23257
- }
23257
+ // fallback: unknown type → generic callback
23258
+ (_d = this.responseCallback) === null || _d === void 0 ? void 0 : _d.call(this, response);
23258
23259
  }
23259
23260
  applyArcwareStyles() {
23260
23261
  const PixelStreamingApplicationStyles = new lib_pixelstreamingfrontend_ui_ue5_5_1.PixelStreamingApplicationStyle(ArcwarePixelStreamingApplicationStyles_1.ArcwareStyles);
@@ -23419,7 +23420,7 @@ class ArcwareConfig extends lib_pixelstreamingfrontend_ue5_5_1.Config {
23419
23420
  if (!config.initialSettings.ss)
23420
23421
  config.initialSettings.ss = exports.DefaultUrl;
23421
23422
  super(config);
23422
- this.VERSION = "1.3.3";
23423
+ this.VERSION = "1.3.6";
23423
23424
  this.settings = settings;
23424
23425
  this.session = new Session_1.Session();
23425
23426
  this._initialSettings = config.initialSettings;
@@ -23573,8 +23574,19 @@ const MicrophoneOverlay_1 = __webpack_require__(3613);
23573
23574
  const ConnectionIdentifier_1 = __webpack_require__(5999);
23574
23575
  const DiagnosticsCollector_1 = __webpack_require__(8429);
23575
23576
  class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStreaming {
23577
+ resetInitGuardsAndHooks() {
23578
+ this.videoInitializedSent = false;
23579
+ this._postInitSideEffectsDone = false;
23580
+ this.cancelFirstRenderedFrameHook(); // just in case
23581
+ this.attachFirstRenderedFrameOnce(); // re-arm rVFC/resize on current video element
23582
+ this.bindTransportEvents(); // ensure listeners are bound to current transport
23583
+ }
23584
+ reconnect() {
23585
+ super.reconnect();
23586
+ this.resetInitGuardsAndHooks();
23587
+ }
23576
23588
  bindTransportEvents() {
23577
- var _a, _b, _c, _d, _f, _g, _h;
23589
+ var _a, _b, _c, _d, _e, _f, _g;
23578
23590
  const current = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23579
23591
  if (!current || current === this._boundTransport)
23580
23592
  return;
@@ -23583,13 +23595,24 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23583
23595
  if (this._onWsOpen)
23584
23596
  (_c = (_b = this._boundTransport).removeEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, "open", this._onWsOpen);
23585
23597
  if (this._onWsClose)
23586
- (_f = (_d = this._boundTransport).removeEventListener) === null || _f === void 0 ? void 0 : _f.call(_d, "close", this._onWsClose);
23598
+ (_e = (_d = this._boundTransport).removeEventListener) === null || _e === void 0 ? void 0 : _e.call(_d, "close", this._onWsClose);
23587
23599
  }
23588
23600
  // Define (or reuse) callbacks
23589
23601
  if (!this._onWsOpen) {
23590
23602
  this._onWsOpen = () => {
23591
23603
  this.flushOutbox();
23592
- this.startVideoInitWatchdog(); // only start, no send
23604
+ this.attachFirstRenderedFrameOnce();
23605
+ // no watchdog anymore
23606
+ setTimeout(() => {
23607
+ var _a, _b, _c;
23608
+ if (!this.videoInitializedSent) {
23609
+ const v = (_c = (_b = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement) === null || _c === void 0 ? void 0 : _c.call(_b);
23610
+ if (v && v.videoWidth > 0 && v.videoHeight > 0 && v.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) {
23611
+ this.sendVideoInitializedOnce();
23612
+ this.runPostInitSideEffectsOnce();
23613
+ }
23614
+ }
23615
+ }, 1200);
23593
23616
  };
23594
23617
  }
23595
23618
  if (!this._onWsClose) {
@@ -23599,85 +23622,10 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23599
23622
  };
23600
23623
  }
23601
23624
  // Bind to current
23602
- (_g = current.addEventListener) === null || _g === void 0 ? void 0 : _g.call(current, "open", this._onWsOpen);
23603
- (_h = current.addEventListener) === null || _h === void 0 ? void 0 : _h.call(current, "close", this._onWsClose);
23625
+ (_f = current.addEventListener) === null || _f === void 0 ? void 0 : _f.call(current, "open", this._onWsOpen);
23626
+ (_g = current.addEventListener) === null || _g === void 0 ? void 0 : _g.call(current, "close", this._onWsClose);
23604
23627
  this._boundTransport = current;
23605
23628
  }
23606
- // conservative media-evidence check (no stats involved)
23607
- hasMediaEvidence() {
23608
- var _a, _b, _c;
23609
- const videoEl = (_c = (_b = (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement) === null || _c === void 0 ? void 0 : _c.call(_b);
23610
- if (!videoEl)
23611
- return false;
23612
- const dimensions = videoEl.videoWidth > 0 && videoEl.videoHeight > 0;
23613
- const ready = videoEl.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA; // >= 2
23614
- const activelyPlaying = !videoEl.paused && !videoEl.ended;
23615
- // Require at least two signals to avoid false positives on metadata-only loads
23616
- const strong = (dimensions && ready) || (dimensions && activelyPlaying) || (ready && activelyPlaying);
23617
- // also allow explicit 'playing' evidence we latched separately
23618
- return strong || this.seenVideoPlaying;
23619
- }
23620
- startVideoInitWatchdog() {
23621
- // restart the interval
23622
- this.stopVideoInitWatchdog();
23623
- const startedAt = Date.now();
23624
- this.videoInitWatchdogInterval = window.setInterval(() => {
23625
- if (this.videoInitializedSent) {
23626
- this.stopVideoInitWatchdog();
23627
- return;
23628
- }
23629
- if (this.hasMediaEvidence()) {
23630
- this.sendVideoInitializedOnce();
23631
- this.stopVideoInitWatchdog();
23632
- return;
23633
- }
23634
- // Optional maximum wait: if set and exceeded, backfill only if we saw playing
23635
- if (this.videoInitMaxWaitMs && Date.now() - startedAt > this.videoInitMaxWaitMs) {
23636
- if (this.seenVideoPlaying && !this.videoInitializedSent) {
23637
- this.sendVideoInitializedOnce();
23638
- }
23639
- this.stopVideoInitWatchdog();
23640
- }
23641
- }, this.videoInitCheckMs);
23642
- }
23643
- stopVideoInitWatchdog() {
23644
- if (this.videoInitWatchdogInterval) {
23645
- window.clearInterval(this.videoInitWatchdogInterval);
23646
- this.videoInitWatchdogInterval = undefined;
23647
- }
23648
- }
23649
- startTransportWatcher() {
23650
- // Rebind if the transport object reference changes (cheap safety net)
23651
- if (this._transportWatchTimer)
23652
- return;
23653
- this._transportWatchTimer = window.setInterval(() => {
23654
- var _a;
23655
- const cur = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23656
- if (cur && cur !== this._boundTransport)
23657
- this.bindTransportEvents();
23658
- }, 3000); // light-touch; adjust if you like
23659
- }
23660
- stopTransportWatcher() {
23661
- if (this._transportWatchTimer) {
23662
- window.clearInterval(this._transportWatchTimer);
23663
- this._transportWatchTimer = undefined;
23664
- }
23665
- }
23666
- bindVideoElPlayingOnce() {
23667
- var _a, _b, _c;
23668
- const videoEl = (_c = (_b = (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement) === null || _c === void 0 ? void 0 : _c.call(_b);
23669
- if (!videoEl || videoEl === this._boundVideoEl)
23670
- return;
23671
- // Unbind older one if replaced
23672
- if (this._boundVideoEl && this._onVideoPlaying) {
23673
- this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
23674
- }
23675
- this._onVideoPlaying = () => {
23676
- this.seenVideoPlaying = true;
23677
- };
23678
- videoEl.addEventListener("playing", this._onVideoPlaying, { once: true });
23679
- this._boundVideoEl = videoEl;
23680
- }
23681
23629
  get isWsOpen() {
23682
23630
  var _a, _b;
23683
23631
  const ws = (_b = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport) === null || _b === void 0 ? void 0 : _b.webSocket;
@@ -23698,7 +23646,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23698
23646
  return state !== undefined ? state : WebSocket.CLOSED;
23699
23647
  }
23700
23648
  constructor(config, overrides) {
23701
- var _a, _b, _c, _d, _f, _g, _h;
23649
+ var _a, _b, _c;
23702
23650
  /** As soon as upstream is fixed, we got to adjust the url building process. */
23703
23651
  (0, ApplyUrlHack_1.ApplyUrlHack)();
23704
23652
  super(config, overrides);
@@ -23706,25 +23654,18 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23706
23654
  this.isProcessingQueue = false;
23707
23655
  // --- reliable send / idempotence ---
23708
23656
  this.outbox = [];
23709
- this.retryTimers = new Map(); // reserved if you later add ACKs
23710
23657
  this.videoInitializedSent = false;
23711
- this.versionReplyInFlight = false;
23712
- this.nextMsgId = 1;
23713
- this.videoInitCheckMs = 250; // default poll; can be overridden from config
23714
- this.seenVideoPlaying = false;
23658
+ // --- first-frame (rVFC) detection + element swap handling ---
23659
+ this._rVFCsupported = "requestVideoFrameCallback" in HTMLVideoElement.prototype;
23660
+ this._postInitSideEffectsDone = false;
23715
23661
  // Externalized
23716
- /** On ping the session creation timestamp will be updated. */
23717
23662
  this.queueHandler = new EventHandler_1.EventHandler();
23718
- /** Error receiver. */
23719
23663
  this.errorHandler = new EventHandler_1.EventHandler();
23720
- /** LoveLetter */
23721
23664
  this.loveLetterHandler = new EventHandler_1.EventHandler();
23722
- /** SessionId */
23723
23665
  this.sessionIdHandler = new EventHandler_1.EventHandler();
23724
- /** VideoInitialized */
23666
+ /** VideoInitialized (native Epic event) */
23725
23667
  this.videoInitializedHandler = new EventHandler_1.EventHandler();
23726
23668
  // Internal
23727
- /** WebSocket Close */
23728
23669
  this.websocketOnCloseHandler = new EventHandler_1.EventHandler();
23729
23670
  /** Theoretically this call should be used to implement the signalling url, but this would not work at all, if config is setup for "AutoConnect=true"
23730
23671
  * Instead we use ApplyUrlHack();
@@ -23737,19 +23678,15 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23737
23678
  const transport = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23738
23679
  (_b = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _b === void 0 ? void 0 : _b.call(transport, "open", () => {
23739
23680
  this.flushOutbox();
23740
- this.startVideoInitWatchdog(); // only start, no send
23681
+ // no polling watchdog
23741
23682
  });
23742
23683
  (_c = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _c === void 0 ? void 0 : _c.call(transport, "close", (evt) => {
23743
- // Bubble to your public close handler if you expose one
23744
23684
  if (this.websocketOnCloseHandler) {
23745
23685
  EventHandler_1.EventHandler.Emit(this.websocketOnCloseHandler, evt);
23746
23686
  }
23747
23687
  });
23748
- this.setupVideoInitFallbacks();
23749
23688
  // Set override config.
23750
23689
  this.config = config;
23751
- this.videoInitCheckMs = (_f = (_d = this.config.settings) === null || _d === void 0 ? void 0 : _d.videoInitCheckMs) !== null && _f !== void 0 ? _f : this.videoInitCheckMs;
23752
- this.videoInitMaxWaitMs = (_h = (_g = this.config.settings) === null || _g === void 0 ? void 0 : _g.videoInitMaxWaitMs) !== null && _h !== void 0 ? _h : undefined;
23753
23690
  this.loveLettersList = [];
23754
23691
  this.microphoneOverlay = new MicrophoneOverlay_1.MicrophoneOverlay(this);
23755
23692
  this.diagnosticsCollector = new DiagnosticsCollector_1.DiagnosticsCollector({
@@ -23758,9 +23695,9 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23758
23695
  // after super(...) and once webRtcController is available
23759
23696
  this.bindTransportEvents();
23760
23697
  this.startTransportWatcher();
23761
- // ensure video 'playing' fallback is attached to the current element
23762
- this.bindVideoElPlayingOnce();
23763
- // this.loveLettersContainer = null;
23698
+ // Arm first-frame detector & watch for element swaps
23699
+ this.attachFirstRenderedFrameOnce();
23700
+ this.watchVideoElementReplacement();
23764
23701
  this.wrapWebSocketOnCloseHandler();
23765
23702
  // Bind the event listener function to the class instance
23766
23703
  this.handleResolutionChange = this.handleResolutionChange.bind(this);
@@ -23828,14 +23765,13 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23828
23765
  (_a = lib_pixelstreamingfrontend_ue5_5_1.Logger.Warning) === null || _a === void 0 ? void 0 : _a.call(lib_pixelstreamingfrontend_ue5_5_1.Logger, `Diagnostics collection failed: ${(_b = e === null || e === void 0 ? void 0 : e.message) !== null && _b !== void 0 ? _b : e}`);
23829
23766
  }
23830
23767
  finally {
23831
- // Build payload with required fields only; append diagnostics if available
23832
23768
  const payload = {
23833
23769
  type: "version",
23834
23770
  version: this.config.VERSION
23835
23771
  };
23836
23772
  if (diagnostics !== undefined)
23837
23773
  payload.diagnostics = diagnostics;
23838
- this.send(payload); // uses your buffered send
23774
+ this.send(payload); // uses buffered send
23839
23775
  }
23840
23776
  });
23841
23777
  }
@@ -23848,14 +23784,10 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23848
23784
  this.session.set(this.session.current);
23849
23785
  }
23850
23786
  /** Handle incoming configurations. */
23851
- // public readonly streamInfoHandler = new EventHandler<never>();
23852
23787
  onStreamInfo(streamInfo) {
23853
23788
  var _a, _b, _c, _d;
23854
23789
  lib_pixelstreamingfrontend_ue5_5_1.Logger.Info(`StreamInfo received.`);
23855
- // Save the streamInfo to the instance variable
23856
23790
  this.streamInfo = streamInfo;
23857
- // By setting this hidden flag, the evaluation of the streamInfo can be cut off.
23858
- // Cutting of the streamInfo can lead to unwanted behavior, therefore it's not advertised.
23859
23791
  if (!((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b["do-not-eval-streamInfo"])) {
23860
23792
  const { afk } = streamInfo.streamInfo;
23861
23793
  if (afk) {
@@ -23865,7 +23797,6 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23865
23797
  const { afkController } = this.webRtcController;
23866
23798
  afkController.countDown = afk.action;
23867
23799
  }
23868
- // Relevant settings need to be interpreted when they come through the streamInfo to the client.
23869
23800
  if ((_c = streamInfo.streamInfo.webSdkSettings) === null || _c === void 0 ? void 0 : _c.init) {
23870
23801
  this.config.setSettings(streamInfo.streamInfo.webSdkSettings.init);
23871
23802
  }
@@ -23880,7 +23811,6 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23880
23811
  }
23881
23812
  this.handleMouseLock();
23882
23813
  this.injectCustomUI();
23883
- // EventHandler.Emit(this.streamInfoHandler, undefined as never);
23884
23814
  }
23885
23815
  onQueue(message) {
23886
23816
  lib_pixelstreamingfrontend_ue5_5_1.Logger.Info(`QueueInfo received.`);
@@ -23891,7 +23821,6 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23891
23821
  EventHandler_1.EventHandler.Emit(this.errorHandler, error);
23892
23822
  }
23893
23823
  onLoveLetter(loveLetter) {
23894
- // Logger.Info(Logger.GetStackTrace(), loveLetter.reason);
23895
23824
  if (this.config.settings.loveLetterLogging)
23896
23825
  console.info(loveLetter.reason);
23897
23826
  EventHandler_1.EventHandler.Emit(this.loveLetterHandler, loveLetter);
@@ -23899,7 +23828,6 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23899
23828
  }
23900
23829
  onSessionId(message) {
23901
23830
  lib_pixelstreamingfrontend_ue5_5_1.Logger.Info(message.sessionId);
23902
- // console.info(`Session: ${message.sessionId}`);
23903
23831
  this.session.set(message.sessionId);
23904
23832
  EventHandler_1.EventHandler.Emit(this.sessionIdHandler, message.sessionId);
23905
23833
  }
@@ -23907,59 +23835,112 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23907
23835
  if (this.videoInitializedSent)
23908
23836
  return;
23909
23837
  this.videoInitializedSent = true;
23910
- // Use withId if you plan to support idempotence on the server
23911
- this.send(/* this.withId( */ { type: "onVideoInitialized" } /* ) */);
23838
+ // cancel rVFC if still armed (we've already initialized)
23839
+ this.cancelFirstRenderedFrameHook();
23840
+ this.send({ type: "onVideoInitialized" });
23912
23841
  if (this.videoInitializedHandler) {
23913
23842
  EventHandler_1.EventHandler.Emit(this.videoInitializedHandler, undefined);
23914
23843
  }
23915
23844
  }
23916
- // Attach fallbacks once (call this in constructor after transport wiring)
23917
- setupVideoInitFallbacks() {
23918
- var _a, _b, _c, _d, _f, _g, _h;
23919
- // Fallback #1: HTMLVideoElement 'playing'
23920
- const videoEl = (_c = (_b = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement) === null || _c === void 0 ? void 0 : _c.call(_b);
23921
- (_d = videoEl === null || videoEl === void 0 ? void 0 : videoEl.addEventListener) === null || _d === void 0 ? void 0 : _d.call(videoEl, "playing", () => {
23922
- this.seenVideoPlaying = true;
23923
- }, { once: true });
23924
- (_f = this.addEventListener) === null || _f === void 0 ? void 0 : _f.call(this, "statsReceived", (_e) => {
23925
- /* no-op for video init */
23926
- });
23927
- // Fallback #3: after socket opens, give it a tick
23928
- const transport = (_g = this.webRtcController) === null || _g === void 0 ? void 0 : _g.transport;
23929
- (_h = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _h === void 0 ? void 0 : _h.call(transport, "open", () => {
23930
- this.startVideoInitWatchdog(); // only start, no send
23931
- });
23932
- }
23933
- onVideoInitialized() {
23934
- var _a, _b, _c, _d, _f, _g, _h;
23935
- // send early and once
23936
- this.stopVideoInitWatchdog(); // PS event arrived, cancel backup
23937
- this.sendVideoInitializedOnce();
23938
- // keep side-effects guarded so they can't break the send
23845
+ runPostInitSideEffectsOnce() {
23846
+ var _a, _b, _c, _d, _e, _f, _g;
23847
+ if (this._postInitSideEffectsDone)
23848
+ return;
23849
+ this._postInitSideEffectsDone = true;
23939
23850
  try {
23940
23851
  (_a = this.handleMouseLock) === null || _a === void 0 ? void 0 : _a.call(this);
23941
23852
  }
23942
- catch (_j) { }
23853
+ catch (_h) { }
23943
23854
  try {
23944
23855
  (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23945
23856
  }
23946
- catch (_k) { }
23857
+ catch (_j) { }
23947
23858
  try {
23948
23859
  (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23949
23860
  }
23861
+ catch (_k) { }
23862
+ try {
23863
+ (_e = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _e === void 0 ? void 0 : _e.call(_d, false);
23864
+ }
23950
23865
  catch (_l) { }
23951
23866
  try {
23952
- (_f = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _f === void 0 ? void 0 : _f.call(_d, false);
23867
+ (_f = this.applyResolutionIfPlaying) === null || _f === void 0 ? void 0 : _f.call(this);
23953
23868
  }
23954
23869
  catch (_m) { }
23955
23870
  try {
23956
- (_g = this.applyResolutionIfPlaying) === null || _g === void 0 ? void 0 : _g.call(this);
23871
+ (_g = this.removeXRIconIfDisabled) === null || _g === void 0 ? void 0 : _g.call(this);
23957
23872
  }
23958
23873
  catch (_o) { }
23874
+ }
23875
+ onVideoInitialized() {
23876
+ if (this.videoInitializedSent) {
23877
+ // Init was already sent by rVFC; ensure side-effects run once, then bail.
23878
+ this.runPostInitSideEffectsOnce();
23879
+ return;
23880
+ }
23881
+ //console.log("Ran from Epic");
23882
+ this.sendVideoInitializedOnce();
23883
+ this.runPostInitSideEffectsOnce();
23884
+ }
23885
+ // --- First-frame detection (rVFC/resize) ---
23886
+ attachFirstRenderedFrameOnce() {
23887
+ var _a, _b, _c, _d;
23888
+ const v = (_c = (_b = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement) === null || _c === void 0 ? void 0 : _c.call(_b);
23889
+ if (!v)
23890
+ return;
23891
+ if (this._rVFCArmedForElement === v)
23892
+ return;
23893
+ this.cancelFirstRenderedFrameHook();
23894
+ this._rVFCArmedForElement = v;
23895
+ // Modern path
23896
+ if (this._rVFCsupported) {
23897
+ const anyV = v;
23898
+ this._rvfcHandle = (_d = anyV.requestVideoFrameCallback) === null || _d === void 0 ? void 0 : _d.call(anyV, (_now, _meta) => {
23899
+ this.sendVideoInitializedOnce();
23900
+ this.runPostInitSideEffectsOnce();
23901
+ this._rvfcHandle = undefined;
23902
+ });
23903
+ }
23904
+ // Always attach resize once as a parallel fallback
23905
+ const onResize = () => {
23906
+ v.removeEventListener("resize", onResize);
23907
+ this.sendVideoInitializedOnce();
23908
+ this.runPostInitSideEffectsOnce();
23909
+ };
23910
+ v.addEventListener("resize", onResize, { once: true });
23911
+ }
23912
+ cancelFirstRenderedFrameHook() {
23913
+ var _a;
23914
+ const v = this._rVFCArmedForElement;
23915
+ if (!v)
23916
+ return;
23917
+ if (this._rvfcHandle && "cancelVideoFrameCallback" in HTMLVideoElement.prototype) {
23918
+ const anyV = v;
23919
+ try {
23920
+ (_a = anyV.cancelVideoFrameCallback) === null || _a === void 0 ? void 0 : _a.call(anyV, this._rvfcHandle);
23921
+ }
23922
+ catch (_b) { }
23923
+ }
23924
+ this._rvfcHandle = undefined;
23925
+ this._rVFCArmedForElement = undefined;
23926
+ }
23927
+ watchVideoElementReplacement() {
23928
+ var _a, _b, _c, _d;
23929
+ // Observe the player container; if a new <video> is inserted/replaced, re-arm rVFC
23959
23930
  try {
23960
- (_h = this.removeXRIconIfDisabled) === null || _h === void 0 ? void 0 : _h.call(this);
23931
+ const parent = (_c = (_b = (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoParentElement) === null || _c === void 0 ? void 0 : _c.call(_b);
23932
+ if (!parent)
23933
+ return;
23934
+ (_d = this._mo) === null || _d === void 0 ? void 0 : _d.disconnect();
23935
+ this._mo = new MutationObserver(() => {
23936
+ // Try to re-attach on any child change (cheap and reliable)
23937
+ this.attachFirstRenderedFrameOnce();
23938
+ });
23939
+ this._mo.observe(parent, { childList: true, subtree: true });
23940
+ }
23941
+ catch (_e) {
23942
+ // noop
23961
23943
  }
23962
- catch (_p) { }
23963
23944
  }
23964
23945
  /** Adding a zod-safe handler. */
23965
23946
  addMessageHandler(type, zod, boundMethod) {
@@ -23968,13 +23949,12 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23968
23949
  if (parsed.success)
23969
23950
  boundMethod.call(this, parsed.data);
23970
23951
  else {
23971
- // This cast has to be done, since Frontend does not use typescript-strict setting.
23972
23952
  const parsedError = parsed;
23973
23953
  const error = new Error(`Unexpected message content. Event:'${type}', ZodError: ${parsedError.error.message}`);
23974
23954
  lib_pixelstreamingfrontend_ue5_5_1.Logger.Error(error.message);
23975
23955
  }
23976
23956
  if (type === "error") {
23977
- //this.disconnect();
23957
+ // this.disconnect();
23978
23958
  }
23979
23959
  });
23980
23960
  }
@@ -23985,7 +23965,6 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23985
23965
  */
23986
23966
  sendStats(stats) {
23987
23967
  const message = { type: "stats", stats: (0, Stats_1.Stats)(stats) };
23988
- // This cast has to be done, since Frontend does not use typescript-strict setting.
23989
23968
  this.send(message);
23990
23969
  }
23991
23970
  send(a, b) {
@@ -24026,22 +24005,18 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24026
24005
  this.signallingProtocol.sendMessage(m);
24027
24006
  }
24028
24007
  catch (_a) {
24029
- // if we fail mid-flush, put remaining back and bail
24030
24008
  this.outbox.unshift(m, ...batch.slice(batch.indexOf(m) + 1));
24031
24009
  break;
24032
24010
  }
24033
24011
  }
24034
24012
  }
24035
24013
  handleResolutionChange() {
24036
- var _a, _b, _c, _d, _f, _g, _h;
24037
- // Get the resolution from the streamInfo if available
24014
+ var _a, _b, _c, _d, _e, _f, _g;
24038
24015
  if (!(this === null || this === void 0 ? void 0 : this.streamInfo) || !(this === null || this === void 0 ? void 0 : this.webRtcController) || !((_b = (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement())) {
24039
24016
  return;
24040
24017
  }
24041
- // Get the resolution from the streamInfo if available
24042
24018
  const resolution = (_d = (_c = this === null || this === void 0 ? void 0 : this.streamInfo) === null || _c === void 0 ? void 0 : _c.streamInfo) === null || _d === void 0 ? void 0 : _d.resolution;
24043
- const unrealVersion = (_h = (_g = (_f = this === null || this === void 0 ? void 0 : this.streamInfo) === null || _f === void 0 ? void 0 : _f.streamInfo) === null || _g === void 0 ? void 0 : _g.meta) === null || _h === void 0 ? void 0 : _h.version;
24044
- // Check if resolution.dynamic is true
24019
+ const unrealVersion = (_g = (_f = (_e = this === null || this === void 0 ? void 0 : this.streamInfo) === null || _e === void 0 ? void 0 : _e.streamInfo) === null || _f === void 0 ? void 0 : _f.meta) === null || _g === void 0 ? void 0 : _g.version;
24045
24020
  if (resolution && (resolution === null || resolution === void 0 ? void 0 : resolution.dynamic)) {
24046
24021
  setTimeout(() => {
24047
24022
  var _a;
@@ -24049,32 +24024,24 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24049
24024
  const videoElementParent = videoPlayer === null || videoPlayer === void 0 ? void 0 : videoPlayer.getVideoParentElement();
24050
24025
  const browserWidth = videoElementParent === null || videoElementParent === void 0 ? void 0 : videoElementParent.getBoundingClientRect().width;
24051
24026
  const browserHeight = videoElementParent === null || videoElementParent === void 0 ? void 0 : videoElementParent.getBoundingClientRect().height;
24052
- // Define maximum allowed resolution
24053
24027
  const maxWidth = resolution === null || resolution === void 0 ? void 0 : resolution.width;
24054
24028
  const maxHeight = resolution === null || resolution === void 0 ? void 0 : resolution.height;
24055
- // Calculate the aspect ratio of the browser viewport
24056
24029
  const aspectRatio = browserWidth / browserHeight;
24057
- // Calculate the new width and height based on the aspect ratio
24058
24030
  let limitedWidth, limitedHeight;
24059
24031
  if (aspectRatio > maxWidth / maxHeight) {
24060
- // Width is the limiting factor
24061
24032
  limitedWidth = maxWidth;
24062
24033
  limitedHeight = maxWidth / aspectRatio;
24063
24034
  }
24064
24035
  else {
24065
- // Height is the limiting factor
24066
24036
  limitedHeight = maxHeight;
24067
24037
  limitedWidth = maxHeight * aspectRatio;
24068
24038
  }
24069
24039
  if (videoPlayer) {
24070
- // Check Unreal Engine version
24071
24040
  if (!unrealVersion || (unrealVersion === null || unrealVersion === void 0 ? void 0 : unrealVersion.startsWith("4.27"))) {
24072
- // Use the aspect ratio limited resolution for the r.setres command
24073
24041
  const descriptor = { Console: `r.setres ${Math.round(limitedWidth)}x${Math.round(limitedHeight)}w` };
24074
24042
  (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.emitUIInteraction(descriptor);
24075
24043
  }
24076
24044
  else {
24077
- // Use the aspect ratio limited resolution for the onMatchViewportResolutionCallback
24078
24045
  videoPlayer.onMatchViewportResolutionCallback(Math.round(limitedWidth), Math.round(limitedHeight));
24079
24046
  }
24080
24047
  }
@@ -24093,21 +24060,39 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24093
24060
  }
24094
24061
  }
24095
24062
  removePlayer() {
24096
- var _a, _b, _c, _d;
24097
- this.stopVideoInitWatchdog(); // PS event arrived, cancel backup
24063
+ var _a, _b, _c, _d, _e;
24098
24064
  this.stopTransportWatcher();
24099
- // Optional: unbind handlers
24065
+ // Unbind transport listeners
24100
24066
  if (this._boundTransport) {
24101
24067
  if (this._onWsOpen)
24102
24068
  (_b = (_a = this._boundTransport).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, "open", this._onWsOpen);
24103
24069
  if (this._onWsClose)
24104
24070
  (_d = (_c = this._boundTransport).removeEventListener) === null || _d === void 0 ? void 0 : _d.call(_c, "close", this._onWsClose);
24105
24071
  }
24106
- if (this._boundVideoEl && this._onVideoPlaying) {
24107
- this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
24072
+ // Cancel rVFC + observer
24073
+ this.cancelFirstRenderedFrameHook();
24074
+ try {
24075
+ (_e = this._mo) === null || _e === void 0 ? void 0 : _e.disconnect();
24108
24076
  }
24077
+ catch (_f) { }
24109
24078
  this.disconnect();
24110
24079
  }
24080
+ startTransportWatcher() {
24081
+ if (this._transportWatchTimer)
24082
+ return;
24083
+ this._transportWatchTimer = window.setInterval(() => {
24084
+ var _a;
24085
+ const cur = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
24086
+ if (cur && cur !== this._boundTransport)
24087
+ this.bindTransportEvents();
24088
+ }, 3000);
24089
+ }
24090
+ stopTransportWatcher() {
24091
+ if (this._transportWatchTimer) {
24092
+ window.clearInterval(this._transportWatchTimer);
24093
+ this._transportWatchTimer = undefined;
24094
+ }
24095
+ }
24111
24096
  handleMouseLock() {
24112
24097
  var _a, _b, _c;
24113
24098
  (_a = this === null || this === void 0 ? void 0 : this.config) === null || _a === void 0 ? void 0 : _a.modifyInitialSettings(!((_c = (_b = this === null || this === void 0 ? void 0 : this.streamInfo) === null || _b === void 0 ? void 0 : _b.streamInfo.meta) === null || _c === void 0 ? void 0 : _c.mouseLock));
@@ -24139,31 +24124,25 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24139
24124
  }
24140
24125
  pushLetter(letter) {
24141
24126
  var _a;
24142
- // Add the letter to the queue
24143
24127
  (_a = this === null || this === void 0 ? void 0 : this.loveLettersQueue) === null || _a === void 0 ? void 0 : _a.push(letter);
24144
- // If not already processing the queue, start processing
24145
24128
  if (!this.isProcessingQueue) {
24146
24129
  this === null || this === void 0 ? void 0 : this.processLoveLetterQueue();
24147
24130
  }
24148
24131
  }
24149
24132
  processLoveLetterQueue() {
24150
24133
  var _a, _b;
24151
- // Set the flag to indicate that we are processing the queue
24152
24134
  this.isProcessingQueue = true;
24153
- // Take the first item from the queue
24154
24135
  const letter = this.loveLettersQueue.shift();
24155
24136
  if (letter !== undefined) {
24156
24137
  const formattedLoveLetter = letter === null || letter === void 0 ? void 0 : letter.replace(/LL: |\.$/g, "");
24157
24138
  (_a = this === null || this === void 0 ? void 0 : this.loveLettersList) === null || _a === void 0 ? void 0 : _a.push(formattedLoveLetter);
24158
24139
  const loveLettersBox = new LoveLetters_1.LoveLetters();
24159
24140
  loveLettersBox === null || loveLettersBox === void 0 ? void 0 : loveLettersBox.addLetter(formattedLoveLetter, (_b = this === null || this === void 0 ? void 0 : this.loveLettersList) === null || _b === void 0 ? void 0 : _b.length);
24160
- // Process the next item in the queue after a delay
24161
24141
  setTimeout(() => {
24162
24142
  this.processLoveLetterQueue();
24163
24143
  }, 1000);
24164
24144
  }
24165
24145
  else {
24166
- // If the queue is empty, reset the flag
24167
24146
  this.isProcessingQueue = false;
24168
24147
  }
24169
24148
  }
@@ -24205,9 +24184,10 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24205
24184
  (_b = this === null || this === void 0 ? void 0 : this.microphoneOverlay) === null || _b === void 0 ? void 0 : _b.toggleMessage(enable);
24206
24185
  setTimeout(() => { var _a; return (_a = this === null || this === void 0 ? void 0 : this.microphoneOverlay) === null || _a === void 0 ? void 0 : _a.toggleVisibility(true); }, 200);
24207
24186
  setTimeout(() => {
24208
- this.videoInitializedSent = false; // <-- reset before a real media restart
24209
- this.bindVideoElPlayingOnce(); // in case a new element will appear
24210
- this.bindTransportEvents(); // cheap rebind now
24187
+ this.videoInitializedSent = false; // reset before a real media restart
24188
+ // Re-arm rVFC on the current (or new) video element
24189
+ this.attachFirstRenderedFrameOnce();
24190
+ this.bindTransportEvents();
24211
24191
  this.reconnect();
24212
24192
  }, 1000);
24213
24193
  }
@@ -24221,12 +24201,10 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24221
24201
  }
24222
24202
  onStreamingStateChange(callback) {
24223
24203
  var _a, _b, _c, _d;
24224
- // Listen to video element events
24225
24204
  const videoElement = (_b = (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement();
24226
24205
  videoElement === null || videoElement === void 0 ? void 0 : videoElement.addEventListener("play", () => callback(true));
24227
24206
  videoElement === null || videoElement === void 0 ? void 0 : videoElement.addEventListener("pause", () => callback(false));
24228
24207
  videoElement === null || videoElement === void 0 ? void 0 : videoElement.addEventListener("ended", () => callback(false));
24229
- // Listen to WebSocket events
24230
24208
  (_c = this.webRtcController) === null || _c === void 0 ? void 0 : _c.transport.addEventListener("open", () => {
24231
24209
  callback(true);
24232
24210
  });
@@ -24235,12 +24213,12 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24235
24213
  });
24236
24214
  }
24237
24215
  removeXRIconIfDisabled() {
24238
- var _a, _b, _c, _d, _f;
24216
+ var _a, _b, _c, _d, _e;
24239
24217
  if (!((_b = (_a = this === null || this === void 0 ? void 0 : this.config) === null || _a === void 0 ? void 0 : _a.initialSettings) === null || _b === void 0 ? void 0 : _b.XRControllerInput)) {
24240
24218
  (_c = this === null || this === void 0 ? void 0 : this.config) === null || _c === void 0 ? void 0 : _c.setFlagEnabled(lib_pixelstreamingfrontend_ue5_5_1.Flags.XRControllerInput, false);
24241
24219
  if (this.videoElementParent) {
24242
24220
  if ((_d = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _d === void 0 ? void 0 : _d.parentElement) {
24243
- const xrBtn = (_f = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _f === void 0 ? void 0 : _f.parentElement.querySelector("#xrBtn");
24221
+ const xrBtn = (_e = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _e === void 0 ? void 0 : _e.parentElement.querySelector("#xrBtn");
24244
24222
  xrBtn === null || xrBtn === void 0 ? void 0 : xrBtn.remove();
24245
24223
  }
24246
24224
  }
@@ -24382,7 +24360,7 @@ class ConnectionIdentifier {
24382
24360
  return;
24383
24361
  const activeStates = this.GetWebSocketStates().filter((state) => state <= WebsocketState.OPEN);
24384
24362
  if (activeStates.length === 1) {
24385
- console.log(`PixelStreaming Instance is connected.`);
24363
+ //console.log(`PixelStreaming Instance is connected.`);
24386
24364
  }
24387
24365
  else if (activeStates.length !== 0) {
24388
24366
  console.warn(`${activeStates.length} PixelStreaming Instances are connected!`);