senza-sdk 4.4.9 → 4.4.11
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/dist/bundle.js +1 -1
- package/dist/implementation.bundle.js +1 -1
- package/package.json +1 -1
- package/src/implementation/lifecycle.js +79 -58
- package/src/implementation/remotePlayer.js +7 -0
- package/src/interface/lifecycle.js +19 -5
- package/src/interface/remotePlayer.js +1 -1
- package/src/interface/version.js +1 -1
package/package.json
CHANGED
|
@@ -17,9 +17,9 @@ import { DEFAULT_REMOTE_PLAYER_CONFIRMATION_TIMEOUT, remotePlayer } from "./remo
|
|
|
17
17
|
import {bus, Events} from "./eventBus";
|
|
18
18
|
|
|
19
19
|
// Default values for autoBackground settings. These values are used if the UIStreamer settings are not provided.
|
|
20
|
-
const DEFAULT_AUTO_BACKGROUND_VIDEO_DELAY = 10*60;
|
|
21
|
-
const DEFAULT_AUTO_BACKGROUND_UI_DELAY = 10*60;
|
|
22
|
-
const DEFAULT_AUTO_BACKGROUND_ENABLED = true;
|
|
20
|
+
export const DEFAULT_AUTO_BACKGROUND_VIDEO_DELAY = 10*60;
|
|
21
|
+
export const DEFAULT_AUTO_BACKGROUND_UI_DELAY = 10*60;
|
|
22
|
+
export const DEFAULT_AUTO_BACKGROUND_ENABLED = true;
|
|
23
23
|
// Default values for autoSuspend settings
|
|
24
24
|
const DEFAULT_AUTO_SUSPEND_ENABLED = false;
|
|
25
25
|
const DEFAULT_AUTO_SUSPEND_PLAYING_DELAY = 60;
|
|
@@ -101,12 +101,6 @@ class Lifecycle extends LifecycleInterface {
|
|
|
101
101
|
*/
|
|
102
102
|
this._backgroundTimestamp = Date.now();
|
|
103
103
|
|
|
104
|
-
/**
|
|
105
|
-
* Flag to track if suspend was triggered by timer
|
|
106
|
-
* @type {boolean}
|
|
107
|
-
* @private
|
|
108
|
-
*/
|
|
109
|
-
this._isSuspendTriggeredByTimer = false;
|
|
110
104
|
|
|
111
105
|
this._isInTransitionToSuspended = false;
|
|
112
106
|
|
|
@@ -266,6 +260,21 @@ class Lifecycle extends LifecycleInterface {
|
|
|
266
260
|
autoSuspend: uiStreamerSettings.autoSuspend
|
|
267
261
|
});
|
|
268
262
|
}
|
|
263
|
+
this._timersInit();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* @private initialize timers based on current configuration
|
|
269
|
+
*/
|
|
270
|
+
_timersInit() {
|
|
271
|
+
// Start background countdown if auto background is enabled and in foreground
|
|
272
|
+
if (this._isAutoBackgroundEnabled() && this._isForegroundOrTransitioning()) {
|
|
273
|
+
this._startCountdown();
|
|
274
|
+
}
|
|
275
|
+
// start suspend countdown if auto suspend is enabled and in background
|
|
276
|
+
if (this._isAutoSuspendEnabled() && this._state === this.UiState.BACKGROUND) {
|
|
277
|
+
this._startSuspendCountdown();
|
|
269
278
|
}
|
|
270
279
|
}
|
|
271
280
|
|
|
@@ -321,7 +330,7 @@ class Lifecycle extends LifecycleInterface {
|
|
|
321
330
|
if (this._isBackgroundTriggeredByTimer && (this.state === this.UiState.BACKGROUND ||
|
|
322
331
|
this.state === this.UiState.IN_TRANSITION_TO_BACKGROUND)) {
|
|
323
332
|
sdkLogger.log("Moving to foreground due to user interaction after auto background");
|
|
324
|
-
this.moveToForeground();
|
|
333
|
+
this.moveToForeground(true);
|
|
325
334
|
} else {
|
|
326
335
|
this._startCountdown();
|
|
327
336
|
}
|
|
@@ -602,25 +611,9 @@ class Lifecycle extends LifecycleInterface {
|
|
|
602
611
|
// Only start countdown if delay is positive
|
|
603
612
|
if (timeoutDelay > 0) {
|
|
604
613
|
sdkLogger.debug("Starting countdown timeout", timeoutDelay, isPlaying ? "(video)" : "(UI)");
|
|
605
|
-
this._countdown = setTimeout(
|
|
606
|
-
sdkLogger.
|
|
607
|
-
|
|
608
|
-
// Create the event with cancelable: true
|
|
609
|
-
const event = new Event("beforestatechange", { cancelable: true });
|
|
610
|
-
event.state = this.UiState.BACKGROUND;
|
|
611
|
-
// Use the event manager to dispatch the event and wait for all listeners
|
|
612
|
-
await this._eventManager.dispatch("beforestatechange", event);
|
|
613
|
-
// Check if any listener called preventDefault()
|
|
614
|
-
if (event.defaultPrevented) {
|
|
615
|
-
sdkLogger.info("moveToBackground was prevented by a listener");
|
|
616
|
-
// Restart the countdown since the move was cancelled
|
|
617
|
-
if (this._isForegroundOrTransitioning()) {
|
|
618
|
-
this._startCountdown();
|
|
619
|
-
}
|
|
620
|
-
} else {
|
|
621
|
-
this.moveToBackground(true);
|
|
622
|
-
}
|
|
623
|
-
|
|
614
|
+
this._countdown = setTimeout(() => {
|
|
615
|
+
sdkLogger.info("Countdown timeout reached, moving to background");
|
|
616
|
+
this.moveToBackground(true);
|
|
624
617
|
}, timeoutDelay * 1000);
|
|
625
618
|
} else {
|
|
626
619
|
sdkLogger.debug("Countdown not started - delay is negative or zero");
|
|
@@ -657,30 +650,14 @@ class Lifecycle extends LifecycleInterface {
|
|
|
657
650
|
this._suspendCountdown = setTimeout(async () => {
|
|
658
651
|
sdkLogger.debug("Suspend countdown timeout reached, moving to suspended");
|
|
659
652
|
if (this._state === this.UiState.BACKGROUND) {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
await this._eventManager.dispatch("beforestatechange", event);
|
|
665
|
-
// Check if any listener called preventDefault()
|
|
666
|
-
if (event.defaultPrevented) {
|
|
667
|
-
sdkLogger.info("moveToSuspended was prevented by a listener");
|
|
668
|
-
// Restart the suspend countdown since the move was cancelled
|
|
669
|
-
this._startSuspendCountdown();
|
|
670
|
-
} else {
|
|
671
|
-
try {
|
|
672
|
-
// Set flag to indicate suspend was triggered by timer
|
|
673
|
-
this._isSuspendTriggeredByTimer = true;
|
|
674
|
-
await this.moveToSuspended();
|
|
675
|
-
} catch (error) {
|
|
676
|
-
sdkLogger.error("Failed to move to suspended:", error);
|
|
677
|
-
}
|
|
653
|
+
try {
|
|
654
|
+
await this.moveToSuspended(true);
|
|
655
|
+
} catch (error) {
|
|
656
|
+
sdkLogger.error("Failed to move to suspended:", error);
|
|
678
657
|
}
|
|
679
|
-
|
|
680
658
|
} else {
|
|
681
659
|
sdkLogger.warn("suspend timer was called while not in background");
|
|
682
660
|
}
|
|
683
|
-
|
|
684
661
|
}, timeoutDelay * 1000);
|
|
685
662
|
} else {
|
|
686
663
|
sdkLogger.debug("Suspend countdown not started - delay is zero or negative");
|
|
@@ -695,8 +672,6 @@ class Lifecycle extends LifecycleInterface {
|
|
|
695
672
|
sdkLogger.debug("Stopping suspend countdown timer");
|
|
696
673
|
clearTimeout(this._suspendCountdown);
|
|
697
674
|
this._suspendCountdown = null;
|
|
698
|
-
// Reset the timer flag when stopping countdown
|
|
699
|
-
this._isSuspendTriggeredByTimer = false;
|
|
700
675
|
}
|
|
701
676
|
}
|
|
702
677
|
|
|
@@ -727,7 +702,7 @@ class Lifecycle extends LifecycleInterface {
|
|
|
727
702
|
sdkLogger.warn("lifecycle getState is not supported if NOT running e2e");
|
|
728
703
|
}
|
|
729
704
|
|
|
730
|
-
moveToForeground() {
|
|
705
|
+
async moveToForeground(isSystemTriggered = false) {
|
|
731
706
|
if (!_isUiReady()) {
|
|
732
707
|
sdkLogger.warn("lifecycle moveToForeground: UI is not ready yet. Make sure to call senza.uiReady() before calling lifecycle.moveToForeground()");
|
|
733
708
|
}
|
|
@@ -747,6 +722,19 @@ class Lifecycle extends LifecycleInterface {
|
|
|
747
722
|
sdkLogger.warn(`lifecycle moveToForeground: No need to transition to foreground, state: ${this._state} transition: ${inTransition}`);
|
|
748
723
|
return Promise.resolve(false);
|
|
749
724
|
}
|
|
725
|
+
|
|
726
|
+
// Fire beforestatechange event
|
|
727
|
+
const event = new Event("beforestatechange", { cancelable: true });
|
|
728
|
+
event.state = this.UiState.FOREGROUND;
|
|
729
|
+
event.isSystemTriggered = isSystemTriggered;
|
|
730
|
+
await this._eventManager.dispatch("beforestatechange", event);
|
|
731
|
+
|
|
732
|
+
// Check if any listener called preventDefault()
|
|
733
|
+
if (event.defaultPrevented) {
|
|
734
|
+
sdkLogger.info("moveToForeground was prevented by a listener");
|
|
735
|
+
return Promise.resolve(false);
|
|
736
|
+
}
|
|
737
|
+
|
|
750
738
|
this._inTransitionToForeground = true;
|
|
751
739
|
bus.dispatchEvent(new Event(Events.LifecycleForeground));
|
|
752
740
|
const FCID = getFCID();
|
|
@@ -918,13 +906,13 @@ class Lifecycle extends LifecycleInterface {
|
|
|
918
906
|
return Promise.resolve(false);
|
|
919
907
|
}
|
|
920
908
|
|
|
921
|
-
moveToBackground(
|
|
909
|
+
async moveToBackground(isSystemTriggered = false) {
|
|
922
910
|
if (this._isInTransitionToSuspended) {
|
|
923
911
|
sdkLogger.error("lifecycle moveToBackground: Currently in transition to suspend, cannot move to background");
|
|
924
912
|
return Promise.resolve(false);
|
|
925
913
|
}
|
|
926
914
|
// If the background transition is triggered by the auto background timer, set the flag
|
|
927
|
-
this._isBackgroundTriggeredByTimer =
|
|
915
|
+
this._isBackgroundTriggeredByTimer = isSystemTriggered;
|
|
928
916
|
|
|
929
917
|
if (window.cefQuery) {
|
|
930
918
|
const inTransition = this._isInTransition();
|
|
@@ -932,6 +920,24 @@ class Lifecycle extends LifecycleInterface {
|
|
|
932
920
|
sdkLogger.warn(`lifecycle moveToBackground: No need to transition to background, state: ${this._state} transition: ${inTransition}`);
|
|
933
921
|
return Promise.resolve(false);
|
|
934
922
|
}
|
|
923
|
+
|
|
924
|
+
// Fire beforestatechange event
|
|
925
|
+
const event = new Event("beforestatechange", { cancelable: true });
|
|
926
|
+
event.state = this.UiState.BACKGROUND;
|
|
927
|
+
event.isSystemTriggered = isSystemTriggered;
|
|
928
|
+
await this._eventManager.dispatch("beforestatechange", event);
|
|
929
|
+
|
|
930
|
+
// Check if any listener called preventDefault()
|
|
931
|
+
if (event.defaultPrevented) {
|
|
932
|
+
sdkLogger.info("moveToBackground was prevented by a listener");
|
|
933
|
+
// Clear the timer flag if the move was prevented
|
|
934
|
+
this._isBackgroundTriggeredByTimer = false;
|
|
935
|
+
// Restart the countdown if it was triggered by timer
|
|
936
|
+
if (isSystemTriggered && this._isForegroundOrTransitioning()) {
|
|
937
|
+
this._startCountdown();
|
|
938
|
+
}
|
|
939
|
+
return Promise.resolve(false);
|
|
940
|
+
}
|
|
935
941
|
if (remotePlayer._isSeekingByApplication) {
|
|
936
942
|
remotePlayer._targetSeekPlayingState = TargetPlayingState.PLAYING_ABR;
|
|
937
943
|
return Promise.resolve(true);
|
|
@@ -1076,7 +1082,7 @@ class Lifecycle extends LifecycleInterface {
|
|
|
1076
1082
|
return Promise.reject("disconnect is not supported if NOT running e2e");
|
|
1077
1083
|
}
|
|
1078
1084
|
|
|
1079
|
-
moveToSuspended() {
|
|
1085
|
+
async moveToSuspended(isSystemTriggered = false) {
|
|
1080
1086
|
// Check if the current state is BACKGROUND
|
|
1081
1087
|
if (this._state !== this.UiState.BACKGROUND) {
|
|
1082
1088
|
const errorMsg = `moveToSuspended can only be called from BACKGROUND state. Current state: ${this._state}`;
|
|
@@ -1084,20 +1090,35 @@ class Lifecycle extends LifecycleInterface {
|
|
|
1084
1090
|
return Promise.reject(errorMsg);
|
|
1085
1091
|
}
|
|
1086
1092
|
|
|
1093
|
+
// Fire beforestatechange event
|
|
1094
|
+
const event = new Event("beforestatechange", { cancelable: true });
|
|
1095
|
+
event.state = this.UiState.SUSPENDED;
|
|
1096
|
+
event.isSystemTriggered = isSystemTriggered;
|
|
1097
|
+
await this._eventManager.dispatch("beforestatechange", event);
|
|
1098
|
+
|
|
1099
|
+
// Check if any listener called preventDefault()
|
|
1100
|
+
if (event.defaultPrevented) {
|
|
1101
|
+
sdkLogger.info("moveToSuspended was prevented by a listener");
|
|
1102
|
+
// Restart the suspend countdown if it was triggered by timer
|
|
1103
|
+
if (isSystemTriggered && this._isAutoSuspendEnabled()) {
|
|
1104
|
+
this._startSuspendCountdown();
|
|
1105
|
+
}
|
|
1106
|
+
return Promise.resolve(false);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1087
1109
|
this._isInTransitionToSuspended = true;
|
|
1088
1110
|
// Report metrics for time between background and suspend
|
|
1089
1111
|
const duration = (Date.now() - this._backgroundTimestamp) / 1000;
|
|
1090
1112
|
|
|
1091
1113
|
sdkLogger.metrics({
|
|
1092
1114
|
type: "suspendTransitions",
|
|
1093
|
-
isAutoSuspend:
|
|
1115
|
+
isAutoSuspend: isSystemTriggered,
|
|
1094
1116
|
isPlaying: remotePlayer._isPlaying,
|
|
1095
1117
|
duration
|
|
1096
1118
|
});
|
|
1097
1119
|
|
|
1098
1120
|
// Reset the timer flag after reporting metrics
|
|
1099
|
-
const reason =
|
|
1100
|
-
this._isSuspendTriggeredByTimer = false;
|
|
1121
|
+
const reason = isSystemTriggered ? "timer" : "appInitiated";
|
|
1101
1122
|
|
|
1102
1123
|
if (window.cefQuery) {
|
|
1103
1124
|
return new Promise((resolve, reject) => {
|
|
@@ -254,6 +254,13 @@ class RemotePlayer extends RemotePlayerInterface {
|
|
|
254
254
|
typeof document !== "undefined" && document.addEventListener("hs/ui_inactive", () => {
|
|
255
255
|
/* istanbul ignore next */
|
|
256
256
|
sdkLogger.info("Got hs/ui_inactive event");
|
|
257
|
+
|
|
258
|
+
// this logic is specific for customers that use autoTune. When a playback session is auto tuned, we do not need the guard time before releasing the UI
|
|
259
|
+
// calling moveToSuspended right away, will release the UI faster.
|
|
260
|
+
if (this._isPlaying && this._autoTune) {
|
|
261
|
+
sdkLogger.info("Moving to suspended state, in autoTune playback, due to ui_inactive event");
|
|
262
|
+
lifecycle.moveToSuspended();
|
|
263
|
+
}
|
|
257
264
|
});
|
|
258
265
|
typeof document !== "undefined" && document.addEventListener("hs/senzaPlayerSetRate", (event) => {
|
|
259
266
|
if (!this._videoElement) return;
|
|
@@ -16,18 +16,32 @@ import {
|
|
|
16
16
|
/**
|
|
17
17
|
* @event Lifecycle#beforestatechange
|
|
18
18
|
* @description Fired before transitioning to a new state. This event is cancelable.<br>
|
|
19
|
-
*
|
|
19
|
+
* Fired when transitioning to FOREGROUND, BACKGROUND, or SUSPENDED state.<br>
|
|
20
20
|
* The actual state transition will occur after all event listeners have completed processing.
|
|
21
|
-
* Can be used to prevent automatic transitions
|
|
22
|
-
*
|
|
21
|
+
* Can be used to prevent automatic transitions (e.g., from autoBackground or autoSuspend features) or
|
|
22
|
+
* to perform cleanup operations before state changes.
|
|
23
|
+
* @property {UiState} state - Indicates the target state the lifecycle is trying to transition to (FOREGROUND, BACKGROUND, or SUSPENDED).
|
|
24
|
+
* @property {boolean} isSystemTriggered - Indicates whether the transition was triggered by the system (e.g., auto background timer, auto suspend timer) or by the application.
|
|
23
25
|
* @property {boolean} cancelable - true, indicating the event can be cancelled using preventDefault()
|
|
24
26
|
* @example
|
|
27
|
+
* // Prevent automatic background transition when user is actively interacting
|
|
25
28
|
* lifecycle.addEventListener("beforestatechange", (e) => {
|
|
26
|
-
* if (e.state === lifecycle.UiState.BACKGROUND && userIsInteracting) {
|
|
27
|
-
*
|
|
29
|
+
* if (e.state === lifecycle.UiState.BACKGROUND && e.isSystemTriggered && userIsInteracting) {
|
|
30
|
+
* console.log("Preventing automatic background transition");
|
|
28
31
|
* e.preventDefault();
|
|
29
32
|
* }
|
|
30
33
|
* });
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* // Save application state before moving to suspended
|
|
37
|
+
* lifecycle.addEventListener("beforestatechange", async (e) => {
|
|
38
|
+
* if (e.state === lifecycle.UiState.SUSPENDED) {
|
|
39
|
+
* console.log("Saving application state before suspend");
|
|
40
|
+
* await saveApplicationState();
|
|
41
|
+
* }
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
|
|
31
45
|
*/
|
|
32
46
|
|
|
33
47
|
/**
|
|
@@ -110,7 +110,7 @@ export class RemotePlayerError extends Error {
|
|
|
110
110
|
* | 3403 | Player | Problem accessing segments, server authentication issue |
|
|
111
111
|
* | 3404 | Player | Problem accessing segments, server returned not found |
|
|
112
112
|
* | 3900-3999 | Player | Internal player error |
|
|
113
|
-
* | 6000 | Player | The remote player api call has reached
|
|
113
|
+
* | 6000 | Player | The remote player api call has reached a timeout with no response from the remote player |
|
|
114
114
|
* | 6001 | Player | play() was called while the remote player is not loaded |
|
|
115
115
|
* | 6002 | Player | load() was called while the application was in state 'background' or 'inTransitionToBackground' |
|
|
116
116
|
* | 6500 | Player | remotePlayer api was called before initializing remotePlayer |
|
package/src/interface/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "4.4.
|
|
1
|
+
export const version = "4.4.11";
|