@arcware-cloud/pixelstreaming-websdk 1.3.8 → 1.3.10

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,10 @@ For more detailed examples and advanced usage, please refer to our documentation
80
80
 
81
81
  # Changelog
82
82
 
83
+ ### 1.3.9
84
+
85
+ - added an event handler to check if video is streaming if cloud requests evidence
86
+
83
87
  ### 1.3.8
84
88
 
85
89
  - fixed error handling in SDK to back of reconnects if connection was intentionally terminated by cloud
package/index.cjs.js CHANGED
@@ -23420,7 +23420,7 @@ class ArcwareConfig extends lib_pixelstreamingfrontend_ue5_5_1.Config {
23420
23420
  if (!config.initialSettings.ss)
23421
23421
  config.initialSettings.ss = exports.DefaultUrl;
23422
23422
  super(config);
23423
- this.VERSION = "1.3.8";
23423
+ this.VERSION = "1.3.10";
23424
23424
  this.settings = settings;
23425
23425
  this.session = new Session_1.Session();
23426
23426
  this._initialSettings = config.initialSettings;
@@ -23536,7 +23536,7 @@ function ArcwareInit({ shareId, projectId }, configuration, forceRefresh = false
23536
23536
  useUrlParams: (configuration === null || configuration === void 0 ? void 0 : configuration.useUrlParams) === true,
23537
23537
  initialSettings: Object.assign({ ss: ArcwareConfig_1.DefaultUrl, AutoConnect: false, StartVideoMuted: true, AutoPlayVideo: true, KeyboardInput: true, MouseInput: true, GamepadInput: true, TouchInput: true, XRControllerInput: true, UseMic: true, SuppressBrowserKeys: true, FakeMouseWithTouches: false, ForceMonoAudio: false, HoveringMouse: true }, configuration === null || configuration === void 0 ? void 0 : configuration.initialSettings),
23538
23538
  settings: Object.assign({ shareId,
23539
- projectId, fullscreenButton: true, audioButton: true, stopButton: false, infoButton: false, micButton: false, settingsButton: false, connectionStrengthIcon: false, connectionIdentifierLoggingDisabled: undefined, errorHandler: undefined, loveLetterHandler: undefined, loveLetterLogging: undefined, queueHandler: undefined, sessionIdHandler: undefined, startHeight: undefined, startWidth: undefined }, configuration === null || configuration === void 0 ? void 0 : configuration.settings)
23539
+ projectId, fullscreenButton: true, audioButton: true, stopButton: false, infoButton: false, micButton: false, settingsButton: false, connectionStrengthIcon: false, connectionIdentifierLoggingDisabled: undefined, errorHandler: undefined, loveLetterHandler: undefined, loveLetterLogging: undefined, queueHandler: undefined, sessionIdHandler: undefined, startHeight: undefined, startWidth: undefined, orientationZoom: undefined }, configuration === null || configuration === void 0 ? void 0 : configuration.settings)
23540
23540
  });
23541
23541
  const PixelStreaming = new ArcwarePixelStreaming_1.ArcwarePixelStreaming(Config);
23542
23542
  const Application = new ArcwareApplication_1.ArcwareApplication({ stream: PixelStreaming });
@@ -23573,6 +23573,7 @@ const ArcwareLogoLoader_1 = __webpack_require__(6469);
23573
23573
  const MicrophoneOverlay_1 = __webpack_require__(3613);
23574
23574
  const ConnectionIdentifier_1 = __webpack_require__(5999);
23575
23575
  const DiagnosticsCollector_1 = __webpack_require__(8429);
23576
+ const common_1 = __webpack_require__(2483);
23576
23577
  class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStreaming {
23577
23578
  resetInitGuardsAndHooks() {
23578
23579
  this.videoInitializedSent = false;
@@ -23725,6 +23726,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23725
23726
  this.addMessageHandler("ping", shared_pixelstreaming_websdk_1.Messages.ZPing, this.onPing);
23726
23727
  this.addMessageHandler("queue", shared_pixelstreaming_websdk_1.Messages.ZQueue, this.onQueue);
23727
23728
  this.addMessageHandler("version", shared_pixelstreaming_websdk_1.Messages.ZVersion, this.onVersion);
23729
+ this.addMessageHandler("render", shared_pixelstreaming_websdk_1.Messages.ZRender, this.onRender);
23728
23730
  // Create a debounced version of the handleResolutionChange function
23729
23731
  const debouncedResolutionChange = (0, debounce_1.default)(() => {
23730
23732
  this.handleResolutionChange();
@@ -23791,6 +23793,64 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23791
23793
  }
23792
23794
  });
23793
23795
  }
23796
+ isVideoRenderingNow(video) {
23797
+ if (!video)
23798
+ return false;
23799
+ const hasDims = video.videoWidth > 0 && video.videoHeight > 0;
23800
+ const hasData = video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA; // ≥2
23801
+ const playing = !video.paused && !video.ended;
23802
+ // Be conservative: require at least two signals to avoid metadata-only false positives
23803
+ return (hasDims && hasData) || (hasDims && playing) || (hasData && playing);
23804
+ }
23805
+ waitForFirstFrameWithTimeout(ms = 2000) {
23806
+ var _a, _b, _c;
23807
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
23808
+ const video = (_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);
23809
+ if (this.isVideoRenderingNow(video))
23810
+ return true;
23811
+ let t;
23812
+ const ok = yield Promise.race([
23813
+ new Promise((resolve) => {
23814
+ var _a, _b;
23815
+ const done = () => {
23816
+ cleanup();
23817
+ resolve(true);
23818
+ };
23819
+ const cleanup = () => {
23820
+ var _a, _b;
23821
+ video.removeEventListener("playing", onPlaying);
23822
+ video.removeEventListener("resize", onResize);
23823
+ if ("cancelVideoFrameCallback" in HTMLVideoElement.prototype && rvfcId != null) {
23824
+ (_b = (_a = video).cancelVideoFrameCallback) === null || _b === void 0 ? void 0 : _b.call(_a, rvfcId);
23825
+ }
23826
+ };
23827
+ const onPlaying = () => this.isVideoRenderingNow(video) && done();
23828
+ const onResize = () => this.isVideoRenderingNow(video) && done();
23829
+ video.addEventListener("playing", onPlaying, { once: true });
23830
+ video.addEventListener("resize", onResize, { once: true });
23831
+ const rvfcId = "requestVideoFrameCallback" in HTMLVideoElement.prototype
23832
+ ? (_b = (_a = video).requestVideoFrameCallback) === null || _b === void 0 ? void 0 : _b.call(_a, () => done())
23833
+ : null;
23834
+ }),
23835
+ new Promise((resolve) => {
23836
+ t = window.setTimeout(() => resolve(false), ms);
23837
+ })
23838
+ ]);
23839
+ if (t)
23840
+ clearTimeout(t);
23841
+ return ok;
23842
+ });
23843
+ }
23844
+ onRender(_msg) {
23845
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
23846
+ const isRendering = yield this.waitForFirstFrameWithTimeout();
23847
+ const payload = {
23848
+ type: "render",
23849
+ isRendering: isRendering
23850
+ };
23851
+ this.send(payload); // uses buffered send
23852
+ });
23853
+ }
23794
23854
  /** On ping the session creation timestamp will be updated. */
