senza-sdk 4.5.3 → 4.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "senza-sdk",
3
- "version": "4.5.3",
3
+ "version": "4.5.5",
4
4
  "main": "./src/api.js",
5
5
  "description": "API for Senza application",
6
6
  "license": "MIT",
@@ -29,12 +29,12 @@
29
29
  "@babel/preset-env": "^7.22.0",
30
30
  "@eslint/eslintrc": "^3.3.0",
31
31
  "@eslint/js": "^9.22.0",
32
- "babel-jest": "^30.2.0",
32
+ "babel-jest": "^30.4.1",
33
33
  "eslint": "^9.22.0",
34
34
  "eslint-plugin-jest": "^28.11.0",
35
35
  "globals": "^16.0.0",
36
- "jest": "^30.2.0",
37
- "jest-environment-jsdom": "^30.2.0",
36
+ "jest": "^30.4.2",
37
+ "jest-environment-jsdom": "^30.4.1",
38
38
  "jsdoc-to-markdown": "^7.1.1",
39
39
  "webpack": "^5.72.1",
40
40
  "webpack-cli": "^5.1.4"
@@ -55,9 +55,9 @@
55
55
  },
56
56
  "src/interface": {
57
57
  "branches": 64,
58
- "functions": 39.23,
58
+ "functions": 38,
59
59
  "lines": 63,
60
- "statements": 64
60
+ "statements": 63
61
61
  }
62
62
  }
63
63
  },
@@ -1,5 +1,5 @@
1
1
  import { AlarmManager as AlarmManagerInterface } from "../interface/alarmManager.js";
2
- import { getFCID, sdkLogger } from "./utils.js";
2
+ import { areAlarmsEnabled, getFCID, sdkLogger } from "./utils.js";
3
3
  import { EventListenersManager } from "./eventListenersManager.js";
4
4
  import { lifecycle } from "./lifecycle.js";
5
5
  import { bus, Events } from "./eventBus";
@@ -137,8 +137,13 @@ class AlarmManager extends AlarmManagerInterface {
137
137
  throw Error("data must be a string");
138
138
  }
139
139
  const FCID = getFCID();
