@arcware-cloud/pixelstreaming-websdk 1.3.2 → 1.3.4

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
@@ -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.2";
23423
+ this.VERSION = "1.3.4";
23423
23424
  this.settings = settings;
23424
23425
  this.session = new Session_1.Session();
23425
23426
  this._initialSettings = config.initialSettings;
@@ -23574,7 +23575,7 @@ 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 {
23576
23577
  bindTransportEvents() {
23577
- var _a, _b, _c, _d, _e, _f, _g;
23578
+ var _a, _b, _c, _d, _f, _g, _h;
23578
23579
  const current = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23579
23580
  if (!current || current === this._boundTransport)
23580
23581
  return;
@@ -23583,15 +23584,13 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23583
23584
  if (this._onWsOpen)
23584
23585
  (_c = (_b = this._boundTransport).removeEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, "open", this._onWsOpen);
23585
23586
  if (this._onWsClose)
23586
- (_e = (_d = this._boundTransport).removeEventListener) === null || _e === void 0 ? void 0 : _e.call(_d, "close", this._onWsClose);
23587
+ (_f = (_d = this._boundTransport).removeEventListener) === null || _f === void 0 ? void 0 : _f.call(_d, "close", this._onWsClose);
23587
23588
  }
23588
23589
  // Define (or reuse) callbacks
23589
23590
  if (!this._onWsOpen) {
23590
23591
  this._onWsOpen = () => {
23591
23592
  this.flushOutbox();
23592
- // fallback nudge for videoInitialized
23593
- if (!this.videoInitializedSent)
23594
- setTimeout(() => this.sendVideoInitializedOnce(), 150);
23593
+ this.startVideoInitWatchdog(); // only start, no send
23595
23594
  };
23596
23595
  }
23597
23596
  if (!this._onWsClose) {
@@ -23601,10 +23600,53 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23601
23600
  };
23602
23601
  }
23603
23602
  // 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);
23603
+ (_g = current.addEventListener) === null || _g === void 0 ? void 0 : _g.call(current, "open", this._onWsOpen);
23604
+ (_h = current.addEventListener) === null || _h === void 0 ? void 0 : _h.call(current, "close", this._onWsClose);
23606
23605
  this._boundTransport = current;
23607
23606
  }
23607
+ // conservative media-evidence check (no stats involved)
23608
+ hasMediaEvidence() {
23609
+ var _a, _b, _c;
23610
+ 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);
23611
+ if (!videoEl)
23612
+ return false;
23613
+ const dimensions = videoEl.videoWidth > 0 && videoEl.videoHeight > 0;
23614
+ const ready = videoEl.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA; // >= 2
23615
+ const activelyPlaying = !videoEl.paused && !videoEl.ended;
23616
+ // Require at least two signals to avoid false positives on metadata-only loads
23617
+ const strong = (dimensions && ready) || (dimensions && activelyPlaying) || (ready && activelyPlaying);
23618
+ // also allow explicit 'playing' evidence we latched separately
23619
+ return strong || this.seenVideoPlaying;
23620
+ }
23621
+ startVideoInitWatchdog() {
23622
+ // restart the interval
23623
+ this.stopVideoInitWatchdog();
23624
+ const startedAt = Date.now();
23625
+ this.videoInitWatchdogInterval = window.setInterval(() => {
23626
+ if (this.videoInitializedSent) {
23627
+ this.stopVideoInitWatchdog();
23628
+ return;
23629
+ }
23630
+ if (this.hasMediaEvidence()) {
23631
+ this.sendVideoInitializedOnce();
23632
+ this.stopVideoInitWatchdog();
23633
+ return;
23634
+ }
23635
+ // Optional maximum wait: if set and exceeded, backfill only if we saw playing
23636
+ if (this.videoInitMaxWaitMs && Date.now() - startedAt > this.videoInitMaxWaitMs) {
23637
+ if (this.seenVideoPlaying && !this.videoInitializedSent) {
23638
+ this.sendVideoInitializedOnce();
23639
+ }
23640
+ this.stopVideoInitWatchdog();
23641
+ }
23642
+ }, this.videoInitCheckMs);
23643
+ }
23644
+ stopVideoInitWatchdog() {
23645
+ if (this.videoInitWatchdogInterval) {
23646
+ window.clearInterval(this.videoInitWatchdogInterval);
23647
+ this.videoInitWatchdogInterval = undefined;
23648
+ }
23649
+ }
23608
23650
  startTransportWatcher() {
23609
23651
  // Rebind if the transport object reference changes (cheap safety net)
23610
23652
  if (this._transportWatchTimer)
@@ -23631,7 +23673,9 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23631
23673
  if (this._boundVideoEl && this._onVideoPlaying) {
23632
23674
  this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
23633
23675
  }
23634
- this._onVideoPlaying = () => this.sendVideoInitializedOnce();
23676
+ this._onVideoPlaying = () => {
23677
+ this.seenVideoPlaying = true;
23678
+ };
23635
23679
  videoEl.addEventListener("playing", this._onVideoPlaying, { once: true });
23636
23680
  this._boundVideoEl = videoEl;
23637
23681
  }
@@ -23655,7 +23699,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23655
23699
  return state !== undefined ? state : WebSocket.CLOSED;
23656
23700
  }