23795
23855
  onPing(message) {
23796
23856
  var _a, _b;
@@ -24043,15 +24103,16 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24043
24103
  }
24044
24104
  }
24045
24105
  handleResolutionChange() {
24046
- var _a, _b, _c, _d, _e, _f, _g;
24106
+ var _a, _b, _c, _d, _e, _f, _g, _h;
24047
24107
  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())) {
24048
24108
  return;
24049
24109
  }
24050
24110
  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;
24051
24111
  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;
24112
+ const orientationZoom = (_h = this.config.settings) === null || _h === void 0 ? void 0 : _h.orientationZoom;
24052
24113
  if (resolution && (resolution === null || resolution === void 0 ? void 0 : resolution.dynamic)) {
24053
24114
  setTimeout(() => {
24054
- var _a;
24115
+ var _a, _b, _c;
24055
24116
  const { videoPlayer } = this === null || this === void 0 ? void 0 : this.webRtcController;
24056
24117
  const videoElementParent = videoPlayer === null || videoPlayer === void 0 ? void 0 : videoPlayer.getVideoParentElement();
24057
24118
  const browserWidth = videoElementParent === null || videoElementParent === void 0 ? void 0 : videoElementParent.getBoundingClientRect().width;
@@ -24068,10 +24129,32 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24068
24129
  limitedHeight = maxHeight;
24069
24130
  limitedWidth = maxHeight * aspectRatio;
24070
24131
  }
24132
+ // width: clientWidth * Math.max(window.devicePixelRatio, 1) - for retina device, 1 is min upscale factor
24133
+ const newRes = (0, common_1.capScale)({
24134
+ width: browserWidth * Math.max(window.devicePixelRatio, 1.25),
24135
+ height: browserHeight * Math.max(window.devicePixelRatio, 1.25),
24136
+ }, {
24137
+ width: maxWidth,
24138
+ height: maxHeight,
24139
+ });
24140
+ // Zoom level for orientation change if provided
24141
+ if (orientationZoom) {
24142
+ if (newRes.width < newRes.height) {
24143
+ if (orientationZoom.hasOwnProperty('portrait'))
24144
+ (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.emitUIInteraction({
24145
+ zoom: orientationZoom.portrait
24146
+ });
24147
+ }
24148
+ else if (orientationZoom.hasOwnProperty('landscape')) {
24149
+ (_b = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _b === void 0 ? void 0 : _b.emitUIInteraction({
24150
+ zoom: orientationZoom.landscape
24151
+ });
24152
+ }
24153
+ }
24071
24154
  if (videoPlayer) {
24072
24155
  if (!unrealVersion || (unrealVersion === null || unrealVersion === void 0 ? void 0 : unrealVersion.startsWith("4.27"))) {
24073
24156
  const descriptor = { Console: `r.setres ${Math.round(limitedWidth)}x${Math.round(limitedHeight)}w` };
24074
- (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.emitUIInteraction(descriptor);
24157
+ (_c = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _c === void 0 ? void 0 : _c.emitUIInteraction(descriptor);
24075
24158
  }
24076
24159
  else {
24077
24160
  videoPlayer.onMatchViewportResolutionCallback(Math.round(limitedWidth), Math.round(limitedHeight));
@@ -24257,11 +24340,14 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24257
24340
  }
24258
24341
  }
24259
24342
  injectCustomUI() {
24260
- var _a;
24261
- const customUI = document === null || document === void 0 ? void 0 : document.getElementById("stream-ui");
24262
- const videoElementParent = (_a = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _a === void 0 ? void 0 : _a.parentElement;
24263
- if (customUI && videoElementParent)
24264
- videoElementParent === null || videoElementParent === void 0 ? void 0 : videoElementParent.appendChild(customUI);
24343
+ (0, common_1.waitForElement)('#stream-ui')
24344
+ .then(el => {
24345
+ var _a;
24346
+ const videoElementParent = (_a = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _a === void 0 ? void 0 : _a.parentElement;
24347
+ if (videoElementParent) {
24348
+ videoElementParent === null || videoElementParent === void 0 ? void 0 : videoElementParent.appendChild(el);
24349
+ }
24350
+ });
24265
24351
  }
24266
24352
  }
24267
24353
  exports.ArcwarePixelStreaming = ArcwarePixelStreaming;
@@ -24325,7 +24411,12 @@ exports.ArcwareSettingsSchema = zod_1.z.object({
24325
24411
  /** Width with which instance should be started */
24326
24412
  startWidth: zod_1.z.number().optional(),
24327
24413
  /** Height with which instance should be started */
24328
- startHeight: zod_1.z.number().optional()
24414
+ startHeight: zod_1.z.number().optional(),
24415
+ /** Zoom functionality */
24416
+ orientationZoom: zod_1.z.object({
24417
+ landscape: zod_1.z.number(),
24418
+ portrait: zod_1.z.number(),
24419
+ }).strict().optional()
24329
24420
  });
24330
24421
 
24331
24422
 
@@ -25123,7 +25214,7 @@ exports.DiagnosticsCollector = DiagnosticsCollector;
25123
25214
 
25124
25215
 
25125
25216
  Object.defineProperty(exports, "__esModule", ({ value: true }));
25126
- exports.normalizeType = exports.randomHash = exports.extFromMime = exports.sanitizeFilename = exports.truncateByBytes = exports.parseUnknownToObject = void 0;
25217
+ exports.capScale = exports.waitForElement = exports.normalizeType = exports.randomHash = exports.extFromMime = exports.sanitizeFilename = exports.truncateByBytes = exports.parseUnknownToObject = void 0;
25127
25218
  /** Conservative normalizer: accepts object, strict JSON string, or JSON-ish like {foo: "bar"} */
25128
25219
  function parseUnknownToObject(input, opts = { allowJsonish: true }) {
25129
25220
  if (input && typeof input === "object")
@@ -25222,6 +25313,47 @@ function normalizeType(v) {
25222
25313
  return typeof v === "string" ? v.trim().toLowerCase() : "";
25223
25314
  }
25224
25315
  exports.normalizeType = normalizeType;
25316
+ function waitForElement(selector, { root = document, timeout = 3000 } = {}) {
25317
+ return new Promise((resolve) => {
25318
+ const existing = root.querySelector(selector);
25319
+ if (existing)
25320
+ return resolve(existing);
25321
+ const observer = new MutationObserver(() => {
25322
+ const el = root.querySelector(selector);
25323
+ if (el) {
25324
+ clearTimeout(timer);
25325
+ observer.disconnect();
25326
+ resolve(el); // fires once
25327
+ }
25328
+ });
25329
+ observer.observe(root.documentElement || root, { childList: true, subtree: true });
25330
+ const timer = setTimeout(() => {
25331
+ observer.disconnect();
25332
+ }, timeout);
25333
+ });
25334
+ }
25335
+ exports.waitForElement = waitForElement;
25336
+ function capScale(size, max) {
25337
+ const result = { width: 0, height: 0 };
25338
+ /* result.width = size.width > max.width ? max.width : size.width;
25339
+ result.height = size.height > max.height ? max.height : size.height; */
25340
+ result.width = Math.floor(size.width);
25341
+ result.height = Math.floor(size.height);
25342
+ if (result.height > max.height) {
25343
+ const heightScale = max.height / result.height;
25344
+ result.height = max.height;
25345
+ result.width *= heightScale;
25346
+ }
25347
+ if (result.width > max.width) {
25348
+ const heightScale = max.width / result.width;
25349
+ result.width = max.width;
25350
+ result.height *= heightScale;
25351
+ }
25352
+ result.width = (result.width % 2) + result.width;
25353
+ result.height = (result.height % 2) + result.height;
25354
+ return result;
25355
+ }
25356
+ exports.capScale = capScale;
25225
25357
 
25226
25358
 
25227
25359
  /***/ }),
@@ -26427,6 +26559,20 @@ exports.ZQueue = zod_1.z.object({
26427
26559
  });
26428
26560
 
26429
26561
 
26562
+ /***/ }),
26563
+
26564
+ /***/ 1919:
26565
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
26566
+
26567
+
26568
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
26569
+ exports.ZRender = void 0;
26570
+ const zod_1 = __webpack_require__(8754);
26571
+ exports.ZRender = zod_1.z.object({
26572
+ type: zod_1.z.literal("render")
26573
+ });
26574
+
26575
+
26430
26576
  /***/ }),
26431
26577
 
26432
26578
  /***/ 4201:
@@ -26784,9 +26930,10 @@ tslib_1.__exportStar(__webpack_require__(1224), exports);
26784
26930
  tslib_1.__exportStar(__webpack_require__(4882), exports);
26785
26931
  tslib_1.__exportStar(__webpack_require__(3751), exports);
26786
26932
  tslib_1.__exportStar(__webpack_require__(9864), exports);
26933
+ tslib_1.__exportStar(__webpack_require__(1919), exports);
26787
26934
  const Stats_1 = __webpack_require__(3403);
26788
26935
  exports.Send = {
26789
- stats: Stats_1.ZStats,
26936
+ stats: Stats_1.ZStats
26790
26937
  };
26791
26938
 
26792
26939
 
package/index.esm.js CHANGED
@@ -23428,7 +23428,7 @@ class ArcwareConfig extends _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBP
23428
23428
  if (!config.initialSettings.ss)
23429
23429
  config.initialSettings.ss = DefaultUrl;
23430
23430
  super(config);
23431
- this.VERSION = "1.3.8";
23431
+ this.VERSION = "1.3.10";
23432
23432
  this.settings = settings;
23433
23433
  this.session = new _domain_Session__WEBPACK_IMPORTED_MODULE_0__.Session();
23434
23434
  this._initialSettings = config.initialSettings;
@@ -23547,7 +23547,7 @@ function ArcwareInit({ shareId, projectId }, configuration, forceRefresh = false
23547
23547
  useUrlParams: (configuration === null || configuration === void 0 ? void 0 : configuration.useUrlParams) === true,
23548
23548
  initialSettings: Object.assign({ ss: _ArcwareConfig__WEBPACK_IMPORTED_MODULE_0__.DefaultUrl, AutoConnect: false, StartVideoMuted: true, AutoPlayVideo: true, KeyboardInput: true, MouseInput: true, GamepadInput: true, TouchInput: true, XRControllerInput: true, UseMic: true, SuppressBrowserKeys: true, FakeMouseWithTouches: false, ForceMonoAudio: false, HoveringMouse: true }, configuration === null || configuration === void 0 ? void 0 : configuration.initialSettings),
23549
23549
  settings: Object.assign({ shareId,
23550
- projectId, fullscreenButton: true, audioButton: true, stopButton: false, infoButton: false, micButton: false, settingsButton: false, connectionStrengthIcon: false, connectionIdentifierLoggingDisabled: undefined, errorHandler: undefined, loveLetterHandler: undefined, loveLetterLogging: undefined, queueHandler: undefined, sessionIdHandler: undefined, startHeight: undefined, startWidth: undefined }, configuration === null || configuration === void 0 ? void 0 : configuration.settings)
23550
+ projectId, fullscreenButton: true, audioButton: true, stopButton: false, infoButton: false, micButton: false, settingsButton: false, connectionStrengthIcon: false, connectionIdentifierLoggingDisabled: undefined, errorHandler: undefined, loveLetterHandler: undefined, loveLetterLogging: undefined, queueHandler: undefined, sessionIdHandler: undefined, startHeight: undefined, startWidth: undefined, orientationZoom: undefined }, configuration === null || configuration === void 0 ? void 0 : configuration.settings)
23551
23551
  });
