@arcware-cloud/pixelstreaming-websdk 1.3.2 → 1.3.3

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/README.md CHANGED
@@ -80,6 +80,12 @@ For more detailed examples and advanced usage, please refer to our documentation
80
80
 
81
81
  # Changelog
82
82
 
83
+ ### 1.3.3
84
+
85
+ - adding built in functionality for filetransfer (docs will follow soon)
86
+ - added function to send events to Arcware Platform for custom analytics (this feature is alpha on backend, contact account manager if you are interested)
87
+ - some fixes to
88
+
83
89
  ### 1.2.18
84
90
 
85
91
  - fixed webpack to emit types
package/index.cjs.js CHANGED
@@ -23419,7 +23419,7 @@ class ArcwareConfig extends lib_pixelstreamingfrontend_ue5_5_1.Config {
23419
23419
  if (!config.initialSettings.ss)
23420
23420
  config.initialSettings.ss = exports.DefaultUrl;
23421
23421
  super(config);
23422
- this.VERSION = "1.3.2";
23422
+ this.VERSION = "1.3.3";
23423
23423
  this.settings = settings;
23424
23424
  this.session = new Session_1.Session();
23425
23425
  this._initialSettings = config.initialSettings;
@@ -23574,7 +23574,7 @@ const ConnectionIdentifier_1 = __webpack_require__(5999);
23574
23574
  const DiagnosticsCollector_1 = __webpack_require__(8429);
23575
23575
  class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStreaming {
23576
23576
  bindTransportEvents() {
23577
- var _a, _b, _c, _d, _e, _f, _g;
23577
+ var _a, _b, _c, _d, _f, _g, _h;
23578
23578
  const current = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23579
23579
  if (!current || current === this._boundTransport)
23580
23580
  return;
@@ -23583,15 +23583,13 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23583
23583
  if (this._onWsOpen)
23584
23584
  (_c = (_b = this._boundTransport).removeEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, "open", this._onWsOpen);
23585
23585
  if (this._onWsClose)
23586
- (_e = (_d = this._boundTransport).removeEventListener) === null || _e === void 0 ? void 0 : _e.call(_d, "close", this._onWsClose);
23586
+ (_f = (_d = this._boundTransport).removeEventListener) === null || _f === void 0 ? void 0 : _f.call(_d, "close", this._onWsClose);
23587
23587
  }
23588
23588
  // Define (or reuse) callbacks
23589
23589
  if (!this._onWsOpen) {
23590
23590
  this._onWsOpen = () => {
23591
23591
  this.flushOutbox();
23592
- // fallback nudge for videoInitialized
23593
- if (!this.videoInitializedSent)
23594
- setTimeout(() => this.sendVideoInitializedOnce(), 150);
23592
+ this.startVideoInitWatchdog(); // only start, no send
23595
23593
  };
23596
23594
  }
23597
23595
  if (!this._onWsClose) {
@@ -23601,10 +23599,53 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23601
23599
  };
23602
23600
  }
23603
23601
  // Bind to current
23604
- (_f = current.addEventListener) === null || _f === void 0 ? void 0 : _f.call(current, "open", this._onWsOpen);
23605
- (_g = current.addEventListener) === null || _g === void 0 ? void 0 : _g.call(current, "close", this._onWsClose);
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);
23606
23604
  this._boundTransport = current;
23607
23605
  }
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
+ }
23608
23649
  startTransportWatcher() {
23609
23650
  // Rebind if the transport object reference changes (cheap safety net)
23610
23651
  if (this._transportWatchTimer)
@@ -23631,7 +23672,9 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23631
23672
  if (this._boundVideoEl && this._onVideoPlaying) {
23632
23673
  this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
23633
23674
  }
23634
- this._onVideoPlaying = () => this.sendVideoInitializedOnce();
23675
+ this._onVideoPlaying = () => {
23676
+ this.seenVideoPlaying = true;
23677
+ };
23635
23678
  videoEl.addEventListener("playing", this._onVideoPlaying, { once: true });
23636
23679
  this._boundVideoEl = videoEl;
23637
23680
  }
@@ -23655,7 +23698,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23655
23698
  return state !== undefined ? state : WebSocket.CLOSED;
23656
23699
  }
