senza-sdk 4.4.1 → 4.4.2

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.4.1",
3
+ "version": "4.4.2",
4
4
  "main": "./src/api.js",
5
5
  "description": "API for Senza application",
6
6
  "license": "MIT",
@@ -2,6 +2,7 @@ import { AlarmManager as AlarmManagerInterface } from "../interface/alarmManager
2
2
  import { getFCID, sdkLogger } from "./utils.js";
3
3
  import { EventListenersManager } from "./eventListenersManager.js";
4
4
  import { lifecycle } from "./lifecycle.js";
5
+ import { bus, Events } from "./eventBus";
5
6
 
6
7
  class AlarmManager extends AlarmManagerInterface {
7
8
  constructor() {
@@ -38,6 +39,8 @@ class AlarmManager extends AlarmManagerInterface {
38
39
  * @private Add event listeners for system events
39
40
  */
40
41
  _addSenzaEventListeners() {
42
+ bus.addEventListener(Events.LifecycleForeground, () => this._moveToForegroundCalled());
43
+
41
44
  typeof document !== "undefined" && document.addEventListener("hs/alarmFiredEvent", async (e) => {
42
45
 
43
46
  if (e.detail?.alarmName) {
@@ -100,6 +100,12 @@ export async function init(interfaceApiVersion, showSequenceFunc, initSequenceFu
100
100
  alarmManager._setDefaultTimeout(alarmTimeout);
101
101
  }
102
102
 
103
+ // Set default device manager event timeout using UI-Streamer settings
104
+ const deviceManagerEventTimeout = sessionInfoObj?.settings?.["ui-streamer"]?.deviceManagerEventTimeout;
105
+ if (deviceManagerEventTimeout) {
106
+ deviceManager._setDefaultTimeout(deviceManagerEventTimeout);
107
+ }
108
+
103
109
  // Get trigger event
104
110
  const triggerEventStr = await new Promise((resolve) => {
105
111
  const FCID = getFCID();
@@ -133,6 +139,7 @@ export async function init(interfaceApiVersion, showSequenceFunc, initSequenceFu
133
139
  await remotePlayer._init(sessionInfoObj, triggerEvent);
134
140
  alarmManager._init();
135
141
  messageManager._init();
142
+ deviceManager._init();
136
143
  sdkLogger.log("All submodules initialized");
137
144
 
138
145
 
@@ -1,6 +1,9 @@
1
1
  import { DeviceManager as DeviceManagerInterface } from "../interface/deviceManager";
2
2
  import { getFCID, sdkLogger, getRestResponse } from "./utils";
3
3
  import { sessionInfo } from "./SessionInfo";
4
+ import {EventListenersManager} from "./eventListenersManager";
5
+ import {bus, Events} from "./eventBus";
6
+ import {lifecycle} from "./lifecycle";
4
7
 
5
8
  let wifi_ap_data;
6
9
  let wifi_status;
@@ -38,6 +41,125 @@ class DeviceManager extends DeviceManagerInterface {
38
41
 
39
42
  constructor() {
40
43
  super();
44
+
45
+ /**
46
+ * Mapping of CEC active source status to HdmiStatus.
47
+ * @type {Object}
48
+ * @private
49
+ */
50
+ this._cecActiveSourceStatusMap = Object.freeze({
51
+ active: this.HdmiStatus.ACTIVE,
52
+ inactive: this.HdmiStatus.INACTIVE,
53
+ unknown: this.HdmiStatus.UNKNOWN
54
+ });
55
+
56
+ /**
57
+ * Event listeners manager for the deviceManager events
58
+ * @type {EventListenersManager}
59
+ * @private
60
+ */
61
+ this._eventManager = new EventListenersManager({
62
+ timeoutMs: 10000 // Default timeout of 10 seconds, can be overridden by _setDefaultTimeout
63
+ });
64
+
65
+ /**
66
+ * @type {boolean}
67
+ * @private
68
+ */
69
+ this._isInitialized = false;
70
+ }
71
+
72
+ /**
73
+ * @private
74
+ */
75
+ _init() {
76
+ sdkLogger.log("Initializing DeviceManager");
77
+ if (!this._isInitialized) {
78
+ this._isInitialized = true;
79
+ this._addSenzaEventListeners();
80
+ }
81
+ }
82
+
83
+ /**
84
+ * @private Add event listeners for system events
85
+ */
86
+ _addSenzaEventListeners() {
87
+ bus.addEventListener(Events.LifecycleForeground, () => {
88
+ this._moveToForegroundHasBeenCalled = true;
89
+ });
90
+
91
+ typeof document !== "undefined" && document.addEventListener("hs/hdmiStatusChanged", async (event) => {
92
+ sdkLogger.info("Got hs/hdmiStatusChanged event with detail", JSON.stringify(event?.detail));
93
+
94
+ // Translate the HdmiStatus information to a single HdmiStatus for the application
95
+ // 1) cecStatus is a configuration setting from the client. If false, we always return UNKNOWN to the application
96
+ // 2) If cecStatus is true, we check the hdmiStatus. If not "connected", the HDMI status is definitely INACTIVE.
97
+ // 3) If hdmiStatus is "connected" and cecStatus is true, we rely on the cecActiveSourceStatus to determine the HdmiStatus
98
+ let hdmiStatus = this.HdmiStatus.UNKNOWN;
99
+ const status = JSON.parse(event?.detail?.hdmiStatus ?? "{}"); // Object containing the 3 statuses
100
+ if (status?.cecStatus) {
101
+ if (status.hdmiStatus !== "connected") {
102
+ hdmiStatus = this.HdmiStatus.INACTIVE;
103
+ } else {
104
+ const cecActive = this._cecActiveSourceStatusMap[status.cecActiveSourceStatus];
105
+ hdmiStatus = cecActive ?? this.HdmiStatus.UNKNOWN;
106
+ if (!cecActive) {
107
+ sdkLogger.warn(`Unknown CEC active source status: ${status.cecActiveSourceStatus}`);
108
+ }
109
+ }
110
+ } else {
111
+ sdkLogger.warn("cec is disabled or no hdmiStatus");
112
+ }
113
+
114
+ const timeBeforeCallbacks = Date.now();
115
+
116
+ // Dispatch event to application and allow a chance to move to foreground.
117
+ // If there are no callbacks or the application doesn't move to foreground, the UI will be disconnected.
118
+ await this._eventManager.dispatch("hdmistatuschanged", {hdmiStatus});
119
+
120
+ const callbackDuration = Date.now() - timeBeforeCallbacks;
121
+ sdkLogger.log(`All callbacks for hdmiStatusChanged are finished within ${callbackDuration}ms`);
122
+ const isTriggering = lifecycle.triggerEvent.type === "hdmiStatusChanged" && lifecycle._triggerEventFcid && lifecycle._triggerEventFcid === event.detail.fcid;
123
+ if (isTriggering) {
124
+ if (!this._moveToForegroundHasBeenCalled && window.cefQuery) {
125
+ sdkLogger.log("Application is about to be disconnected since didn't move to foreground");
126
+ const message = { type: "disconnect" };
127
+ const request = { target: "TC", waitForResponse: false, message: JSON.stringify(message) };
128
+ window.cefQuery({
129
+ request: JSON.stringify(request),
130
+ persistent: false,
131
+ onSuccess: () => {
132
+ sdkLogger.log("disconnect request successfully sent");
133
+ },
134
+ onFailure: (code, msg) => {
135
+ sdkLogger.error(`disconnect request failed: ${code} ${msg}`);
136
+ }
137
+ });
138
+ }
139
+ }
140
+ });
141
+ }
142
+
143
+ /**
144
+ * Set the default timeout for device manager event listeners
145
+ * @param {number} timeout - Timeout in milliseconds for device manager event listeners
146
+ * @private
147
+ */
148
+ _setDefaultTimeout(timeout) {
149
+ if (typeof timeout === "number" && timeout > 0) {
150
+ this._eventManager.timeoutMs = timeout;
151
+ sdkLogger.log(`DeviceManager event listener timeout set to ${timeout}ms`);
152
+ } else {
153
+ sdkLogger.warn(`Invalid timeout value: ${timeout}. Must be a positive number.`);
154
+ }
155
+ }
156
+
157
+ addEventListener(type, callback) {
158
+ this._eventManager.addEventListener(type, callback);
159
+ }
160
+
161
+ removeEventListener(type, callback) {
162
+ this._eventManager.removeEventListener(type, callback);
41
163
  }
42
164
 
43
165
  get deviceInfo() {
@@ -0,0 +1,5 @@
1
+ class EventBus extends EventTarget {}
2
+ export const bus = new EventBus();
3
+ export const Events = {
4
+ LifecycleForeground: "lifecycle:foreground"
5
+ };
@@ -14,6 +14,7 @@ import {
14
14
  import { EventListenersManager } from "./eventListenersManager.js";
15
15
  import { sessionInfo } from "./SessionInfo.js";
16
16
  import { DEFAULT_REMOTE_PLAYER_CONFIRMATION_TIMEOUT, remotePlayer } from "./remotePlayer.js";
17
+ import {bus, Events} from "./eventBus";
17
18
 
18
19
  // Default values for autoBackground settings. These values are used if the UIStreamer settings are not provided.
19
20
  const DEFAULT_AUTO_BACKGROUND_VIDEO_DELAY = 30;
@@ -136,6 +137,8 @@ class Lifecycle extends LifecycleInterface {
136
137
  this._triggerEvent.data = { eventCode: triggerEvent.eventCode, errorCode: triggerEvent.errorCode };
137
138
  } else if (triggerEvent.type === "getLicense") {
138
139
  sdkLogger.info("The license request is available on the license-request event which is triggered after uiReady is called");
140
+ } else if (triggerEvent.type === "hdmiStatusChanged") {
141
+ sdkLogger.info("The hdmiStatusChanged data is sent in the callback after uiReady is called");
139
142
  }
140
143
  }
141
144
  if (triggerEvent.fcid) {
@@ -461,7 +464,7 @@ class Lifecycle extends LifecycleInterface {
461
464
  return Promise.resolve(false);
462
465
  }
463
466
  this._inTransitionToForeground = true;
464
- alarmManager._moveToForegroundCalled();
467
+ bus.dispatchEvent(new Event(Events.LifecycleForeground));
465
468
  const FCID = getFCID();
466
469
  if (this._remotePlayerApiVersion >= 2) {
467
470
  // Only update to playing UI if we started seeking in ABR. But, if we are seeking while already paused, keep the target seek state as is.
@@ -1,9 +1,33 @@
1
1
  import { sdkLogger, noop } from "./utils.js";
2
2
 
3
3
  /**
4
- * DeviceManager is a singleton class that manages the device
4
+ * @event DeviceManager#hdmistatuschanged
5
+ * @description Fired when the HDMI connection status changes.<br>
6
+ * @property {HdmiStatus} hdmiStatus - the status of the HDMI connection.
7
+ * @example
8
+ * deviceManager.addEventListener("hdmistatuschanged", (e) => {
9
+ * console.info("HDMI status changed:", e.detail.hdmiStatus);
10
+ * });
11
+ * @private
12
+ */
13
+
14
+ /**
15
+ * DeviceManager is a singleton class that manages the device.<br>
16
+ * @fires hdmistatuschanged
5
17
  */
6
18
  export class DeviceManager extends EventTarget {
19
+ /**
20
+ * @typedef {Object} HdmiStatus - The HDMI status of the device
21
+ * @property {string} ACTIVE - The device is connected to the active HDMI source.
22
+ * @property {string} INACTIVE - The active HDMI source is different than the one connected to the device or the TV is in standby.
23
+ * @property {string} UNKNOWN - The status is unknown. This can happen if the TV does not support HDMI status detection.
24
+ */
25
+ HdmiStatus = Object.freeze({
26
+ ACTIVE: "active",
27
+ INACTIVE: "inactive",
28
+ UNKNOWN: "unknown"
29
+ });
30
+
7
31
  /**
8
32
  * @property {object} DeviceInfo
9
33
  * @property {string} DeviceInfo.deviceId
@@ -1 +1 @@
1
- export const version = "4.4.1";
1
+ export const version = "4.4.2";