23552
23552
  const PixelStreaming = new _ArcwarePixelStreaming__WEBPACK_IMPORTED_MODULE_1__.ArcwarePixelStreaming(Config);
23553
23553
  const Application = new _ArcwareApplication__WEBPACK_IMPORTED_MODULE_2__.ArcwareApplication({ stream: PixelStreaming });
@@ -23581,11 +23581,13 @@ __webpack_require__.r(__webpack_exports__);
23581
23581
  /* harmony import */ var _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(3379);
23582
23582
  /* harmony import */ var _domain_Stats__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9764);
23583
23583
  /* harmony import */ var _domain_debounce__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(9580);
23584
- /* harmony import */ var _ui_LoveLetters__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(4572);
23585
- /* harmony import */ var _ui_ArcwareLogoLoader__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(6469);
23584
+ /* harmony import */ var _ui_LoveLetters__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(4572);
23585
+ /* harmony import */ var _ui_ArcwareLogoLoader__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(6469);
23586
23586
  /* harmony import */ var _ui_MicrophoneOverlay__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(3613);
23587
23587
  /* harmony import */ var _domain_ConnectionIdentifier__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5999);
23588
23588
  /* harmony import */ var _features_DiagnosticsCollector__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8429);
23589
+ /* harmony import */ var _features_common__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(2483);
23590
+
23589
23591
 
23590
23592
 
23591
23593
 
@@ -23750,6 +23752,7 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23750
23752
  this.addMessageHandler("ping", _arcware_cloud_shared_pixelstreaming_websdk__WEBPACK_IMPORTED_MODULE_0__.Messages.ZPing, this.onPing);
23751
23753
  this.addMessageHandler("queue", _arcware_cloud_shared_pixelstreaming_websdk__WEBPACK_IMPORTED_MODULE_0__.Messages.ZQueue, this.onQueue);
23752
23754
  this.addMessageHandler("version", _arcware_cloud_shared_pixelstreaming_websdk__WEBPACK_IMPORTED_MODULE_0__.Messages.ZVersion, this.onVersion);
23755
+ this.addMessageHandler("render", _arcware_cloud_shared_pixelstreaming_websdk__WEBPACK_IMPORTED_MODULE_0__.Messages.ZRender, this.onRender);
23753
23756
  // Create a debounced version of the handleResolutionChange function
23754
23757
  const debouncedResolutionChange = (0,_domain_debounce__WEBPACK_IMPORTED_MODULE_8__["default"])(() => {
23755
23758
  this.handleResolutionChange();
@@ -23816,6 +23819,64 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23816
23819
  }
23817
23820
  });
23818
23821
  }