140
- const logger = sdkLogger.withFields({ alarmName, FCID });
141
- logger.log(`addAlarm called for ${alarmName} to be fired at ${alarmTime} with tolerance of ${toleranceBefore} minutes before and ${toleranceAfter} minutes after`);
140
+ const alarmsEnabled = areAlarmsEnabled();
141
+ const logger = sdkLogger.withFields({ alarmName, FCID, alarmsEnabled });
142
+ logger.log(`addAlarm called for ${alarmName} to be fired at ${alarmTime} with tolerance of ${toleranceBefore} minutes before and ${toleranceAfter} minutes after. alarmsEnabled=${alarmsEnabled}`);
143
+ if (!alarmsEnabled) {
144
+ logger.log("addAlarm is disabled by ui-streamer disableAlarms setting; alarm request will not be sent");
145
+ return;
146
+ }
142
147
  if (window.cefQuery) {
143
148
  const message = {
144
149
  type: "addAlarm",
@@ -22,6 +22,8 @@ const OVERLAY_CAPTURE_PRESETS = {
22
22
 
23
23
  const DEFAULT_CAPTURE_PRESET = "default";
24
24
  const VALID_QUALITIES = new Set(["low", "mid", "high"]);
25
+ const DEFAULT_AUTO_HIDE_DURATION_SEC = 600;
26
+ const OVERLAY_DURATION_SEC_MAX = 65535;
25
27
 
26
28
  class Overlay extends OverlayInterface {
27
29
  constructor() {
@@ -31,7 +33,8 @@ class Overlay extends OverlayInterface {
31
33
  this._configuration = {
32
34
  useTransparency: true,
33
35
  overlayCapturePreset: DEFAULT_CAPTURE_PRESET,
34
- overlayCapturePlan: null
36
+ overlayCapturePlan: null,
37
+ autoHideDurationSec: DEFAULT_AUTO_HIDE_DURATION_SEC
35
38
  };
36
39
  this._activeCapturePlan = OVERLAY_CAPTURE_PRESETS[DEFAULT_CAPTURE_PRESET];
37
40
  this._retryGeneration = 0;
@@ -138,6 +141,7 @@ class Overlay extends OverlayInterface {
138
141
  quality,
139
142
  conditional
140
143
  };
144
+ message.overlayDurationSec = this._configuration.autoHideDurationSec;
141
145
  sdkLogger.log(`Overlay: rendering frame x=${x} y=${y} width=${width} height=${height} fcid=${FCID} (batchId=${batchId}, quality=${quality}, conditional=${conditional})`);
142
146
  const request = { target: "UI-Streamer", waitForResponse: false, message: JSON.stringify(message) };
143
147
  window.cefQuery({
@@ -226,6 +230,16 @@ class Overlay extends OverlayInterface {
226
230
  }
227
231
  }
228
232
 
233
+ if (Object.prototype.hasOwnProperty.call(normalizedConfiguration, "autoHideDurationSec")) {
234
+ const duration = normalizedConfiguration.autoHideDurationSec;
235
+ if (Number.isInteger(duration) && duration >= 0 && duration <= OVERLAY_DURATION_SEC_MAX) {
236
+ normalizedConfiguration.autoHideDurationSec = duration;
237
+ } else {
238
+ sdkLogger.warn(`Overlay: invalid autoHideDurationSec "${duration}", keeping previous value`);
239
+ delete normalizedConfiguration.autoHideDurationSec;
240
+ }
241
+ }
242
+
229
243
  this._configuration = { ...this._configuration, ...normalizedConfiguration };
230
244
  this._activeCapturePlan = this._resolveCapturePlan();
231
245
  }
@@ -3,6 +3,7 @@ import { RemotePlayer as RemotePlayerInterface, RemotePlayerError as RemotePlaye
3
3
  import {
4
4
  getFCID,
5
5
  generatePlaybackId,
6
+ getRestResponse,
6
7
  isAudioSyncConfigured,
7
8
  clearTimer,
8
9
  sdkLogger,
@@ -1133,6 +1134,29 @@ class RemotePlayer extends RemotePlayerInterface {
1133
1134
  return this._loadMode;
1134
1135
  }
1135
1136
 
1137
+ /** Get the playback position directly from the connector.
1138
+ * @returns {Promise<number|undefined>} current playback position
1139
+ * @throws {RemotePlayerError} error object contains code & msg
1140
+ */
1141
+ async getPlaybackPosition() {
1142
+ if (!this._isInitialized) {
1143
+ throw new RemotePlayerError(6500, "Cannot call getPlaybackPosition() if remote player is not initialized");
1144
+ }
1145
+ if (this._loadMode !== this.LoadMode.LOADED) {
1146
+ throw new RemotePlayerError(6001, "Cannot call getPlaybackPosition() if player is not loaded");
1147
+ }
1148
+
1149
+ try {
1150
+ const response = await getRestResponse("playback-position");
1151
+ const { currentVideoPosition } = JSON.parse(response || "{}");
1152
+ return currentVideoPosition;
1153
+ } catch (error) {
1154
+ const message = error instanceof Error ? error.message : String(error);
1155
+ sdkLogger.error(`remotePlayer getPlaybackPosition failed: ${message}`);
1156
+ throw new RemotePlayerError(6504, `getPlaybackPosition() failed: ${message}`);
1157
+ }
1158
+ }
1159
+
1136
1160
  /**
1137
1161
  * @typedef {Object} TextTrack
1138
1162
  * @property {string} id - A unique ID for the track.
@@ -143,6 +143,11 @@ export function isAudioSyncConfigured() {
143
143
  export function isSubtitlesTranslationAllowed() {
144
144
  return sessionInfo.sessionInfoObj?.settings?.["ui-streamer"]?.allowSubtitlesTranslation === true;
145
145
  }
146
+
147
+ export function areAlarmsEnabled() {
148
+ return sessionInfo.sessionInfoObj?.settings?.["ui-streamer"]?.disableAlarms !== true;
149
+ }
150
+
146
151
  export function isSubtitlesTranslationPattern(lang) {
147
152
  // This language pattern such as "*:eng" indicates to cloud components to translate subtitles to eng
148
153
  return (lang?.toString() || "").startsWith("*:");
@@ -59,8 +59,8 @@ class Overlay extends EventTarget {
59
59
  }
60
60
 
61
61
  /**
62
- * Removes all registered elements, sends a zero-dimension frame to the UI-Streamer,
63
- * and deactivates the overlay. After calling removeAllElements(), a new element can be registered.
62
+ * Removes all registered elements and deactivates the overlay.
63
+ * After calling removeAllElements(), a new element can be registered.
64
64
  *
65
65
  * @returns {Promise<boolean>} Resolves to true if successful, rejects with error if failed.
66
66
  */
@@ -82,7 +82,7 @@ class Overlay extends EventTarget {
82
82
  *
83
83
  * @param {Object} configuration - The new configuration to apply.
84
84
  * @param {boolean} [configuration.useTransparency=true] - Controls whether the overlay should be rendered with transparency.
85
- * When set to `true`, the value is forwarded to UI-Streamer in `displayOverlay` requests.
85
+ * When set to `true`, the overlay is rendered with transparency.
86
86
  * @param {string} [configuration.overlayCapturePreset="default"] - Named capture plan preset:
87
87
  * `default` (progressive low→high captures) or `once` (one immediate high-quality conditional step).
88
88
  * @param {Array<{quality: "low"|"mid"|"high", conditional: boolean, delay: number}>} [configuration.overlayCapturePlan]
@@ -90,6 +90,9 @@ class Overlay extends EventTarget {
90
90
  * the previous step in the batch. Set `conditional` per step (the SDK does not derive it):
91
91
  * when `true`, capture only if overlay content changed since the last required (non-conditional)
92
92
  * capture in this batch; when `false`, always capture on that step.
93
+ * @param {number} [configuration.autoHideDurationSec=600] - Client auto-hide duration in seconds.
94
+ * Defaults to `600` (10 minutes) until configured. Omit the key to keep the current value.
95
+ * `0` means never auto-hide. Valid range: `0`–`65535`.
93
96
  */
94
97
  configure(configuration) {
95
98
  noop(configuration);
@@ -357,6 +357,14 @@ class RemotePlayer extends EventTarget {
357
357
  return this.LoadMode.NOT_LOADED;
358
358
  }
359
359
 
360
+ /** Get the playback position directly from the connector. Note that this function can load the system. It is recommended to use it when accurate time is needed and currentTime can not be used.
361
+ * @returns {Promise<number|undefined>} current playback position
362
+ * @throws {RemotePlayerError} error object contains code & msg
363
+ */
364
+ async getPlaybackPosition() {
365
+ return 0;
366
+ }
367
+
360
368
 
361
369
  /**
362
370
  * @typedef {Object} TextTrack
@@ -481,7 +489,7 @@ class RemotePlayer extends EventTarget {
481
489
  }
482
490
 
483
491
  /**
484
- * Getter/Setter for currentTime
492
+ * Getter/Setter for currentTime. Current time can be used to get the current playback position in specific use cases like loading from suspend mode or after a key press.
485
493
  */
486
494
  get currentTime() {
487
495
  return 0;
@@ -1 +1 @@
1
- export const version = "4.5.3";
1
+ export const version = "4.5.5";