23657
23701
  constructor(config, overrides) {
23658
- var _a, _b, _c;
23702
+ var _a, _b, _c, _d, _f, _g, _h;
23659
23703
  /** As soon as upstream is fixed, we got to adjust the url building process. */
23660
23704
  (0, ApplyUrlHack_1.ApplyUrlHack)();
23661
23705
  super(config, overrides);
@@ -23667,6 +23711,8 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23667
23711
  this.videoInitializedSent = false;
23668
23712
  this.versionReplyInFlight = false;
23669
23713
  this.nextMsgId = 1;
23714
+ this.videoInitCheckMs = 250; // default poll; can be overridden from config
23715
+ this.seenVideoPlaying = false;
23670
23716
  // Externalized
23671
23717
  /** On ping the session creation timestamp will be updated. */
23672
23718
  this.queueHandler = new EventHandler_1.EventHandler();
@@ -23692,6 +23738,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23692
23738
  const transport = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23693
23739
  (_b = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _b === void 0 ? void 0 : _b.call(transport, "open", () => {
23694
23740
  this.flushOutbox();
23741
+ this.startVideoInitWatchdog(); // only start, no send
23695
23742
  });
23696
23743
  (_c = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _c === void 0 ? void 0 : _c.call(transport, "close", (evt) => {
23697
23744
  // Bubble to your public close handler if you expose one
@@ -23702,6 +23749,8 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23702
23749
  this.setupVideoInitFallbacks();
23703
23750
  // Set override config.
23704
23751
  this.config = config;
23752
+ this.videoInitCheckMs = (_f = (_d = this.config.settings) === null || _d === void 0 ? void 0 : _d.videoInitCheckMs) !== null && _f !== void 0 ? _f : this.videoInitCheckMs;
23753
+ this.videoInitMaxWaitMs = (_h = (_g = this.config.settings) === null || _g === void 0 ? void 0 : _g.videoInitMaxWaitMs) !== null && _h !== void 0 ? _h : undefined;
23705
23754
  this.loveLettersList = [];
23706
23755
  this.microphoneOverlay = new MicrophoneOverlay_1.MicrophoneOverlay(this);
23707
23756
  this.diagnosticsCollector = new DiagnosticsCollector_1.DiagnosticsCollector({
@@ -23867,55 +23916,51 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23867
23916
  }
23868
23917
  // Attach fallbacks once (call this in constructor after transport wiring)
23869
23918
  setupVideoInitFallbacks() {
23870
- var _a, _b, _c, _d, _e, _f, _g;
23919
+ var _a, _b, _c, _d, _f, _g, _h;
23871
23920
  // Fallback #1: HTMLVideoElement 'playing'
23872
23921
  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
- }
23922
+ (_d = videoEl === null || videoEl === void 0 ? void 0 : videoEl.addEventListener) === null || _d === void 0 ? void 0 : _d.call(videoEl, "playing", () => {
23923
+ this.seenVideoPlaying = true;
23924
+ }, { once: true });
23925
+ (_f = this.addEventListener) === null || _f === void 0 ? void 0 : _f.call(this, "statsReceived", (_e) => {
23926
+ /* no-op for video init */
23881
23927
  });
23882
23928
  // 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
- }
23929
+ const transport = (_g = this.webRtcController) === null || _g === void 0 ? void 0 : _g.transport;
23930
+ (_h = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _h === void 0 ? void 0 : _h.call(transport, "open", () => {
23931
+ this.startVideoInitWatchdog(); // only start, no send
23888
23932
  });
23889
23933
  }
23890
23934
  onVideoInitialized() {
23891
- var _a, _b, _c, _d, _e, _f, _g;
23935
+ var _a, _b, _c, _d, _f, _g, _h;
23892
23936
  // send early and once
23937
+ this.stopVideoInitWatchdog(); // PS event arrived, cancel backup
23893
23938
  this.sendVideoInitializedOnce();
23894
23939
  // keep side-effects guarded so they can't break the send
23895
23940
  try {
23896
23941
  (_a = this.handleMouseLock) === null || _a === void 0 ? void 0 : _a.call(this);
23897
23942
  }
23898
- catch (_h) { }
23899
- try {
23900
- (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23901
- }
23902
23943
  catch (_j) { }
23903
23944
  try {
23904
- (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23945
+ (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23905
23946
  }
23906
23947
  catch (_k) { }
23907
23948
  try {
23908
- (_e = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _e === void 0 ? void 0 : _e.call(_d, false);
23949
+ (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23909
23950
  }
23910
23951
  catch (_l) { }
23911
23952
  try {
23912
- (_f = this.applyResolutionIfPlaying) === null || _f === void 0 ? void 0 : _f.call(this);
23953
+ (_f = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _f === void 0 ? void 0 : _f.call(_d, false);
23913
23954
  }
23914
23955
  catch (_m) { }
23915
23956
  try {
23916
- (_g = this.removeXRIconIfDisabled) === null || _g === void 0 ? void 0 : _g.call(this);
23957
+ (_g = this.applyResolutionIfPlaying) === null || _g === void 0 ? void 0 : _g.call(this);
23917
23958
  }
23918
23959
  catch (_o) { }
23960
+ try {
23961
+ (_h = this.removeXRIconIfDisabled) === null || _h === void 0 ? void 0 : _h.call(this);
23962
+ }
23963
+ catch (_p) { }
23919
23964
  }
23920
23965
  /** Adding a zod-safe handler. */
23921
23966
  addMessageHandler(type, zod, boundMethod) {
@@ -23989,14 +24034,14 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23989
24034
  }
23990
24035
  }
23991
24036
  handleResolutionChange() {
23992
- var _a, _b, _c, _d, _e, _f, _g;
24037
+ var _a, _b, _c, _d, _f, _g, _h;
23993
24038
  // Get the resolution from the streamInfo if available
23994
24039
  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
24040
  return;
23996
24041
  }
23997
24042
  // Get the resolution from the streamInfo if available
23998
24043
  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;
24044
+ 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
24045
  // Check if resolution.dynamic is true
24001
24046
  if (resolution && (resolution === null || resolution === void 0 ? void 0 : resolution.dynamic)) {
24002
24047
  setTimeout(() => {
@@ -24050,6 +24095,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24050
24095
  }
24051
24096
  removePlayer() {
24052
24097
  var _a, _b, _c, _d;
24098
+ this.stopVideoInitWatchdog(); // PS event arrived, cancel backup
24053
24099
  this.stopTransportWatcher();
24054
24100
  // Optional: unbind handlers
24055
24101
  if (this._boundTransport) {
@@ -24190,12 +24236,12 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24190
24236
  });
24191
24237
  }
24192
24238
  removeXRIconIfDisabled() {
24193
- var _a, _b, _c, _d, _e;
24239
+ var _a, _b, _c, _d, _f;
24194
24240
  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
24241
  (_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
24242
  if (this.videoElementParent) {
24197
24243
  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");
24244
+ const xrBtn = (_f = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _f === void 0 ? void 0 : _f.parentElement.querySelector("#xrBtn");
24199
24245
  xrBtn === null || xrBtn === void 0 ? void 0 : xrBtn.remove();
24200
24246
  }
24201
24247
  }
package/index.esm.js CHANGED
@@ -23235,27 +23235,28 @@ class ArcwareApplication extends _epicgames_ps_lib_pixelstreamingfrontend_ui_ue5
23235
23235
  });
23236
23236
  }
23237
23237
  applicationResponse(response) {
23238
- var _a, _b;
23239
- let obj = null;
23238
+ var _a, _b, _c, _d;
23239
+ let obj;
23240
23240
  try {
23241
23241
  obj = (0,_features_common__WEBPACK_IMPORTED_MODULE_10__.parseUnknownToObject)(response, { allowJsonish: true });
23242
23242
  }
23243
- catch (_c) {
23244
- // If not parseable, fall through to generic callback
23243
+ catch (_e) {
23244
+ // not parseable just send to generic handler and bail out
23245
+ (_a = this.responseCallback) === null || _a === void 0 ? void 0 : _a.call(this, response);
23246
+ return;
23245
23247
  }
23246
23248
  const t = (0,_features_common__WEBPACK_IMPORTED_MODULE_10__.normalizeType)(obj["type"]);
23247
23249
  // route to exactly one callback
23248
23250
  if (t === "event") {
23249
- (_a = this.analyticsEventCallback) === null || _a === void 0 ? void 0 : _a.call(this, response);
23251
+ (_b = this.analyticsEventCallback) === null || _b === void 0 ? void 0 : _b.call(this, response);
23250
23252
  return;
23251
23253
  }
23252
23254
  if (t === "filetransfer" || t === "createscreenshot") {
23253
- (_b = this.fileDownloadCallback) === null || _b === void 0 ? void 0 : _b.call(this, response);
23255
+ (_c = this.fileDownloadCallback) === null || _c === void 0 ? void 0 : _c.call(this, response);
23254
23256
  return;
23255
23257
  }
23256
- if (this.responseCallback) {
23257
- this.responseCallback(response);
23258
- }
23258
+ // fallback: unknown type → generic callback
23259
+ (_d = this.responseCallback) === null || _d === void 0 ? void 0 : _d.call(this, response);
23259
23260
  }
23260
23261
  applyArcwareStyles() {
23261
23262
  const PixelStreamingApplicationStyles = new _epicgames_ps_lib_pixelstreamingfrontend_ui_ue5_5__WEBPACK_IMPORTED_MODULE_11__.PixelStreamingApplicationStyle(_styles_ArcwarePixelStreamingApplicationStyles__WEBPACK_IMPORTED_MODULE_0__.ArcwareStyles);
@@ -23427,7 +23428,7 @@ class ArcwareConfig extends _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBP
23427
23428
  if (!config.initialSettings.ss)
23428
23429
  config.initialSettings.ss = DefaultUrl;
23429
23430
  super(config);
23430
- this.VERSION = "1.3.2";
23431
+ this.VERSION = "1.3.4";
23431
23432
  this.settings = settings;
23432
23433
  this.session = new _domain_Session__WEBPACK_IMPORTED_MODULE_0__.Session();
23433
23434
  this._initialSettings = config.initialSettings;
@@ -23599,7 +23600,7 @@ __webpack_require__.r(__webpack_exports__);
23599
23600
 
23600
23601
  class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_4__.PixelStreaming {
23601
23602
  bindTransportEvents() {
23602
- var _a, _b, _c, _d, _e, _f, _g;
23603
+ var _a, _b, _c, _d, _f, _g, _h;
23603
23604
  const current = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23604
23605
  if (!current || current === this._boundTransport)
23605
23606
  return;
@@ -23608,15 +23609,13 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23608
23609
  if (this._onWsOpen)
23609
23610
  (_c = (_b = this._boundTransport).removeEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, "open", this._onWsOpen);
23610
23611
  if (this._onWsClose)
23611
- (_e = (_d = this._boundTransport).removeEventListener) === null || _e === void 0 ? void 0 : _e.call(_d, "close", this._onWsClose);
23612
+ (_f = (_d = this._boundTransport).removeEventListener) === null || _f === void 0 ? void 0 : _f.call(_d, "close", this._onWsClose);
23612
23613
  }
23613
23614
  // Define (or reuse) callbacks
23614
23615
  if (!this._onWsOpen) {
23615
23616
  this._onWsOpen = () => {
23616
23617
  this.flushOutbox();
23617
- // fallback nudge for videoInitialized
23618
- if (!this.videoInitializedSent)
23619
- setTimeout(() => this.sendVideoInitializedOnce(), 150);
23618
+ this.startVideoInitWatchdog(); // only start, no send
23620
23619
  };
23621
23620
  }
23622
23621
  if (!this._onWsClose) {
@@ -23626,10 +23625,53 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23626
23625
  };
23627
23626
  }
23628
23627
  // 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);
23628
+ (_g = current.addEventListener) === null || _g === void 0 ? void 0 : _g.call(current, "open", this._onWsOpen);
23629
+ (_h = current.addEventListener) === null || _h === void 0 ? void 0 : _h.call(current, "close", this._onWsClose);
23631
23630
  this._boundTransport = current;
23632
23631
  }
23632
+ // conservative media-evidence check (no stats involved)
23633
+ hasMediaEvidence() {
23634
+ var _a, _b, _c;
23635
+ 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);
23636
+ if (!videoEl)
23637
+ return false;
23638
+ const dimensions = videoEl.videoWidth > 0 && videoEl.videoHeight > 0;
23639
+ const ready = videoEl.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA; // >= 2
23640
+ const activelyPlaying = !videoEl.paused && !videoEl.ended;
23641
+ // Require at least two signals to avoid false positives on metadata-only loads
23642
+ const strong = (dimensions && ready) || (dimensions && activelyPlaying) || (ready && activelyPlaying);
23643
+ // also allow explicit 'playing' evidence we latched separately
23644
+ return strong || this.seenVideoPlaying;
23645
+ }
23646
+ startVideoInitWatchdog() {
23647
+ // restart the interval
23648
+ this.stopVideoInitWatchdog();
23649
+ const startedAt = Date.now();
23650
+ this.videoInitWatchdogInterval = window.setInterval(() => {
23651
+ if (this.videoInitializedSent) {
23652
+ this.stopVideoInitWatchdog();
23653
+ return;
23654
+ }
23655
+ if (this.hasMediaEvidence()) {
23656
+ this.sendVideoInitializedOnce();
23657
+ this.stopVideoInitWatchdog();
23658
+ return;
23659
+ }
23660
+ // Optional maximum wait: if set and exceeded, backfill only if we saw playing
23661
+ if (this.videoInitMaxWaitMs && Date.now() - startedAt > this.videoInitMaxWaitMs) {
23662
+ if (this.seenVideoPlaying && !this.videoInitializedSent) {
23663
+ this.sendVideoInitializedOnce();
23664
+ }
23665
+ this.stopVideoInitWatchdog();
23666
+ }
23667
+ }, this.videoInitCheckMs);
23668
+ }
23669
+ stopVideoInitWatchdog() {
23670
+ if (this.videoInitWatchdogInterval) {
23671
+ window.clearInterval(this.videoInitWatchdogInterval);
23672
+ this.videoInitWatchdogInterval = undefined;
23673
+ }
23674
+ }
23633
23675
  startTransportWatcher() {
23634
23676
  // Rebind if the transport object reference changes (cheap safety net)
23635
23677
  if (this._transportWatchTimer)
@@ -23656,7 +23698,9 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23656
23698
  if (this._boundVideoEl && this._onVideoPlaying) {
23657
23699
  this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
23658
23700
  }
23659
- this._onVideoPlaying = () => this.sendVideoInitializedOnce();
23701
+ this._onVideoPlaying = () => {
23702
+ this.seenVideoPlaying = true;
23703
+ };
23660
23704
  videoEl.addEventListener("playing", this._onVideoPlaying, { once: true });
23661
23705
  this._boundVideoEl = videoEl;
23662
23706
  }
@@ -23680,7 +23724,7 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23680
23724
  return state !== undefined ? state : WebSocket.CLOSED;
23681
23725
  }
23682
23726
  constructor(config, overrides) {
23683
- var _a, _b, _c;
23727
+ var _a, _b, _c, _d, _f, _g, _h;
23684
23728
  /** As soon as upstream is fixed, we got to adjust the url building process. */
23685
23729
  (0,_ApplyUrlHack__WEBPACK_IMPORTED_MODULE_6__.ApplyUrlHack)();
23686
23730
  super(config, overrides);
@@ -23692,6 +23736,8 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23692
23736
  this.videoInitializedSent = false;
23693
23737
  this.versionReplyInFlight = false;
23694
23738
  this.nextMsgId = 1;
23739
+ this.videoInitCheckMs = 250; // default poll; can be overridden from config
23740
+ this.seenVideoPlaying = false;
23695
23741
  // Externalized
23696
23742
  /** On ping the session creation timestamp will be updated. */
23697
23743
  this.queueHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler();
@@ -23717,6 +23763,7 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23717
23763
  const transport = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23718
23764
  (_b = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _b === void 0 ? void 0 : _b.call(transport, "open", () => {
23719
23765
  this.flushOutbox();
23766
+ this.startVideoInitWatchdog(); // only start, no send
23720
23767
  });
23721
23768
  (_c = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _c === void 0 ? void 0 : _c.call(transport, "close", (evt) => {
23722
23769
  // Bubble to your public close handler if you expose one
@@ -23727,6 +23774,8 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23727
23774
  this.setupVideoInitFallbacks();
23728
23775
  // Set override config.
23729
23776
  this.config = config;
23777
+ this.videoInitCheckMs = (_f = (_d = this.config.settings) === null || _d === void 0 ? void 0 : _d.videoInitCheckMs) !== null && _f !== void 0 ? _f : this.videoInitCheckMs;
23778
+ this.videoInitMaxWaitMs = (_h = (_g = this.config.settings) === null || _g === void 0 ? void 0 : _g.videoInitMaxWaitMs) !== null && _h !== void 0 ? _h : undefined;
23730
23779
  this.loveLettersList = [];
23731
23780
  this.microphoneOverlay = new _ui_MicrophoneOverlay__WEBPACK_IMPORTED_MODULE_7__.MicrophoneOverlay(this);
23732
23781
  this.diagnosticsCollector = new _features_DiagnosticsCollector__WEBPACK_IMPORTED_MODULE_3__.DiagnosticsCollector({
@@ -23892,55 +23941,51 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23892
23941
  }
23893
23942
  // Attach fallbacks once (call this in constructor after transport wiring)
23894
23943
  setupVideoInitFallbacks() {
23895
- var _a, _b, _c, _d, _e, _f, _g;
23944
+ var _a, _b, _c, _d, _f, _g, _h;
23896
23945
  // Fallback #1: HTMLVideoElement 'playing'
23897
23946
  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
- }
23947
+ (_d = videoEl === null || videoEl === void 0 ? void 0 : videoEl.addEventListener) === null || _d === void 0 ? void 0 : _d.call(videoEl, "playing", () => {
23948
+ this.seenVideoPlaying = true;
23949
+ }, { once: true });
23950
+ (_f = this.addEventListener) === null || _f === void 0 ? void 0 : _f.call(this, "statsReceived", (_e) => {
23951
+ /* no-op for video init */
23906
23952
  });
23907
23953
  // 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
- }
23954
+ const transport = (_g = this.webRtcController) === null || _g === void 0 ? void 0 : _g.transport;
23955
+ (_h = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _h === void 0 ? void 0 : _h.call(transport, "open", () => {
23956
+ this.startVideoInitWatchdog(); // only start, no send
23913
23957
  });
23914
23958
  }
23915
23959
  onVideoInitialized() {
23916
- var _a, _b, _c, _d, _e, _f, _g;
23960
+ var _a, _b, _c, _d, _f, _g, _h;
23917
23961
  // send early and once
23962
+ this.stopVideoInitWatchdog(); // PS event arrived, cancel backup
23918
23963
  this.sendVideoInitializedOnce();
23919
23964
  // keep side-effects guarded so they can't break the send
23920
23965
  try {
23921
23966
  (_a = this.handleMouseLock) === null || _a === void 0 ? void 0 : _a.call(this);
23922
23967
  }
23923
- catch (_h) { }
23924
- try {
23925
- (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23926
- }
23927
23968
  catch (_j) { }
23928
23969
  try {
23929
- (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23970
+ (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23930
23971
  }
23931
23972
  catch (_k) { }
23932
23973
  try {
23933
- (_e = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _e === void 0 ? void 0 : _e.call(_d, false);
23974
+ (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23934
23975
  }
23935
23976
  catch (_l) { }
23936
23977
  try {
23937
- (_f = this.applyResolutionIfPlaying) === null || _f === void 0 ? void 0 : _f.call(this);
23978
+ (_f = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _f === void 0 ? void 0 : _f.call(_d, false);
23938
23979
  }
23939
23980
  catch (_m) { }
23940
23981
  try {
23941
- (_g = this.removeXRIconIfDisabled) === null || _g === void 0 ? void 0 : _g.call(this);
23982
+ (_g = this.applyResolutionIfPlaying) === null || _g === void 0 ? void 0 : _g.call(this);
23942
23983
  }
23943
23984
  catch (_o) { }
23985
+ try {
23986
+ (_h = this.removeXRIconIfDisabled) === null || _h === void 0 ? void 0 : _h.call(this);
23987
+ }
23988
+ catch (_p) { }
23944
23989
  }
23945
23990
  /** Adding a zod-safe handler. */
23946
23991
  addMessageHandler(type, zod, boundMethod) {
@@ -24014,14 +24059,14 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
24014
24059
  }
24015
24060
  }
24016
24061
  handleResolutionChange() {
24017
- var _a, _b, _c, _d, _e, _f, _g;
24062
+ var _a, _b, _c, _d, _f, _g, _h;
24018
24063
  // Get the resolution from the streamInfo if available
24019
24064
  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
24065
  return;
24021
24066
  }
24022
24067
  // Get the resolution from the streamInfo if available
24023
24068
  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;
24069
+ 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
24070
  // Check if resolution.dynamic is true
24026
24071
  if (resolution && (resolution === null || resolution === void 0 ? void 0 : resolution.dynamic)) {
24027
24072
  setTimeout(() => {
@@ -24075,6 +24120,7 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
24075
24120
  }
24076
24121
  removePlayer() {
24077
24122
  var _a, _b, _c, _d;
24123
+ this.stopVideoInitWatchdog(); // PS event arrived, cancel backup
24078
24124
  this.stopTransportWatcher();
24079
24125
  // Optional: unbind handlers
24080
24126
  if (this._boundTransport) {
@@ -24215,12 +24261,12 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
24215
24261
  });
24216
24262
  }
24217
24263
  removeXRIconIfDisabled() {
24218
- var _a, _b, _c, _d, _e;
24264
+ var _a, _b, _c, _d, _f;
24219
24265
  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
24266
  (_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
24267
  if (this.videoElementParent) {
24222
24268
  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");
24269
+ const xrBtn = (_f = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _f === void 0 ? void 0 : _f.parentElement.querySelector("#xrBtn");
24224
24270
  xrBtn === null || xrBtn === void 0 ? void 0 : xrBtn.remove();
24225
24271
  }
24226
24272
  }
package/index.umd.js CHANGED
@@ -23244,27 +23244,28 @@ class ArcwareApplication extends lib_pixelstreamingfrontend_ui_ue5_5_1.Applicati
23244
23244
  });
23245
23245
  }
23246
23246
  applicationResponse(response) {
23247
- var _a, _b;
23248
- let obj = null;
23247
+ var _a, _b, _c, _d;
23248
+ let obj;
23249
23249
  try {
23250
23250
  obj = (0, common_1.parseUnknownToObject)(response, { allowJsonish: true });
23251
23251
  }
23252
- catch (_c) {
23253
- // If not parseable, fall through to generic callback
23252
+ catch (_e) {
23253
+ // not parseable just send to generic handler and bail out
23254
+ (_a = this.responseCallback) === null || _a === void 0 ? void 0 : _a.call(this, response);
23255
+ return;
23254
23256
  }
23255
23257
  const t = (0, common_1.normalizeType)(obj["type"]);
23256
23258
  // route to exactly one callback
23257
23259
  if (t === "event") {
23258
- (_a = this.analyticsEventCallback) === null || _a === void 0 ? void 0 : _a.call(this, response);
23260
+ (_b = this.analyticsEventCallback) === null || _b === void 0 ? void 0 : _b.call(this, response);
23259
23261
  return;
23260
23262
  }
23261
23263
  if (t === "filetransfer" || t === "createscreenshot") {
23262
- (_b = this.fileDownloadCallback) === null || _b === void 0 ? void 0 : _b.call(this, response);
23264
+ (_c = this.fileDownloadCallback) === null || _c === void 0 ? void 0 : _c.call(this, response);
23263
23265
  return;
23264
23266
  }
23265
- if (this.responseCallback) {
23266
- this.responseCallback(response);
23267
- }
23267
+ // fallback: unknown type → generic callback
23268
+ (_d = this.responseCallback) === null || _d === void 0 ? void 0 : _d.call(this, response);
23268
23269
  }
23269
23270
  applyArcwareStyles() {
23270
23271
  const PixelStreamingApplicationStyles = new lib_pixelstreamingfrontend_ui_ue5_5_1.PixelStreamingApplicationStyle(ArcwarePixelStreamingApplicationStyles_1.ArcwareStyles);
@@ -23429,7 +23430,7 @@ class ArcwareConfig extends lib_pixelstreamingfrontend_ue5_5_1.Config {
23429
23430
  if (!config.initialSettings.ss)
23430
23431
  config.initialSettings.ss = exports.DefaultUrl;
23431
23432
  super(config);
23432
- this.VERSION = "1.3.2";
23433
+ this.VERSION = "1.3.4";
23433
23434
  this.settings = settings;
23434
23435
  this.session = new Session_1.Session();
23435
23436
  this._initialSettings = config.initialSettings;
@@ -23584,7 +23585,7 @@ const ConnectionIdentifier_1 = __webpack_require__(5999);
23584
23585
  const DiagnosticsCollector_1 = __webpack_require__(8429);
23585
23586
  class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStreaming {
23586
23587
  bindTransportEvents() {
23587
- var _a, _b, _c, _d, _e, _f, _g;
23588
+ var _a, _b, _c, _d, _f, _g, _h;
23588
23589
  const current = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23589
23590
  if (!current || current === this._boundTransport)
23590
23591
  return;
@@ -23593,15 +23594,13 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23593
23594
  if (this._onWsOpen)
23594
23595
  (_c = (_b = this._boundTransport).removeEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, "open", this._onWsOpen);
23595
23596
  if (this._onWsClose)
23596
- (_e = (_d = this._boundTransport).removeEventListener) === null || _e === void 0 ? void 0 : _e.call(_d, "close", this._onWsClose);
23597
+ (_f = (_d = this._boundTransport).removeEventListener) === null || _f === void 0 ? void 0 : _f.call(_d, "close", this._onWsClose);
23597
23598
  }
23598
23599
  // Define (or reuse) callbacks
23599
23600
  if (!this._onWsOpen) {
23600
23601
  this._onWsOpen = () => {
23601
23602
  this.flushOutbox();
23602
- // fallback nudge for videoInitialized
23603
- if (!this.videoInitializedSent)
23604
- setTimeout(() => this.sendVideoInitializedOnce(), 150);
23603
+ this.startVideoInitWatchdog(); // only start, no send
23605
23604
  };
23606
23605
  }
23607
23606
  if (!this._onWsClose) {
@@ -23611,10 +23610,53 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23611
23610
  };
23612
23611
  }
23613
23612
  // 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);
23613
+ (_g = current.addEventListener) === null || _g === void 0 ? void 0 : _g.call(current, "open", this._onWsOpen);
23614
+ (_h = current.addEventListener) === null || _h === void 0 ? void 0 : _h.call(current, "close", this._onWsClose);
23616
23615
  this._boundTransport = current;
23617
23616
  }
23617
+ // conservative media-evidence check (no stats involved)
23618
+ hasMediaEvidence() {
23619
+ var _a, _b, _c;
23620
+ 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);
23621
+ if (!videoEl)
23622
+ return false;
23623
+ const dimensions = videoEl.videoWidth > 0 && videoEl.videoHeight > 0;
23624
+ const ready = videoEl.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA; // >= 2
23625
+ const activelyPlaying = !videoEl.paused && !videoEl.ended;
23626
+ // Require at least two signals to avoid false positives on metadata-only loads
23627
+ const strong = (dimensions && ready) || (dimensions && activelyPlaying) || (ready && activelyPlaying);
23628
+ // also allow explicit 'playing' evidence we latched separately
23629
+ return strong || this.seenVideoPlaying;
23630
+ }
23631
+ startVideoInitWatchdog() {
23632
+ // restart the interval
23633
+ this.stopVideoInitWatchdog();
23634
+ const startedAt = Date.now();
23635
+ this.videoInitWatchdogInterval = window.setInterval(() => {
23636
+ if (this.videoInitializedSent) {
23637
+ this.stopVideoInitWatchdog();
23638
+ return;
23639
+ }
23640
+ if (this.hasMediaEvidence()) {
23641
+ this.sendVideoInitializedOnce();
23642
+ this.stopVideoInitWatchdog();
23643
+ return;
23644
+ }
23645
+ // Optional maximum wait: if set and exceeded, backfill only if we saw playing
23646
+ if (this.videoInitMaxWaitMs && Date.now() - startedAt > this.videoInitMaxWaitMs) {
23647
+ if (this.seenVideoPlaying && !this.videoInitializedSent) {
23648
+ this.sendVideoInitializedOnce();
23649
+ }
23650
+ this.stopVideoInitWatchdog();
23651
+ }
23652
+ }, this.videoInitCheckMs);
23653
+ }
23654
+ stopVideoInitWatchdog() {
23655
+ if (this.videoInitWatchdogInterval) {
23656
+ window.clearInterval(this.videoInitWatchdogInterval);
23657
+ this.videoInitWatchdogInterval = undefined;
23658
+ }
23659
+ }
23618
23660
  startTransportWatcher() {
23619
23661
  // Rebind if the transport object reference changes (cheap safety net)
23620
23662
  if (this._transportWatchTimer)
@@ -23641,7 +23683,9 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23641
23683
  if (this._boundVideoEl && this._onVideoPlaying) {
23642
23684
  this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
23643
23685
  }
23644
- this._onVideoPlaying = () => this.sendVideoInitializedOnce();
23686
+ this._onVideoPlaying = () => {
23687
+ this.seenVideoPlaying = true;
23688
+ };
23645
23689
  videoEl.addEventListener("playing", this._onVideoPlaying, { once: true });
23646
23690
  this._boundVideoEl = videoEl;
23647
23691
  }
@@ -23665,7 +23709,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23665
23709
  return state !== undefined ? state : WebSocket.CLOSED;
23666
23710
  }
23667
23711
  constructor(config, overrides) {
23668
- var _a, _b, _c;
23712
+ var _a, _b, _c, _d, _f, _g, _h;
23669
23713
  /** As soon as upstream is fixed, we got to adjust the url building process. */
23670
23714
  (0, ApplyUrlHack_1.ApplyUrlHack)();
23671
23715
  super(config, overrides);
@@ -23677,6 +23721,8 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23677
23721
  this.videoInitializedSent = false;
23678
23722
  this.versionReplyInFlight = false;
23679
23723
  this.nextMsgId = 1;
23724
+ this.videoInitCheckMs = 250; // default poll; can be overridden from config
23725
+ this.seenVideoPlaying = false;
23680
23726
  // Externalized
23681
23727
  /** On ping the session creation timestamp will be updated. */
23682
23728
  this.queueHandler = new EventHandler_1.EventHandler();
@@ -23702,6 +23748,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23702
23748
  const transport = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23703
23749
  (_b = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _b === void 0 ? void 0 : _b.call(transport, "open", () => {
23704
23750
  this.flushOutbox();
23751
+ this.startVideoInitWatchdog(); // only start, no send
23705
23752
  });
23706
23753
  (_c = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _c === void 0 ? void 0 : _c.call(transport, "close", (evt) => {
23707
23754
  // Bubble to your public close handler if you expose one
@@ -23712,6 +23759,8 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23712
23759
  this.setupVideoInitFallbacks();
23713
23760
  // Set override config.
23714
23761
  this.config = config;
23762
+ this.videoInitCheckMs = (_f = (_d = this.config.settings) === null || _d === void 0 ? void 0 : _d.videoInitCheckMs) !== null && _f !== void 0 ? _f : this.videoInitCheckMs;
23763
+ this.videoInitMaxWaitMs = (_h = (_g = this.config.settings) === null || _g === void 0 ? void 0 : _g.videoInitMaxWaitMs) !== null && _h !== void 0 ? _h : undefined;
23715
23764
  this.loveLettersList = [];
23716
23765
  this.microphoneOverlay = new MicrophoneOverlay_1.MicrophoneOverlay(this);
23717
23766
  this.diagnosticsCollector = new DiagnosticsCollector_1.DiagnosticsCollector({
@@ -23877,55 +23926,51 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23877
23926
  }
23878
23927
  // Attach fallbacks once (call this in constructor after transport wiring)
23879
23928
  setupVideoInitFallbacks() {
23880
- var _a, _b, _c, _d, _e, _f, _g;
23929
+ var _a, _b, _c, _d, _f, _g, _h;
23881
23930
  // Fallback #1: HTMLVideoElement 'playing'
23882
23931
  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
- }
23932
+ (_d = videoEl === null || videoEl === void 0 ? void 0 : videoEl.addEventListener) === null || _d === void 0 ? void 0 : _d.call(videoEl, "playing", () => {
23933
+ this.seenVideoPlaying = true;
23934
+ }, { once: true });
23935
+ (_f = this.addEventListener) === null || _f === void 0 ? void 0 : _f.call(this, "statsReceived", (_e) => {
23936
+ /* no-op for video init */
23891
23937
  });
23892
23938
  // 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
- }
23939
+ const transport = (_g = this.webRtcController) === null || _g === void 0 ? void 0 : _g.transport;
23940
+ (_h = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _h === void 0 ? void 0 : _h.call(transport, "open", () => {
23941
+ this.startVideoInitWatchdog(); // only start, no send
23898
23942
  });
23899
23943
  }
23900
23944
  onVideoInitialized() {
23901
- var _a, _b, _c, _d, _e, _f, _g;
23945
+ var _a, _b, _c, _d, _f, _g, _h;
23902
23946
  // send early and once
23947
+ this.stopVideoInitWatchdog(); // PS event arrived, cancel backup
23903
23948
  this.sendVideoInitializedOnce();
23904
23949
  // keep side-effects guarded so they can't break the send
23905
23950
  try {
23906
23951
  (_a = this.handleMouseLock) === null || _a === void 0 ? void 0 : _a.call(this);
23907
23952
  }
23908
- catch (_h) { }
23909
- try {
23910
- (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23911
- }
23912
23953
  catch (_j) { }
23913
23954
  try {
23914
- (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23955
+ (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23915
23956
  }
23916
23957
  catch (_k) { }
23917
23958
  try {
23918
- (_e = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _e === void 0 ? void 0 : _e.call(_d, false);
23959
+ (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23919
23960
  }
23920
23961
  catch (_l) { }
23921
23962
  try {
23922
- (_f = this.applyResolutionIfPlaying) === null || _f === void 0 ? void 0 : _f.call(this);
23963
+ (_f = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _f === void 0 ? void 0 : _f.call(_d, false);
23923
23964
  }
23924
23965
  catch (_m) { }
23925
23966
  try {
23926
- (_g = this.removeXRIconIfDisabled) === null || _g === void 0 ? void 0 : _g.call(this);
23967
+ (_g = this.applyResolutionIfPlaying) === null || _g === void 0 ? void 0 : _g.call(this);
23927
23968
  }
23928
23969
  catch (_o) { }
23970
+ try {
23971
+ (_h = this.removeXRIconIfDisabled) === null || _h === void 0 ? void 0 : _h.call(this);
23972
+ }
23973
+ catch (_p) { }
23929
23974
  }
23930
23975
  /** Adding a zod-safe handler. */
23931
23976
  addMessageHandler(type, zod, boundMethod) {
@@ -23999,14 +24044,14 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23999
24044
  }
24000
24045
  }
24001
24046
  handleResolutionChange() {
24002
- var _a, _b, _c, _d, _e, _f, _g;
24047
+ var _a, _b, _c, _d, _f, _g, _h;
24003
24048
  // Get the resolution from the streamInfo if available
24004
24049
  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
24050
  return;
24006
24051
  }
24007
24052
  // Get the resolution from the streamInfo if available
24008
24053
  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;
24054
+ 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
24055
  // Check if resolution.dynamic is true
24011
24056
  if (resolution && (resolution === null || resolution === void 0 ? void 0 : resolution.dynamic)) {
24012
24057
  setTimeout(() => {
@@ -24060,6 +24105,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24060
24105
  }
24061
24106
  removePlayer() {
24062
24107
  var _a, _b, _c, _d;
24108
+ this.stopVideoInitWatchdog(); // PS event arrived, cancel backup
24063
24109
  this.stopTransportWatcher();
24064
24110
  // Optional: unbind handlers
24065
24111
  if (this._boundTransport) {
@@ -24200,12 +24246,12 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24200
24246
  });
24201
24247
  }
24202
24248
  removeXRIconIfDisabled() {
24203
- var _a, _b, _c, _d, _e;
24249
+ var _a, _b, _c, _d, _f;
24204
24250
  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
24251
  (_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
24252
  if (this.videoElementParent) {
24207
24253
  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");
24254
+ const xrBtn = (_f = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _f === void 0 ? void 0 : _f.parentElement.querySelector("#xrBtn");
24209
24255
  xrBtn === null || xrBtn === void 0 ? void 0 : xrBtn.remove();
24210
24256
  }
24211
24257
  }
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.4",
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.4";
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;