23822
+ isVideoRenderingNow(video) {
23823
+ if (!video)
23824
+ return false;
23825
+ const hasDims = video.videoWidth > 0 && video.videoHeight > 0;
23826
+ const hasData = video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA; // ≥2
23827
+ const playing = !video.paused && !video.ended;
23828
+ // Be conservative: require at least two signals to avoid metadata-only false positives
23829
+ return (hasDims && hasData) || (hasDims && playing) || (hasData && playing);
23830
+ }
23831
+ waitForFirstFrameWithTimeout(ms = 2000) {
23832
+ var _a, _b, _c;
23833
+ return (0,tslib__WEBPACK_IMPORTED_MODULE_9__.__awaiter)(this, void 0, void 0, function* () {
23834
+ const video = (_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);
23835
+ if (this.isVideoRenderingNow(video))
23836
+ return true;
23837
+ let t;
23838
+ const ok = yield Promise.race([
23839
+ new Promise((resolve) => {
23840
+ var _a, _b;
23841
+ const done = () => {
23842
+ cleanup();
23843
+ resolve(true);
23844
+ };
23845
+ const cleanup = () => {
23846
+ var _a, _b;
23847
+ video.removeEventListener("playing", onPlaying);
23848
+ video.removeEventListener("resize", onResize);
23849
+ if ("cancelVideoFrameCallback" in HTMLVideoElement.prototype && rvfcId != null) {
23850
+ (_b = (_a = video).cancelVideoFrameCallback) === null || _b === void 0 ? void 0 : _b.call(_a, rvfcId);
23851
+ }
23852
+ };
23853
+ const onPlaying = () => this.isVideoRenderingNow(video) && done();
23854
+ const onResize = () => this.isVideoRenderingNow(video) && done();
23855
+ video.addEventListener("playing", onPlaying, { once: true });
23856
+ video.addEventListener("resize", onResize, { once: true });
23857
+ const rvfcId = "requestVideoFrameCallback" in HTMLVideoElement.prototype
23858
+ ? (_b = (_a = video).requestVideoFrameCallback) === null || _b === void 0 ? void 0 : _b.call(_a, () => done())
23859
+ : null;
23860
+ }),
23861
+ new Promise((resolve) => {
23862
+ t = window.setTimeout(() => resolve(false), ms);
23863
+ })
23864
+ ]);
23865
+ if (t)
23866
+ clearTimeout(t);
23867
+ return ok;
23868
+ });
23869
+ }
23870
+ onRender(_msg) {
23871
+ return (0,tslib__WEBPACK_IMPORTED_MODULE_9__.__awaiter)(this, void 0, void 0, function* () {
23872
+ const isRendering = yield this.waitForFirstFrameWithTimeout();
23873
+ const payload = {
23874
+ type: "render",
23875
+ isRendering: isRendering
23876
+ };
23877
+ this.send(payload); // uses buffered send
23878
+ });
23879
+ }
23819
23880
  /** On ping the session creation timestamp will be updated. */
23820
23881
  onPing(message) {
23821
23882
  var _a, _b;
@@ -24068,15 +24129,16 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
24068
24129
  }
24069
24130
  }
24070
24131
  handleResolutionChange() {
24071
- var _a, _b, _c, _d, _e, _f, _g;
24132
+ var _a, _b, _c, _d, _e, _f, _g, _h;
24072
24133
  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())) {
24073
24134
  return;
24074
24135
  }
24075
24136
  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;
24076
24137
  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;