23657
23700
  constructor(config, overrides) {
23658
- var _a, _b, _c;
23701
+ var _a, _b, _c, _d, _f, _g, _h;
23659
23702
  /** As soon as upstream is fixed, we got to adjust the url building process. */
23660
23703
  (0, ApplyUrlHack_1.ApplyUrlHack)();
23661
23704
  super(config, overrides);
@@ -23667,6 +23710,8 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23667
23710
  this.videoInitializedSent = false;
23668
23711
  this.versionReplyInFlight = false;
23669
23712
  this.nextMsgId = 1;
23713
+ this.videoInitCheckMs = 250; // default poll; can be overridden from config
23714
+ this.seenVideoPlaying = false;
23670
23715
  // Externalized
23671
23716
  /** On ping the session creation timestamp will be updated. */
23672
23717
  this.queueHandler = new EventHandler_1.EventHandler();
@@ -23692,6 +23737,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23692
23737
  const transport = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23693
23738
  (_b = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _b === void 0 ? void 0 : _b.call(transport, "open", () => {
23694
23739
  this.flushOutbox();
23740
+ this.startVideoInitWatchdog(); // only start, no send
23695
23741
  });
23696
23742
  (_c = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _c === void 0 ? void 0 : _c.call(transport, "close", (evt) => {
23697
23743
  // Bubble to your public close handler if you expose one
@@ -23702,6 +23748,8 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23702
23748
  this.setupVideoInitFallbacks();
23703
23749
  // Set override config.
23704
23750
  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;
23705
23753
  this.loveLettersList = [];
23706
23754
  this.microphoneOverlay = new MicrophoneOverlay_1.MicrophoneOverlay(this);
23707
23755
  this.diagnosticsCollector = new DiagnosticsCollector_1.DiagnosticsCollector({
@@ -23867,55 +23915,51 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23867
23915
  }
23868
23916
  // Attach fallbacks once (call this in constructor after transport wiring)
23869
23917
  setupVideoInitFallbacks() {
23870
- var _a, _b, _c, _d, _e, _f, _g;
23918
+ var _a, _b, _c, _d, _f, _g, _h;
23871
23919
  // Fallback #1: HTMLVideoElement 'playing'
23872
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);
23873
- (_d = videoEl === null || videoEl === void 0 ? void 0 : videoEl.addEventListener) === null || _d === void 0 ? void 0 : _d.call(videoEl, "playing", () => this.sendVideoInitializedOnce(), { once: true });
23874
- // Fallback #2: stats hook (if you emit one)
23875
- (_e = this.addEventListener) === null || _e === void 0 ? void 0 : _e.call(this, "statsReceived", (e) => {
23876
- var _a, _b;
23877
- const stats = e === null || e === void 0 ? void 0 : e.detail;
23878
- if (!this.videoInitializedSent && ((_b = (_a = stats === null || stats === void 0 ? void 0 : stats.video) === null || _a === void 0 ? void 0 : _a.framesDecoded) !== null && _b !== void 0 ? _b : 0) > 0) {
23879
- this.sendVideoInitializedOnce();
23880
- }
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 */
23881
23926
  });
23882
23927
  // Fallback #3: after socket opens, give it a tick
23883
- const transport = (_f = this.webRtcController) === null || _f === void 0 ? void 0 : _f.transport;
23884
- (_g = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _g === void 0 ? void 0 : _g.call(transport, "open", () => {
23885
- if (!this.videoInitializedSent) {
23886
- setTimeout(() => this.sendVideoInitializedOnce(), 150);
23887
- }
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
23888
23931
  });
23889
23932
  }
23890
23933
  onVideoInitialized() {
23891
- var _a, _b, _c, _d, _e, _f, _g;
23934
+ var _a, _b, _c, _d, _f, _g, _h;
23892
23935
  // send early and once
23936
+ this.stopVideoInitWatchdog(); // PS event arrived, cancel backup
23893
23937
  this.sendVideoInitializedOnce();
23894
23938
  // keep side-effects guarded so they can't break the send
23895
23939
  try {
23896
23940
  (_a = this.handleMouseLock) === null || _a === void 0 ? void 0 : _a.call(this);
23897
23941
  }
23898
- catch (_h) { }
23899
- try {
23900
- (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23901
- }
23902
23942
  catch (_j) { }
23903
23943
  try {
23904
- (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23944
+ (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23905
23945
  }
23906
23946
  catch (_k) { }
23907
23947
  try {
23908
- (_e = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _e === void 0 ? void 0 : _e.call(_d, false);
23948
+ (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23909
23949
  }
23910
23950
  catch (_l) { }
23911
23951
  try {
23912
- (_f = this.applyResolutionIfPlaying) === null || _f === void 0 ? void 0 : _f.call(this);
23952
+ (_f = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _f === void 0 ? void 0 : _f.call(_d, false);
23913
23953
  }
23914
23954
  catch (_m) { }
23915
23955
  try {
23916
- (_g = this.removeXRIconIfDisabled) === null || _g === void 0 ? void 0 : _g.call(this);
23956
+ (_g = this.applyResolutionIfPlaying) === null || _g === void 0 ? void 0 : _g.call(this);
23917
23957
  }
23918
23958
  catch (_o) { }
23959
+ try {
23960
+ (_h = this.removeXRIconIfDisabled) === null || _h === void 0 ? void 0 : _h.call(this);
23961
+ }
23962
+ catch (_p) { }
23919
23963
  }
23920
23964
  /** Adding a zod-safe handler. */
23921
23965
  addMessageHandler(type, zod, boundMethod) {
@@ -23989,14 +24033,14 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23989
24033
  }
23990
24034
  }
23991
24035
  handleResolutionChange() {
23992
- var _a, _b, _c, _d, _e, _f, _g;
24036
+ var _a, _b, _c, _d, _f, _g, _h;
23993
24037
  // Get the resolution from the streamInfo if available
23994
24038
  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())) {
23995
24039
  return;
23996
24040
  }
23997
24041
  // Get the resolution from the streamInfo if available
23998
24042
  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;
23999
- 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;
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;
24000
24044
  // Check if resolution.dynamic is true
24001
24045
  if (resolution && (resolution === null || resolution === void 0 ? void 0 : resolution.dynamic)) {
24002
24046
  setTimeout(() => {
@@ -24050,6 +24094,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24050
24094
  }
24051
24095
  removePlayer() {
24052
24096
  var _a, _b, _c, _d;
24097
+ this.stopVideoInitWatchdog(); // PS event arrived, cancel backup
24053
24098
  this.stopTransportWatcher();
24054
24099
  // Optional: unbind handlers
24055
24100
  if (this._boundTransport) {
@@ -24190,12 +24235,12 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24190
24235
  });
24191
24236
  }
24192
24237
  removeXRIconIfDisabled() {
24193
- var _a, _b, _c, _d, _e;
24238
+ var _a, _b, _c, _d, _f;
24194
24239
  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)) {
24195
24240
  (_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);
24196
24241
  if (this.videoElementParent) {
24197
24242
  if ((_d = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _d === void 0 ? void 0 : _d.parentElement) {
24198
- const xrBtn = (_e = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _e === void 0 ? void 0 : _e.parentElement.querySelector("#xrBtn");
24243
+ const xrBtn = (_f = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _f === void 0 ? void 0 : _f.parentElement.querySelector("#xrBtn");
24199
24244
  xrBtn === null || xrBtn === void 0 ? void 0 : xrBtn.remove();
24200
24245
  }
24201
24246
  }
package/index.esm.js CHANGED
@@ -23427,7 +23427,7 @@ class ArcwareConfig extends _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBP
23427
23427
  if (!config.initialSettings.ss)
23428
23428
  config.initialSettings.ss = DefaultUrl;
23429
23429
  super(config);
23430
- this.VERSION = "1.3.2";
23430
+ this.VERSION = "1.3.3";
23431
23431
  this.settings = settings;
23432
23432
  this.session = new _domain_Session__WEBPACK_IMPORTED_MODULE_0__.Session();
23433
23433
  this._initialSettings = config.initialSettings;
@@ -23599,7 +23599,7 @@ __webpack_require__.r(__webpack_exports__);
23599
23599
 
23600
23600
  class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_4__.PixelStreaming {
23601
23601
  bindTransportEvents() {
23602
- var _a, _b, _c, _d, _e, _f, _g;
23602
+ var _a, _b, _c, _d, _f, _g, _h;
23603
23603
  const current = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23604
23604
  if (!current || current === this._boundTransport)
23605
23605
  return;
@@ -23608,15 +23608,13 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23608
23608
  if (this._onWsOpen)
23609
23609
  (_c = (_b = this._boundTransport).removeEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, "open", this._onWsOpen);
23610
23610
  if (this._onWsClose)
23611
- (_e = (_d = this._boundTransport).removeEventListener) === null || _e === void 0 ? void 0 : _e.call(_d, "close", this._onWsClose);
23611
+ (_f = (_d = this._boundTransport).removeEventListener) === null || _f === void 0 ? void 0 : _f.call(_d, "close", this._onWsClose);
23612
23612
  }
23613
23613
  // Define (or reuse) callbacks
23614
23614
  if (!this._onWsOpen) {
23615
23615
  this._onWsOpen = () => {
23616
23616
  this.flushOutbox();
23617
- // fallback nudge for videoInitialized
23618
- if (!this.videoInitializedSent)
23619
- setTimeout(() => this.sendVideoInitializedOnce(), 150);
23617
+ this.startVideoInitWatchdog(); // only start, no send
23620
23618
  };
23621
23619
  }
23622
23620
  if (!this._onWsClose) {
@@ -23626,10 +23624,53 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23626
23624
  };
23627
23625
  }
23628
23626
  // Bind to current
23629
- (_f = current.addEventListener) === null || _f === void 0 ? void 0 : _f.call(current, "open", this._onWsOpen);
23630
- (_g = current.addEventListener) === null || _g === void 0 ? void 0 : _g.call(current, "close", this._onWsClose);
23627
+ (_g = current.addEventListener) === null || _g === void 0 ? void 0 : _g.call(current, "open", this._onWsOpen);
23628
+ (_h = current.addEventListener) === null || _h === void 0 ? void 0 : _h.call(current, "close", this._onWsClose);
23631
23629
  this._boundTransport = current;
23632
23630
  }
23631
+ // conservative media-evidence check (no stats involved)
23632
+ hasMediaEvidence() {
23633
+ var _a, _b, _c;
23634
+ 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);
23635
+ if (!videoEl)
23636
+ return false;
23637
+ const dimensions = videoEl.videoWidth > 0 && videoEl.videoHeight > 0;
23638
+ const ready = videoEl.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA; // >= 2
23639
+ const activelyPlaying = !videoEl.paused && !videoEl.ended;
23640
+ // Require at least two signals to avoid false positives on metadata-only loads
23641
+ const strong = (dimensions && ready) || (dimensions && activelyPlaying) || (ready && activelyPlaying);
23642
+ // also allow explicit 'playing' evidence we latched separately
23643
+ return strong || this.seenVideoPlaying;
23644
+ }
23645
+ startVideoInitWatchdog() {
23646
+ // restart the interval
23647
+ this.stopVideoInitWatchdog();
23648
+ const startedAt = Date.now();
23649
+ this.videoInitWatchdogInterval = window.setInterval(() => {
23650
+ if (this.videoInitializedSent) {
23651
+ this.stopVideoInitWatchdog();
23652
+ return;
23653
+ }
23654
+ if (this.hasMediaEvidence()) {
23655
+ this.sendVideoInitializedOnce();
23656
+ this.stopVideoInitWatchdog();
23657
+ return;
23658
+ }
23659
+ // Optional maximum wait: if set and exceeded, backfill only if we saw playing
23660
+ if (this.videoInitMaxWaitMs && Date.now() - startedAt > this.videoInitMaxWaitMs) {
23661
+ if (this.seenVideoPlaying && !this.videoInitializedSent) {
23662
+ this.sendVideoInitializedOnce();
23663
+ }
23664
+ this.stopVideoInitWatchdog();
23665
+ }
23666
+ }, this.videoInitCheckMs);
23667
+ }
23668
+ stopVideoInitWatchdog() {
23669
+ if (this.videoInitWatchdogInterval) {
23670
+ window.clearInterval(this.videoInitWatchdogInterval);
23671
+ this.videoInitWatchdogInterval = undefined;
23672
+ }
23673
+ }
23633
23674
  startTransportWatcher() {
23634
23675
  // Rebind if the transport object reference changes (cheap safety net)
23635
23676
  if (this._transportWatchTimer)
@@ -23656,7 +23697,9 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23656
23697
  if (this._boundVideoEl && this._onVideoPlaying) {
23657
23698
  this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
23658
23699
  }
23659
- this._onVideoPlaying = () => this.sendVideoInitializedOnce();
23700
+ this._onVideoPlaying = () => {
23701
+ this.seenVideoPlaying = true;
23702
+ };
23660
23703
  videoEl.addEventListener("playing", this._onVideoPlaying, { once: true });
23661
23704
  this._boundVideoEl = videoEl;
23662
23705
  }
@@ -23680,7 +23723,7 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23680
23723
  return state !== undefined ? state : WebSocket.CLOSED;
23681
23724
  }
23682
23725
  constructor(config, overrides) {
23683
- var _a, _b, _c;
23726
+ var _a, _b, _c, _d, _f, _g, _h;
23684
23727
  /** As soon as upstream is fixed, we got to adjust the url building process. */
23685
23728
  (0,_ApplyUrlHack__WEBPACK_IMPORTED_MODULE_6__.ApplyUrlHack)();
23686
23729
  super(config, overrides);
@@ -23692,6 +23735,8 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23692
23735
  this.videoInitializedSent = false;
23693
23736
  this.versionReplyInFlight = false;
23694
23737
  this.nextMsgId = 1;
23738
+ this.videoInitCheckMs = 250; // default poll; can be overridden from config
23739
+ this.seenVideoPlaying = false;
23695
23740
  // Externalized
23696
23741
  /** On ping the session creation timestamp will be updated. */
23697
23742
  this.queueHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler();
@@ -23717,6 +23762,7 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23717
23762
  const transport = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23718
23763
  (_b = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _b === void 0 ? void 0 : _b.call(transport, "open", () => {
23719
23764
  this.flushOutbox();
23765
+ this.startVideoInitWatchdog(); // only start, no send
23720
23766
  });
23721
23767
  (_c = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _c === void 0 ? void 0 : _c.call(transport, "close", (evt) => {
23722
23768
  // Bubble to your public close handler if you expose one
@@ -23727,6 +23773,8 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23727
23773
  this.setupVideoInitFallbacks();
23728
23774
  // Set override config.
23729
23775
  this.config = config;
23776
+ this.videoInitCheckMs = (_f = (_d = this.config.settings) === null || _d === void 0 ? void 0 : _d.videoInitCheckMs) !== null && _f !== void 0 ? _f : this.videoInitCheckMs;
23777
+ this.videoInitMaxWaitMs = (_h = (_g = this.config.settings) === null || _g === void 0 ? void 0 : _g.videoInitMaxWaitMs) !== null && _h !== void 0 ? _h : undefined;
23730
23778
  this.loveLettersList = [];
23731
23779
  this.microphoneOverlay = new _ui_MicrophoneOverlay__WEBPACK_IMPORTED_MODULE_7__.MicrophoneOverlay(this);
23732
23780
  this.diagnosticsCollector = new _features_DiagnosticsCollector__WEBPACK_IMPORTED_MODULE_3__.DiagnosticsCollector({
@@ -23892,55 +23940,51 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23892
23940
  }
23893
23941
  // Attach fallbacks once (call this in constructor after transport wiring)
23894
23942
  setupVideoInitFallbacks() {
23895
- var _a, _b, _c, _d, _e, _f, _g;
23943
+ var _a, _b, _c, _d, _f, _g, _h;
23896
23944
  // Fallback #1: HTMLVideoElement 'playing'
23897
23945
  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);
23898
- (_d = videoEl === null || videoEl === void 0 ? void 0 : videoEl.addEventListener) === null || _d === void 0 ? void 0 : _d.call(videoEl, "playing", () => this.sendVideoInitializedOnce(), { once: true });
23899
- // Fallback #2: stats hook (if you emit one)
23900
- (_e = this.addEventListener) === null || _e === void 0 ? void 0 : _e.call(this, "statsReceived", (e) => {
23901
- var _a, _b;
23902
- const stats = e === null || e === void 0 ? void 0 : e.detail;
23903
- if (!this.videoInitializedSent && ((_b = (_a = stats === null || stats === void 0 ? void 0 : stats.video) === null || _a === void 0 ? void 0 : _a.framesDecoded) !== null && _b !== void 0 ? _b : 0) > 0) {
23904
- this.sendVideoInitializedOnce();
23905
- }
23946
+ (_d = videoEl === null || videoEl === void 0 ? void 0 : videoEl.addEventListener) === null || _d === void 0 ? void 0 : _d.call(videoEl, "playing", () => {
23947
+ this.seenVideoPlaying = true;
23948
+ }, { once: true });
23949
+ (_f = this.addEventListener) === null || _f === void 0 ? void 0 : _f.call(this, "statsReceived", (_e) => {
23950
+ /* no-op for video init */
23906
23951
  });
23907
23952
  // Fallback #3: after socket opens, give it a tick
23908
- const transport = (_f = this.webRtcController) === null || _f === void 0 ? void 0 : _f.transport;
23909
- (_g = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _g === void 0 ? void 0 : _g.call(transport, "open", () => {
23910
- if (!this.videoInitializedSent) {
23911
- setTimeout(() => this.sendVideoInitializedOnce(), 150);
23912
- }
23953
+ const transport = (_g = this.webRtcController) === null || _g === void 0 ? void 0 : _g.transport;
23954
+ (_h = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _h === void 0 ? void 0 : _h.call(transport, "open", () => {
23955
+ this.startVideoInitWatchdog(); // only start, no send
23913
23956
  });
23914
23957
  }
23915
23958
  onVideoInitialized() {
23916
- var _a, _b, _c, _d, _e, _f, _g;
23959
+ var _a, _b, _c, _d, _f, _g, _h;
23917
23960
  // send early and once
23961
+ this.stopVideoInitWatchdog(); // PS event arrived, cancel backup
23918
23962
  this.sendVideoInitializedOnce();
23919
23963
  // keep side-effects guarded so they can't break the send
23920
23964
  try {
23921
23965
  (_a = this.handleMouseLock) === null || _a === void 0 ? void 0 : _a.call(this);
23922
23966
  }
23923
- catch (_h) { }
23924
- try {
23925
- (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23926
- }
23927
23967
  catch (_j) { }
23928
23968
  try {
23929
- (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23969
+ (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23930
23970
  }
23931
23971
  catch (_k) { }
23932
23972
  try {
23933
- (_e = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _e === void 0 ? void 0 : _e.call(_d, false);
23973
+ (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23934
23974
  }
23935
23975
  catch (_l) { }
23936
23976
  try {
23937
- (_f = this.applyResolutionIfPlaying) === null || _f === void 0 ? void 0 : _f.call(this);
23977
+ (_f = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _f === void 0 ? void 0 : _f.call(_d, false);
23938
23978
  }
23939
23979
  catch (_m) { }
23940
23980
  try {
23941
- (_g = this.removeXRIconIfDisabled) === null || _g === void 0 ? void 0 : _g.call(this);
23981
+ (_g = this.applyResolutionIfPlaying) === null || _g === void 0 ? void 0 : _g.call(this);
23942
23982
  }
23943
23983
  catch (_o) { }
23984
+ try {
23985
+ (_h = this.removeXRIconIfDisabled) === null || _h === void 0 ? void 0 : _h.call(this);
23986
+ }
23987
+ catch (_p) { }
23944
23988
  }
23945
23989
  /** Adding a zod-safe handler. */
23946
23990
  addMessageHandler(type, zod, boundMethod) {
@@ -24014,14 +24058,14 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
24014
24058
  }
24015
24059
  }
24016
24060
  handleResolutionChange() {
24017
- var _a, _b, _c, _d, _e, _f, _g;
24061
+ var _a, _b, _c, _d, _f, _g, _h;
24018
24062
  // Get the resolution from the streamInfo if available
24019
24063
  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())) {
24020
24064
  return;
24021
24065
  }
24022
24066
  // Get the resolution from the streamInfo if available
24023
24067
  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;
24024
- 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;
24068
+ 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;
24025
24069
  // Check if resolution.dynamic is true
24026
24070
  if (resolution && (resolution === null || resolution === void 0 ? void 0 : resolution.dynamic)) {
24027
24071
  setTimeout(() => {
@@ -24075,6 +24119,7 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
24075
24119
  }
24076
24120
  removePlayer() {
24077
24121
  var _a, _b, _c, _d;
24122
+ this.stopVideoInitWatchdog(); // PS event arrived, cancel backup
24078
24123
  this.stopTransportWatcher();
24079
24124
  // Optional: unbind handlers
24080
24125
  if (this._boundTransport) {
@@ -24215,12 +24260,12 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
24215
24260
  });
24216
24261
  }
24217
24262
  removeXRIconIfDisabled() {
24218
- var _a, _b, _c, _d, _e;
24263
+ var _a, _b, _c, _d, _f;
24219
24264
  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)) {
24220
24265
  (_c = this === null || this === void 0 ? void 0 : this.config) === null || _c === void 0 ? void 0 : _c.setFlagEnabled(_epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_11__.Flags.XRControllerInput, false);
24221
24266
  if (this.videoElementParent) {
24222
24267
  if ((_d = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _d === void 0 ? void 0 : _d.parentElement) {
24223
- const xrBtn = (_e = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _e === void 0 ? void 0 : _e.parentElement.querySelector("#xrBtn");
24268
+ const xrBtn = (_f = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _f === void 0 ? void 0 : _f.parentElement.querySelector("#xrBtn");
24224
24269
  xrBtn === null || xrBtn === void 0 ? void 0 : xrBtn.remove();
24225
24270
  }
24226
24271
  }
package/index.umd.js CHANGED
@@ -23429,7 +23429,7 @@ class ArcwareConfig extends lib_pixelstreamingfrontend_ue5_5_1.Config {
23429
23429
  if (!config.initialSettings.ss)
23430
23430
  config.initialSettings.ss = exports.DefaultUrl;
23431
23431
  super(config);
23432
- this.VERSION = "1.3.2";
23432
+ this.VERSION = "1.3.3";
23433
23433
  this.settings = settings;
23434
23434
  this.session = new Session_1.Session();
23435
23435
  this._initialSettings = config.initialSettings;
@@ -23584,7 +23584,7 @@ const ConnectionIdentifier_1 = __webpack_require__(5999);
23584
23584
  const DiagnosticsCollector_1 = __webpack_require__(8429);
23585
23585
  class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStreaming {
23586
23586
  bindTransportEvents() {
23587
- var _a, _b, _c, _d, _e, _f, _g;
23587
+ var _a, _b, _c, _d, _f, _g, _h;
23588
23588
  const current = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23589
23589
  if (!current || current === this._boundTransport)
23590
23590
  return;
@@ -23593,15 +23593,13 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23593
23593
  if (this._onWsOpen)
23594
23594
  (_c = (_b = this._boundTransport).removeEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, "open", this._onWsOpen);
23595
23595
  if (this._onWsClose)
23596
- (_e = (_d = this._boundTransport).removeEventListener) === null || _e === void 0 ? void 0 : _e.call(_d, "close", this._onWsClose);
23596
+ (_f = (_d = this._boundTransport).removeEventListener) === null || _f === void 0 ? void 0 : _f.call(_d, "close", this._onWsClose);
23597
23597
  }
23598
23598
  // Define (or reuse) callbacks
23599
23599
  if (!this._onWsOpen) {
23600
23600
  this._onWsOpen = () => {
23601
23601
  this.flushOutbox();
23602
- // fallback nudge for videoInitialized
23603
- if (!this.videoInitializedSent)
23604
- setTimeout(() => this.sendVideoInitializedOnce(), 150);
23602
+ this.startVideoInitWatchdog(); // only start, no send
23605
23603
  };
23606
23604
  }
23607
23605
  if (!this._onWsClose) {
@@ -23611,10 +23609,53 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23611
23609
  };
23612
23610
  }
23613
23611
  // Bind to current
23614
- (_f = current.addEventListener) === null || _f === void 0 ? void 0 : _f.call(current, "open", this._onWsOpen);
23615
- (_g = current.addEventListener) === null || _g === void 0 ? void 0 : _g.call(current, "close", this._onWsClose);
23612
+ (_g = current.addEventListener) === null || _g === void 0 ? void 0 : _g.call(current, "open", this._onWsOpen);
23613
+ (_h = current.addEventListener) === null || _h === void 0 ? void 0 : _h.call(current, "close", this._onWsClose);
23616
23614
  this._boundTransport = current;
23617
23615
  }
23616
+ // conservative media-evidence check (no stats involved)
23617
+ hasMediaEvidence() {
23618
+ var _a, _b, _c;
23619
+ 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);
23620
+ if (!videoEl)
23621
+ return false;
23622
+ const dimensions = videoEl.videoWidth > 0 && videoEl.videoHeight > 0;
23623
+ const ready = videoEl.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA; // >= 2
23624
+ const activelyPlaying = !videoEl.paused && !videoEl.ended;
23625
+ // Require at least two signals to avoid false positives on metadata-only loads
23626
+ const strong = (dimensions && ready) || (dimensions && activelyPlaying) || (ready && activelyPlaying);
23627
+ // also allow explicit 'playing' evidence we latched separately
23628
+ return strong || this.seenVideoPlaying;
23629
+ }
23630
+ startVideoInitWatchdog() {
23631
+ // restart the interval
23632
+ this.stopVideoInitWatchdog();
23633
+ const startedAt = Date.now();
23634
+ this.videoInitWatchdogInterval = window.setInterval(() => {
23635
+ if (this.videoInitializedSent) {
23636
+ this.stopVideoInitWatchdog();
23637
+ return;
23638
+ }
23639
+ if (this.hasMediaEvidence()) {
23640
+ this.sendVideoInitializedOnce();
23641
+ this.stopVideoInitWatchdog();
23642
+ return;
23643
+ }
23644
+ // Optional maximum wait: if set and exceeded, backfill only if we saw playing
23645
+ if (this.videoInitMaxWaitMs && Date.now() - startedAt > this.videoInitMaxWaitMs) {
23646
+ if (this.seenVideoPlaying && !this.videoInitializedSent) {
23647
+ this.sendVideoInitializedOnce();
23648
+ }
23649
+ this.stopVideoInitWatchdog();
23650
+ }
23651
+ }, this.videoInitCheckMs);
23652
+ }
23653
+ stopVideoInitWatchdog() {
23654
+ if (this.videoInitWatchdogInterval) {
23655
+ window.clearInterval(this.videoInitWatchdogInterval);
23656
+ this.videoInitWatchdogInterval = undefined;
23657
+ }
23658
+ }
23618
23659
  startTransportWatcher() {
23619
23660
  // Rebind if the transport object reference changes (cheap safety net)
23620
23661
  if (this._transportWatchTimer)
@@ -23641,7 +23682,9 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23641
23682
  if (this._boundVideoEl && this._onVideoPlaying) {
23642
23683
  this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
23643
23684
  }
23644
- this._onVideoPlaying = () => this.sendVideoInitializedOnce();
23685
+ this._onVideoPlaying = () => {
23686
+ this.seenVideoPlaying = true;
23687
+ };
23645
23688
  videoEl.addEventListener("playing", this._onVideoPlaying, { once: true });
23646
23689
  this._boundVideoEl = videoEl;
23647
23690
  }
@@ -23665,7 +23708,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23665
23708
  return state !== undefined ? state : WebSocket.CLOSED;
23666
23709
  }
23667
23710
  constructor(config, overrides) {
23668
- var _a, _b, _c;
23711
+ var _a, _b, _c, _d, _f, _g, _h;
23669
23712
  /** As soon as upstream is fixed, we got to adjust the url building process. */
23670
23713
  (0, ApplyUrlHack_1.ApplyUrlHack)();
23671
23714
  super(config, overrides);
@@ -23677,6 +23720,8 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23677
23720
  this.videoInitializedSent = false;
23678
23721
  this.versionReplyInFlight = false;
23679
23722
  this.nextMsgId = 1;
23723
+ this.videoInitCheckMs = 250; // default poll; can be overridden from config
23724
+ this.seenVideoPlaying = false;
23680
23725
  // Externalized
23681
23726
  /** On ping the session creation timestamp will be updated. */
23682
23727
  this.queueHandler = new EventHandler_1.EventHandler();
@@ -23702,6 +23747,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23702
23747
  const transport = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23703
23748
  (_b = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _b === void 0 ? void 0 : _b.call(transport, "open", () => {
23704
23749
  this.flushOutbox();
23750
+ this.startVideoInitWatchdog(); // only start, no send
23705
23751
  });
23706
23752
  (_c = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _c === void 0 ? void 0 : _c.call(transport, "close", (evt) => {
23707
23753
  // Bubble to your public close handler if you expose one
@@ -23712,6 +23758,8 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23712
23758
  this.setupVideoInitFallbacks();
23713
23759
  // Set override config.
23714
23760
  this.config = config;
23761
+ this.videoInitCheckMs = (_f = (_d = this.config.settings) === null || _d === void 0 ? void 0 : _d.videoInitCheckMs) !== null && _f !== void 0 ? _f : this.videoInitCheckMs;
23762
+ this.videoInitMaxWaitMs = (_h = (_g = this.config.settings) === null || _g === void 0 ? void 0 : _g.videoInitMaxWaitMs) !== null && _h !== void 0 ? _h : undefined;
23715
23763
  this.loveLettersList = [];
23716
23764
  this.microphoneOverlay = new MicrophoneOverlay_1.MicrophoneOverlay(this);
23717
23765
  this.diagnosticsCollector = new DiagnosticsCollector_1.DiagnosticsCollector({
@@ -23877,55 +23925,51 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23877
23925
  }
23878
23926
  // Attach fallbacks once (call this in constructor after transport wiring)
23879
23927
  setupVideoInitFallbacks() {
23880
- var _a, _b, _c, _d, _e, _f, _g;
23928
+ var _a, _b, _c, _d, _f, _g, _h;
23881
23929
  // Fallback #1: HTMLVideoElement 'playing'
23882
23930
  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);
23883
- (_d = videoEl === null || videoEl === void 0 ? void 0 : videoEl.addEventListener) === null || _d === void 0 ? void 0 : _d.call(videoEl, "playing", () => this.sendVideoInitializedOnce(), { once: true });
23884
- // Fallback #2: stats hook (if you emit one)
23885
- (_e = this.addEventListener) === null || _e === void 0 ? void 0 : _e.call(this, "statsReceived", (e) => {
23886
- var _a, _b;
23887
- const stats = e === null || e === void 0 ? void 0 : e.detail;
23888
- if (!this.videoInitializedSent && ((_b = (_a = stats === null || stats === void 0 ? void 0 : stats.video) === null || _a === void 0 ? void 0 : _a.framesDecoded) !== null && _b !== void 0 ? _b : 0) > 0) {
23889
- this.sendVideoInitializedOnce();
23890
- }
23931
+ (_d = videoEl === null || videoEl === void 0 ? void 0 : videoEl.addEventListener) === null || _d === void 0 ? void 0 : _d.call(videoEl, "playing", () => {
23932
+ this.seenVideoPlaying = true;
23933
+ }, { once: true });
23934
+ (_f = this.addEventListener) === null || _f === void 0 ? void 0 : _f.call(this, "statsReceived", (_e) => {
23935
+ /* no-op for video init */
23891
23936
  });
23892
23937
  // Fallback #3: after socket opens, give it a tick
23893
- const transport = (_f = this.webRtcController) === null || _f === void 0 ? void 0 : _f.transport;
23894
- (_g = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _g === void 0 ? void 0 : _g.call(transport, "open", () => {
23895
- if (!this.videoInitializedSent) {
23896
- setTimeout(() => this.sendVideoInitializedOnce(), 150);
23897
- }
23938
+ const transport = (_g = this.webRtcController) === null || _g === void 0 ? void 0 : _g.transport;
23939
+ (_h = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _h === void 0 ? void 0 : _h.call(transport, "open", () => {
23940
+ this.startVideoInitWatchdog(); // only start, no send
23898
23941
  });
23899
23942
  }
23900
23943
  onVideoInitialized() {
23901
- var _a, _b, _c, _d, _e, _f, _g;
23944
+ var _a, _b, _c, _d, _f, _g, _h;
23902
23945
  // send early and once
23946
+ this.stopVideoInitWatchdog(); // PS event arrived, cancel backup
23903
23947
  this.sendVideoInitializedOnce();
23904
23948
  // keep side-effects guarded so they can't break the send
23905
23949
  try {
23906
23950
  (_a = this.handleMouseLock) === null || _a === void 0 ? void 0 : _a.call(this);
23907
23951
  }
23908
- catch (_h) { }
23909
- try {
23910
- (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23911
- }
23912
23952
  catch (_j) { }
23913
23953
  try {
23914
- (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23954
+ (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23915
23955
  }
23916
23956
  catch (_k) { }
23917
23957
  try {
23918
- (_e = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _e === void 0 ? void 0 : _e.call(_d, false);
23958
+ (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23919
23959
  }
23920
23960
  catch (_l) { }
23921
23961
  try {
23922
- (_f = this.applyResolutionIfPlaying) === null || _f === void 0 ? void 0 : _f.call(this);
23962
+ (_f = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _f === void 0 ? void 0 : _f.call(_d, false);
23923
23963
  }
23924
23964
  catch (_m) { }
23925
23965
  try {
23926
- (_g = this.removeXRIconIfDisabled) === null || _g === void 0 ? void 0 : _g.call(this);
23966
+ (_g = this.applyResolutionIfPlaying) === null || _g === void 0 ? void 0 : _g.call(this);
23927
23967
  }
23928
23968
  catch (_o) { }
23969
+ try {
23970
+ (_h = this.removeXRIconIfDisabled) === null || _h === void 0 ? void 0 : _h.call(this);
23971
+ }
23972
+ catch (_p) { }
23929
23973
  }
23930
23974
  /** Adding a zod-safe handler. */
23931
23975
  addMessageHandler(type, zod, boundMethod) {
@@ -23999,14 +24043,14 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23999
24043
  }
24000
24044
  }
24001
24045
  handleResolutionChange() {
24002
- var _a, _b, _c, _d, _e, _f, _g;
24046
+ var _a, _b, _c, _d, _f, _g, _h;
24003
24047
  // Get the resolution from the streamInfo if available
24004
24048
  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())) {
24005
24049
  return;
24006
24050
  }
24007
24051
  // Get the resolution from the streamInfo if available
24008
24052
  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;
24009
- 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;
24053
+ 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;
24010
24054
  // Check if resolution.dynamic is true
24011
24055
  if (resolution && (resolution === null || resolution === void 0 ? void 0 : resolution.dynamic)) {
24012
24056
  setTimeout(() => {
@@ -24060,6 +24104,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24060
24104
  }
24061
24105
  removePlayer() {
24062
24106
  var _a, _b, _c, _d;
24107
+ this.stopVideoInitWatchdog(); // PS event arrived, cancel backup
24063
24108
  this.stopTransportWatcher();
24064
24109
  // Optional: unbind handlers
24065
24110
  if (this._boundTransport) {
@@ -24200,12 +24245,12 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24200
24245
  });
24201
24246
  }
24202
24247
  removeXRIconIfDisabled() {
24203
- var _a, _b, _c, _d, _e;
24248
+ var _a, _b, _c, _d, _f;
24204
24249
  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)) {
24205
24250
  (_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);
24206
24251
  if (this.videoElementParent) {
24207
24252
  if ((_d = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _d === void 0 ? void 0 : _d.parentElement) {
24208
- const xrBtn = (_e = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _e === void 0 ? void 0 : _e.parentElement.querySelector("#xrBtn");
24253
+ const xrBtn = (_f = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _f === void 0 ? void 0 : _f.parentElement.querySelector("#xrBtn");
24209
24254
  xrBtn === null || xrBtn === void 0 ? void 0 : xrBtn.remove();
24210
24255
  }
24211
24256
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@arcware-cloud/pixelstreaming-websdk",
3
3
  "description": "WebSDK for easy implementation of pixel streaming with Arcware Cloud Services. Heavily based on the '@epicgames-ps' library.",
4
- "version": "1.3.2",
4
+ "version": "1.3.3",
5
5
  "type": "commonjs",
6
6
  "main": "./index.umd.js",
7
7
  "module": "./index.umd.js",
@@ -26,7 +26,7 @@ export declare class ArcwareConfig extends Config {
26
26
  readonly session: Session;
27
27
  readonly settings: Settings;
28
28
  private _initialSettings;
29
- readonly VERSION = "1.3.2";
29
+ readonly VERSION = "1.3.3";
30
30
  constructor(config: ArcwareConfigParams);
31
31
  /** Setup connection string. */
32
32
  get urlFlags(): string;
@@ -27,9 +27,16 @@ export declare class ArcwarePixelStreaming extends PixelStreaming {
27
27
  private _onWsOpen?;
28
28
  private _onWsClose?;
29
29
  private _transportWatchTimer?;
30
+ private videoInitWatchdogInterval?;
31
+ private videoInitCheckMs;
32
+ private videoInitMaxWaitMs?;
33
+ private seenVideoPlaying;
30
34
  private _boundVideoEl?;
31
35
  private _onVideoPlaying?;
32
36
  private bindTransportEvents;
37
+ private hasMediaEvidence;
38
+ private startVideoInitWatchdog;
39
+ private stopVideoInitWatchdog;
33
40
  private startTransportWatcher;
34
41
  private stopTransportWatcher;
35
42
  private bindVideoElPlayingOnce;