24138
+ const orientationZoom = (_h = this.config.settings) === null || _h === void 0 ? void 0 : _h.orientationZoom;
24077
24139
  if (resolution && (resolution === null || resolution === void 0 ? void 0 : resolution.dynamic)) {
24078
24140
  setTimeout(() => {
24079
- var _a;
24141
+ var _a, _b, _c;
24080
24142
  const { videoPlayer } = this === null || this === void 0 ? void 0 : this.webRtcController;
24081
24143
  const videoElementParent = videoPlayer === null || videoPlayer === void 0 ? void 0 : videoPlayer.getVideoParentElement();
24082
24144
  const browserWidth = videoElementParent === null || videoElementParent === void 0 ? void 0 : videoElementParent.getBoundingClientRect().width;
@@ -24093,10 +24155,32 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
24093
24155
  limitedHeight = maxHeight;
24094
24156
  limitedWidth = maxHeight * aspectRatio;
24095
24157
  }
24158
+ // width: clientWidth * Math.max(window.devicePixelRatio, 1) - for retina device, 1 is min upscale factor
24159
+ const newRes = (0,_features_common__WEBPACK_IMPORTED_MODULE_12__.capScale)({
24160
+ width: browserWidth * Math.max(window.devicePixelRatio, 1.25),
24161
+ height: browserHeight * Math.max(window.devicePixelRatio, 1.25),
24162
+ }, {
24163
+ width: maxWidth,
24164
+ height: maxHeight,
24165
+ });
24166
+ // Zoom level for orientation change if provided
24167
+ if (orientationZoom) {
24168
+ if (newRes.width < newRes.height) {
24169
+ if (orientationZoom.hasOwnProperty('portrait'))
24170
+ (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.emitUIInteraction({
24171
+ zoom: orientationZoom.portrait
24172
+ });
24173
+ }
24174
+ else if (orientationZoom.hasOwnProperty('landscape')) {
24175
+ (_b = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _b === void 0 ? void 0 : _b.emitUIInteraction({
24176
+ zoom: orientationZoom.landscape
24177
+ });
24178
+ }
24179
+ }
24096
24180
  if (videoPlayer) {
24097
24181
  if (!unrealVersion || (unrealVersion === null || unrealVersion === void 0 ? void 0 : unrealVersion.startsWith("4.27"))) {
24098
24182
  const descriptor = { Console: `r.setres ${Math.round(limitedWidth)}x${Math.round(limitedHeight)}w` };
24099
- (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.emitUIInteraction(descriptor);
24183
+ (_c = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _c === void 0 ? void 0 : _c.emitUIInteraction(descriptor);
24100
24184
  }
24101
24185
  else {
24102
24186
  videoPlayer.onMatchViewportResolutionCallback(Math.round(limitedWidth), Math.round(limitedHeight));
@@ -24156,7 +24240,7 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
24156
24240
  }
24157
24241
  initLoveLettersContainer() {
24158
24242
  var _a;
24159
- const logoLoader = new _ui_ArcwareLogoLoader__WEBPACK_IMPORTED_MODULE_12__.ArcwareLogoLoader();
24243
+ const logoLoader = new _ui_ArcwareLogoLoader__WEBPACK_IMPORTED_MODULE_13__.ArcwareLogoLoader();
24160
24244
  if (!this.loveLettersContainer) {
24161
24245
  const loveLettersContainer = document === null || document === void 0 ? void 0 : document.createElement("div");
24162
24246
  const { videoPlayer } = this === null || this === void 0 ? void 0 : this.webRtcController;
@@ -24193,7 +24277,7 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
24193
24277
  if (letter !== undefined) {
24194
24278
  const formattedLoveLetter = letter === null || letter === void 0 ? void 0 : letter.replace(/LL: |\.$/g, "");
24195
24279
  (_a = this === null || this === void 0 ? void 0 : this.loveLettersList) === null || _a === void 0 ? void 0 : _a.push(formattedLoveLetter);
24196
- const loveLettersBox = new _ui_LoveLetters__WEBPACK_IMPORTED_MODULE_13__.LoveLetters();
24280
+ const loveLettersBox = new _ui_LoveLetters__WEBPACK_IMPORTED_MODULE_14__.LoveLetters();
24197
24281
  loveLettersBox === null || loveLettersBox === void 0 ? void 0 : loveLettersBox.addLetter(formattedLoveLetter, (_b = this === null || this === void 0 ? void 0 : this.loveLettersList) === null || _b === void 0 ? void 0 : _b.length);
24198
24282
  setTimeout(() => {
24199
24283
  this.processLoveLetterQueue();
@@ -24282,11 +24366,14 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
24282
24366
  }
24283
24367
  }
24284
24368
  injectCustomUI() {
24285
- var _a;
24286
- const customUI = document === null || document === void 0 ? void 0 : document.getElementById("stream-ui");
24287
- const videoElementParent = (_a = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _a === void 0 ? void 0 : _a.parentElement;
24288
- if (customUI && videoElementParent)
24289
- videoElementParent === null || videoElementParent === void 0 ? void 0 : videoElementParent.appendChild(customUI);
24369
+ (0,_features_common__WEBPACK_IMPORTED_MODULE_12__.waitForElement)('#stream-ui')
24370
+ .then(el => {
24371
+ var _a;
24372
+ const videoElementParent = (_a = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _a === void 0 ? void 0 : _a.parentElement;
24373
+ if (videoElementParent) {
24374
+ videoElementParent === null || videoElementParent === void 0 ? void 0 : videoElementParent.appendChild(el);
24375
+ }
24376
+ });
24290
24377
  }
24291
24378
  }
24292
24379
 
@@ -24352,7 +24439,12 @@ const ArcwareSettingsSchema = zod__WEBPACK_IMPORTED_MODULE_1__.z.object({
24352
24439
  /** Width with which instance should be started */
24353
24440
  startWidth: zod__WEBPACK_IMPORTED_MODULE_1__.z.number().optional(),
24354
24441
  /** Height with which instance should be started */
24355
- startHeight: zod__WEBPACK_IMPORTED_MODULE_1__.z.number().optional()
24442
+ startHeight: zod__WEBPACK_IMPORTED_MODULE_1__.z.number().optional(),
24443
+ /** Zoom functionality */
24444
+ orientationZoom: zod__WEBPACK_IMPORTED_MODULE_1__.z.object({
24445
+ landscape: zod__WEBPACK_IMPORTED_MODULE_1__.z.number(),
24446
+ portrait: zod__WEBPACK_IMPORTED_MODULE_1__.z.number(),
24447
+ }).strict().optional()
24356
24448
  });
24357
24449
 
24358
24450
 
@@ -25160,12 +25252,14 @@ class DiagnosticsCollector {
25160
25252
 
25161
25253
  __webpack_require__.r(__webpack_exports__);
25162
25254
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
25255
+ /* harmony export */ "capScale": () => (/* binding */ capScale),
25163
25256
  /* harmony export */ "extFromMime": () => (/* binding */ extFromMime),
25164
25257
  /* harmony export */ "normalizeType": () => (/* binding */ normalizeType),
25165
25258
  /* harmony export */ "parseUnknownToObject": () => (/* binding */ parseUnknownToObject),
25166
25259
  /* harmony export */ "randomHash": () => (/* binding */ randomHash),
25167
25260
  /* harmony export */ "sanitizeFilename": () => (/* binding */ sanitizeFilename),
25168
- /* harmony export */ "truncateByBytes": () => (/* binding */ truncateByBytes)
25261
+ /* harmony export */ "truncateByBytes": () => (/* binding */ truncateByBytes),
25262
+ /* harmony export */ "waitForElement": () => (/* binding */ waitForElement)
25169
25263
  /* harmony export */ });
25170
25264
  /** Conservative normalizer: accepts object, strict JSON string, or JSON-ish like {foo: "bar"} */
25171
25265
  function parseUnknownToObject(input, opts = { allowJsonish: true }) {
@@ -25259,6 +25353,45 @@ function randomHash() {
25259
25353
  function normalizeType(v) {
25260
25354
  return typeof v === "string" ? v.trim().toLowerCase() : "";
25261
25355
  }
25356
+ function waitForElement(selector, { root = document, timeout = 3000 } = {}) {
25357
+ return new Promise((resolve) => {
25358
+ const existing = root.querySelector(selector);
25359
+ if (existing)
25360
+ return resolve(existing);
25361
+ const observer = new MutationObserver(() => {
25362
+ const el = root.querySelector(selector);
25363
+ if (el) {
25364
+ clearTimeout(timer);
25365
+ observer.disconnect();
25366
+ resolve(el); // fires once
25367
+ }
25368
+ });
25369
+ observer.observe(root.documentElement || root, { childList: true, subtree: true });
25370
+ const timer = setTimeout(() => {
25371
+ observer.disconnect();
25372
+ }, timeout);
25373
+ });
25374
+ }
25375
+ function capScale(size, max) {
25376
+ const result = { width: 0, height: 0 };
25377
+ /* result.width = size.width > max.width ? max.width : size.width;
25378
+ result.height = size.height > max.height ? max.height : size.height; */
25379
+ result.width = Math.floor(size.width);
25380
+ result.height = Math.floor(size.height);
25381
+ if (result.height > max.height) {
25382
+ const heightScale = max.height / result.height;
25383
+ result.height = max.height;
25384
+ result.width *= heightScale;
25385
+ }
25386
+ if (result.width > max.width) {
25387
+ const heightScale = max.width / result.width;
25388
+ result.width = max.width;
25389
+ result.height *= heightScale;
25390
+ }
25391
+ result.width = (result.width % 2) + result.width;
25392
+ result.height = (result.height % 2) + result.height;
25393
+ return result;
25394
+ }
25262
25395
 
25263
25396
 
25264
25397
  /***/ }),
@@ -26492,6 +26625,22 @@ const ZQueue = zod__WEBPACK_IMPORTED_MODULE_0__.z.object({
26492
26625
  });
26493
26626
 
26494
26627
 
26628
+ /***/ }),
26629
+
26630
+ /***/ 1919:
26631
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
26632
+
26633
+ __webpack_require__.r(__webpack_exports__);
26634
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
26635
+ /* harmony export */ "ZRender": () => (/* binding */ ZRender)
26636
+ /* harmony export */ });
26637
+ /* harmony import */ var zod__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1604);
26638
+
26639
+ const ZRender = zod__WEBPACK_IMPORTED_MODULE_0__.z.object({
26640
+ type: zod__WEBPACK_IMPORTED_MODULE_0__.z.literal("render")
26641
+ });
26642
+
26643
+
26495
26644
  /***/ }),
26496
26645
 
26497
26646
  /***/ 4201:
@@ -26829,6 +26978,7 @@ __webpack_require__.r(__webpack_exports__);
26829
26978
  /* harmony export */ "ZLoveLetter": () => (/* reexport safe */ _LoveLetter__WEBPACK_IMPORTED_MODULE_1__.ZLoveLetter),
26830
26979
  /* harmony export */ "ZPing": () => (/* reexport safe */ _Ping__WEBPACK_IMPORTED_MODULE_5__.ZPing),
26831
26980
  /* harmony export */ "ZQueue": () => (/* reexport safe */ _Queue__WEBPACK_IMPORTED_MODULE_6__.ZQueue),
26981
+ /* harmony export */ "ZRender": () => (/* reexport safe */ _Render__WEBPACK_IMPORTED_MODULE_9__.ZRender),
26832
26982
  /* harmony export */ "ZSessionId": () => (/* reexport safe */ _SessionId__WEBPACK_IMPORTED_MODULE_2__.ZSessionId),
26833
26983
  /* harmony export */ "ZStats": () => (/* reexport safe */ _Stats__WEBPACK_IMPORTED_MODULE_4__.ZStats),
26834
26984
  /* harmony export */ "ZStreamInfo": () => (/* reexport safe */ _StreamInfo__WEBPACK_IMPORTED_MODULE_3__.ZStreamInfo),
@@ -26843,6 +26993,8 @@ __webpack_require__.r(__webpack_exports__);
26843
26993
  /* harmony import */ var _Queue__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(4882);
26844
26994
  /* harmony import */ var _Version__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(3751);
26845
26995
  /* harmony import */ var _WebSdkSettings__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(9864);
26996
+ /* harmony import */ var _Render__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(1919);
26997
+
26846
26998
 
26847
26999
 
26848
27000
 
@@ -26854,7 +27006,7 @@ __webpack_require__.r(__webpack_exports__);
26854
27006
 
26855
27007
 
26856
27008
  const Send = {
26857
- stats: _Stats__WEBPACK_IMPORTED_MODULE_4__.ZStats,
27009
+ stats: _Stats__WEBPACK_IMPORTED_MODULE_4__.ZStats
26858
27010
  };
26859
27011
 
26860
27012
 
package/index.umd.js CHANGED
@@ -23430,7 +23430,7 @@ class ArcwareConfig extends lib_pixelstreamingfrontend_ue5_5_1.Config {
23430
23430
  if (!config.initialSettings.ss)
23431
23431
  config.initialSettings.ss = exports.DefaultUrl;
23432
23432
  super(config);
23433
- this.VERSION = "1.3.8";
23433
+ this.VERSION = "1.3.10";
23434
23434
  this.settings = settings;
23435
23435
  this.session = new Session_1.Session();
23436
23436
  this._initialSettings = config.initialSettings;
@@ -23546,7 +23546,7 @@ function ArcwareInit({ shareId, projectId }, configuration, forceRefresh = false
23546
23546
  useUrlParams: (configuration === null || configuration === void 0 ? void 0 : configuration.useUrlParams) === true,
23547
23547
  initialSettings: Object.assign({ ss: ArcwareConfig_1.DefaultUrl, AutoConnect: false, StartVideoMuted: true, AutoPlayVideo: true, KeyboardInput: true, MouseInput: true, GamepadInput: true, TouchInput: true, XRControllerInput: true, UseMic: true, SuppressBrowserKeys: true, FakeMouseWithTouches: false, ForceMonoAudio: false, HoveringMouse: true }, configuration === null || configuration === void 0 ? void 0 : configuration.initialSettings),
23548
23548
  settings: Object.assign({ shareId,
23549
- projectId, fullscreenButton: true, audioButton: true, stopButton: false, infoButton: false, micButton: false, settingsButton: false, connectionStrengthIcon: false, connectionIdentifierLoggingDisabled: undefined, errorHandler: undefined, loveLetterHandler: undefined, loveLetterLogging: undefined, queueHandler: undefined, sessionIdHandler: undefined, startHeight: undefined, startWidth: undefined }, configuration === null || configuration === void 0 ? void 0 : configuration.settings)
23549
+ projectId, fullscreenButton: true, audioButton: true, stopButton: false, infoButton: false, micButton: false, settingsButton: false, connectionStrengthIcon: false, connectionIdentifierLoggingDisabled: undefined, errorHandler: undefined, loveLetterHandler: undefined, loveLetterLogging: undefined, queueHandler: undefined, sessionIdHandler: undefined, startHeight: undefined, startWidth: undefined, orientationZoom: undefined }, configuration === null || configuration === void 0 ? void 0 : configuration.settings)
23550
23550
  });
23551
23551
  const PixelStreaming = new ArcwarePixelStreaming_1.ArcwarePixelStreaming(Config);
23552
23552
  const Application = new ArcwareApplication_1.ArcwareApplication({ stream: PixelStreaming });
@@ -23583,6 +23583,7 @@ const ArcwareLogoLoader_1 = __webpack_require__(6469);
23583
23583
  const MicrophoneOverlay_1 = __webpack_require__(3613);
23584
23584
  const ConnectionIdentifier_1 = __webpack_require__(5999);
23585
23585
  const DiagnosticsCollector_1 = __webpack_require__(8429);
23586
+ const common_1 = __webpack_require__(2483);
23586
23587
  class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStreaming {
23587
23588
  resetInitGuardsAndHooks() {
23588
23589
  this.videoInitializedSent = false;
@@ -23735,6 +23736,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23735
23736
  this.addMessageHandler("ping", shared_pixelstreaming_websdk_1.Messages.ZPing, this.onPing);
23736
23737
  this.addMessageHandler("queue", shared_pixelstreaming_websdk_1.Messages.ZQueue, this.onQueue);
23737
23738
  this.addMessageHandler("version", shared_pixelstreaming_websdk_1.Messages.ZVersion, this.onVersion);
23739
+ this.addMessageHandler("render", shared_pixelstreaming_websdk_1.Messages.ZRender, this.onRender);
23738
23740
  // Create a debounced version of the handleResolutionChange function
23739
23741
  const debouncedResolutionChange = (0, debounce_1.default)(() => {
23740
23742
  this.handleResolutionChange();
@@ -23801,6 +23803,64 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23801
23803
  }
23802
23804
  });
23803
23805
  }
23806
+ isVideoRenderingNow(video) {
23807
+ if (!video)
23808
+ return false;
23809
+ const hasDims = video.videoWidth > 0 && video.videoHeight > 0;
23810
+ const hasData = video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA; // ≥2
23811
+ const playing = !video.paused && !video.ended;
23812
+ // Be conservative: require at least two signals to avoid metadata-only false positives
23813
+ return (hasDims && hasData) || (hasDims && playing) || (hasData && playing);
23814
+ }
23815
+ waitForFirstFrameWithTimeout(ms = 2000) {
23816
+ var _a, _b, _c;
23817
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
23818
+ const video = (_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);
23819
+ if (this.isVideoRenderingNow(video))
23820
+ return true;
23821
+ let t;
23822
+ const ok = yield Promise.race([
23823
+ new Promise((resolve) => {
23824
+ var _a, _b;
23825
+ const done = () => {
23826
+ cleanup();
23827
+ resolve(true);
23828
+ };
23829
+ const cleanup = () => {
23830
+ var _a, _b;
23831
+ video.removeEventListener("playing", onPlaying);
23832
+ video.removeEventListener("resize", onResize);
23833
+ if ("cancelVideoFrameCallback" in HTMLVideoElement.prototype && rvfcId != null) {
23834
+ (_b = (_a = video).cancelVideoFrameCallback) === null || _b === void 0 ? void 0 : _b.call(_a, rvfcId);
23835
+ }
23836
+ };
23837
+ const onPlaying = () => this.isVideoRenderingNow(video) && done();
23838
+ const onResize = () => this.isVideoRenderingNow(video) && done();
23839
+ video.addEventListener("playing", onPlaying, { once: true });
23840
+ video.addEventListener("resize", onResize, { once: true });
23841
+ const rvfcId = "requestVideoFrameCallback" in HTMLVideoElement.prototype
23842
+ ? (_b = (_a = video).requestVideoFrameCallback) === null || _b === void 0 ? void 0 : _b.call(_a, () => done())
23843
+ : null;
23844
+ }),
23845
+ new Promise((resolve) => {
23846
+ t = window.setTimeout(() => resolve(false), ms);
23847
+ })
23848
+ ]);
23849
+ if (t)
23850
+ clearTimeout(t);
23851
+ return ok;
23852
+ });
23853
+ }
23854
+ onRender(_msg) {
23855
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
23856
+ const isRendering = yield this.waitForFirstFrameWithTimeout();
23857
+ const payload = {
23858
+ type: "render",
23859
+ isRendering: isRendering
23860
+ };
23861
+ this.send(payload); // uses buffered send
23862
+ });
23863
+ }
23804
23864
  /** On ping the session creation timestamp will be updated. */
23805
23865
  onPing(message) {
23806
23866
  var _a, _b;
@@ -24053,15 +24113,16 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24053
24113
  }
24054
24114
  }
24055
24115
  handleResolutionChange() {
24056
- var _a, _b, _c, _d, _e, _f, _g;
24116
+ var _a, _b, _c, _d, _e, _f, _g, _h;
24057
24117
  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())) {
24058
24118
  return;
24059
24119
  }
24060
24120
  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;
24061
24121
  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;
24122
+ const orientationZoom = (_h = this.config.settings) === null || _h === void 0 ? void 0 : _h.orientationZoom;
24062
24123
  if (resolution && (resolution === null || resolution === void 0 ? void 0 : resolution.dynamic)) {
24063
24124
  setTimeout(() => {
24064
- var _a;
24125
+ var _a, _b, _c;
24065
24126
  const { videoPlayer } = this === null || this === void 0 ? void 0 : this.webRtcController;
24066
24127
  const videoElementParent = videoPlayer === null || videoPlayer === void 0 ? void 0 : videoPlayer.getVideoParentElement();
24067
24128
  const browserWidth = videoElementParent === null || videoElementParent === void 0 ? void 0 : videoElementParent.getBoundingClientRect().width;
@@ -24078,10 +24139,32 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24078
24139
  limitedHeight = maxHeight;
24079
24140
  limitedWidth = maxHeight * aspectRatio;
24080
24141
  }
24142
+ // width: clientWidth * Math.max(window.devicePixelRatio, 1) - for retina device, 1 is min upscale factor
24143
+ const newRes = (0, common_1.capScale)({
24144
+ width: browserWidth * Math.max(window.devicePixelRatio, 1.25),
24145
+ height: browserHeight * Math.max(window.devicePixelRatio, 1.25),
24146
+ }, {
24147
+ width: maxWidth,
24148
+ height: maxHeight,
24149
+ });
24150
+ // Zoom level for orientation change if provided
24151
+ if (orientationZoom) {
24152
+ if (newRes.width < newRes.height) {
24153
+ if (orientationZoom.hasOwnProperty('portrait'))
24154
+ (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.emitUIInteraction({
24155
+ zoom: orientationZoom.portrait
24156
+ });
24157
+ }
24158
+ else if (orientationZoom.hasOwnProperty('landscape')) {
24159
+ (_b = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _b === void 0 ? void 0 : _b.emitUIInteraction({
24160
+ zoom: orientationZoom.landscape
24161
+ });
24162
+ }
24163
+ }
24081
24164
  if (videoPlayer) {
24082
24165
  if (!unrealVersion || (unrealVersion === null || unrealVersion === void 0 ? void 0 : unrealVersion.startsWith("4.27"))) {
24083
24166
  const descriptor = { Console: `r.setres ${Math.round(limitedWidth)}x${Math.round(limitedHeight)}w` };
24084
- (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.emitUIInteraction(descriptor);
24167
+ (_c = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _c === void 0 ? void 0 : _c.emitUIInteraction(descriptor);
24085
24168
  }
24086
24169
  else {
24087
24170
  videoPlayer.onMatchViewportResolutionCallback(Math.round(limitedWidth), Math.round(limitedHeight));
@@ -24267,11 +24350,14 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
24267
24350
  }
24268
24351
  }
24269
24352
  injectCustomUI() {
24270
- var _a;
24271
- const customUI = document === null || document === void 0 ? void 0 : document.getElementById("stream-ui");
24272
- const videoElementParent = (_a = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _a === void 0 ? void 0 : _a.parentElement;
24273
- if (customUI && videoElementParent)
24274
- videoElementParent === null || videoElementParent === void 0 ? void 0 : videoElementParent.appendChild(customUI);
24353
+ (0, common_1.waitForElement)('#stream-ui')
24354
+ .then(el => {
24355
+ var _a;
24356
+ const videoElementParent = (_a = this === null || this === void 0 ? void 0 : this.videoElementParent) === null || _a === void 0 ? void 0 : _a.parentElement;
24357
+ if (videoElementParent) {
24358
+ videoElementParent === null || videoElementParent === void 0 ? void 0 : videoElementParent.appendChild(el);
24359
+ }
24360
+ });
24275
24361
  }
24276
24362
  }
24277
24363
  exports.ArcwarePixelStreaming = ArcwarePixelStreaming;
@@ -24335,7 +24421,12 @@ exports.ArcwareSettingsSchema = zod_1.z.object({
24335
24421
  /** Width with which instance should be started */
24336
24422
  startWidth: zod_1.z.number().optional(),
24337
24423
  /** Height with which instance should be started */
24338
- startHeight: zod_1.z.number().optional()
24424
+ startHeight: zod_1.z.number().optional(),
24425
+ /** Zoom functionality */
24426
+ orientationZoom: zod_1.z.object({
24427
+ landscape: zod_1.z.number(),
24428
+ portrait: zod_1.z.number(),
24429
+ }).strict().optional()
24339
24430
  });
24340
24431
 
24341
24432
 
@@ -25133,7 +25224,7 @@ exports.DiagnosticsCollector = DiagnosticsCollector;
25133
25224
 
25134
25225
 
25135
25226
  Object.defineProperty(exports, "__esModule", ({ value: true }));
25136
- exports.normalizeType = exports.randomHash = exports.extFromMime = exports.sanitizeFilename = exports.truncateByBytes = exports.parseUnknownToObject = void 0;
25227
+ exports.capScale = exports.waitForElement = exports.normalizeType = exports.randomHash = exports.extFromMime = exports.sanitizeFilename = exports.truncateByBytes = exports.parseUnknownToObject = void 0;
25137
25228
  /** Conservative normalizer: accepts object, strict JSON string, or JSON-ish like {foo: "bar"} */
25138
25229
  function parseUnknownToObject(input, opts = { allowJsonish: true }) {
25139
25230
  if (input && typeof input === "object")
@@ -25232,6 +25323,47 @@ function normalizeType(v) {
25232
25323
  return typeof v === "string" ? v.trim().toLowerCase() : "";
25233
25324
  }
25234
25325
  exports.normalizeType = normalizeType;
25326
+ function waitForElement(selector, { root = document, timeout = 3000 } = {}) {
25327
+ return new Promise((resolve) => {
25328
+ const existing = root.querySelector(selector);
25329
+ if (existing)
25330
+ return resolve(existing);
25331
+ const observer = new MutationObserver(() => {
25332
+ const el = root.querySelector(selector);
25333
+ if (el) {
25334
+ clearTimeout(timer);
25335
+ observer.disconnect();
25336
+ resolve(el); // fires once
25337
+ }
25338
+ });
25339
+ observer.observe(root.documentElement || root, { childList: true, subtree: true });
25340
+ const timer = setTimeout(() => {
25341
+ observer.disconnect();
25342
+ }, timeout);
25343
+ });
25344
+ }
25345
+ exports.waitForElement = waitForElement;
25346
+ function capScale(size, max) {
25347
+ const result = { width: 0, height: 0 };
25348
+ /* result.width = size.width > max.width ? max.width : size.width;
25349
+ result.height = size.height > max.height ? max.height : size.height; */
25350
+ result.width = Math.floor(size.width);
25351
+ result.height = Math.floor(size.height);
25352
+ if (result.height > max.height) {
25353
+ const heightScale = max.height / result.height;
25354
+ result.height = max.height;
25355
+ result.width *= heightScale;
25356
+ }
25357
+ if (result.width > max.width) {
25358
+ const heightScale = max.width / result.width;
25359
+ result.width = max.width;
25360
+ result.height *= heightScale;
25361
+ }
25362
+ result.width = (result.width % 2) + result.width;
25363
+ result.height = (result.height % 2) + result.height;
25364
+ return result;
25365
+ }
25366
+ exports.capScale = capScale;
25235
25367
 
25236
25368
 
25237
25369
  /***/ }),
@@ -26437,6 +26569,20 @@ exports.ZQueue = zod_1.z.object({
26437
26569
  });
26438
26570
 
26439
26571
 
26572
+ /***/ }),
26573
+
26574
+ /***/ 1919:
26575
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
26576
+
26577
+
26578
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
26579
+ exports.ZRender = void 0;
26580
+ const zod_1 = __webpack_require__(8754);
26581
+ exports.ZRender = zod_1.z.object({
26582
+ type: zod_1.z.literal("render")
26583
+ });
26584
+
26585
+
26440
26586
  /***/ }),
26441
26587
 
26442
26588
  /***/ 4201:
@@ -26794,9 +26940,10 @@ tslib_1.__exportStar(__webpack_require__(1224), exports);
26794
26940
  tslib_1.__exportStar(__webpack_require__(4882), exports);
26795
26941
  tslib_1.__exportStar(__webpack_require__(3751), exports);
26796
26942
  tslib_1.__exportStar(__webpack_require__(9864), exports);
26943
+ tslib_1.__exportStar(__webpack_require__(1919), exports);
26797
26944
  const Stats_1 = __webpack_require__(3403);
26798
26945
  exports.Send = {
26799
- stats: Stats_1.ZStats,
26946
+ stats: Stats_1.ZStats
26800
26947
  };
26801
26948
 
26802
26949
 
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.8",
4
+ "version": "1.3.10",
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.8";
29
+ readonly VERSION = "1.3.10";
30
30
  constructor(config: ArcwareConfigParams);
31
31
  /** Setup connection string. */
32
32
  get urlFlags(): string;
@@ -50,6 +50,9 @@ export declare class ArcwarePixelStreaming extends PixelStreaming {
50
50
  */
51
51
  /** On version requested, the version of the WebSDK would be returned. */
52
52
  private onVersion;
53
+ private isVideoRenderingNow;
54
+ private waitForFirstFrameWithTimeout;
55
+ private onRender;
53
56
  /** On ping the session creation timestamp will be updated. */
54
57
  private onPing;
55
58
  /** Handle incoming configurations. */
@@ -123,6 +123,17 @@ export declare const ArcwareSettingsSchema: z.ZodObject<{
123
123
  startWidth: z.ZodOptional<z.ZodNumber>;
124
124
  /** Height with which instance should be started */
125
125
  startHeight: z.ZodOptional<z.ZodNumber>;
126
+ /** Zoom functionality */
127
+ orientationZoom: z.ZodOptional<z.ZodObject<{
128
+ landscape: z.ZodNumber;
129
+ portrait: z.ZodNumber;
130
+ }, "strict", z.ZodTypeAny, {
131
+ landscape?: number;
132
+ portrait?: number;
133
+ }, {
134
+ landscape?: number;
135
+ portrait?: number;
136
+ }>>;
126
137
  }, "strip", z.ZodTypeAny, {
127
138
  session?: string;
128
139
  token?: string;
@@ -164,6 +175,10 @@ export declare const ArcwareSettingsSchema: z.ZodObject<{
164
175
  connectionIdentifierLoggingDisabled?: boolean;
165
176
  startWidth?: number;
166
177
  startHeight?: number;
178
+ orientationZoom?: {
179
+ landscape?: number;
180
+ portrait?: number;
181
+ };
167
182
  }, {
168
183
  session?: string;
169
184
  token?: string;
@@ -205,5 +220,9 @@ export declare const ArcwareSettingsSchema: z.ZodObject<{
205
220
  connectionIdentifierLoggingDisabled?: boolean;
206
221
  startWidth?: number;
207
222
  startHeight?: number;
223
+ orientationZoom?: {
224
+ landscape?: number;
225
+ portrait?: number;
226
+ };
208
227
  }>;
209
228
  export type Settings = z.infer<typeof ArcwareSettingsSchema>;
@@ -1,3 +1,4 @@
1
+ import { Size } from "@arcware-cloud/shared/signalling-communication";
1
2
  /** Conservative normalizer: accepts object, strict JSON string, or JSON-ish like {foo: "bar"} */
2
3
  export declare function parseUnknownToObject(input: unknown, opts?: {
3
4
  allowJsonish?: boolean;
@@ -11,3 +12,8 @@ export declare function extFromMime(mime: string): string;
11
12
  /** Short random fallback */
12
13
  export declare function randomHash(): string;
13
14
  export declare function normalizeType(v: unknown): string;
15
+ export declare function waitForElement(selector: string, { root, timeout }?: {
16
+ root?: Document;
17
+ timeout?: number;
18
+ }): Promise<any>;
19
+ export declare function capScale(size: Size, max: Size): Size;
@@ -0,0 +1,9 @@
1
+ import { z } from "zod";
2
+ export declare const ZRender: z.ZodObject<{
3
+ type: z.ZodLiteral<"render">;
4
+ }, "strip", z.ZodTypeAny, {
5
+ type?: "render";
6
+ }, {
7
+ type?: "render";
8
+ }>;
9
+ export type Render = z.infer<typeof ZRender>;
@@ -7,6 +7,7 @@ export * from "./Ping";
7
7
  export * from "./Queue";
8
8
  export * from "./Version";
9
9
  export * from "./WebSdkSettings";
10
+ export * from "./Render";
10
11
  export declare const Send: {
11
12
  stats: import("zod").ZodObject<{
12
13
  type: import("zod").ZodLiteral<"stats">;