senza-sdk 4.2.65-90c49ac.0 → 4.3.1-4a01fcf.0
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/package.json +17 -8
- package/src/api.js +248 -329
- package/src/{alarmManager.js → implementation/alarmManager.js} +15 -52
- package/src/implementation/api.js +367 -0
- package/src/{deviceManager.js → implementation/deviceManager.js} +6 -78
- package/src/{lifecycle.js → implementation/lifecycle.js} +28 -215
- package/src/{messageManager.js → implementation/messageManager.js} +6 -6
- package/src/{platformManager.js → implementation/platformManager.js} +5 -4
- package/src/{remotePlayer.js → implementation/remotePlayer.js} +33 -27
- package/src/{senzaShakaPlayer.js → implementation/senzaShakaPlayer.js} +91 -16
- package/src/{utils.js → implementation/utils.js} +15 -6
- package/src/interface/alarmManager.js +69 -0
- package/src/interface/api.js +8 -0
- package/src/{devSequence.js → interface/devSequence.js} +35 -0
- package/src/interface/deviceManager.js +133 -0
- package/src/interface/lifecycle.js +278 -0
- package/src/interface/messageManager.js +46 -0
- package/src/interface/platformManager.js +35 -0
- package/src/interface/remotePlayer.js +441 -0
- package/src/interface/senzaShakaPlayer.js +171 -0
- package/src/interface/utils.js +45 -0
- /package/src/{SessionInfo.js → implementation/SessionInfo.js} +0 -0
- /package/src/{devHelper.js → implementation/devHelper.js} +0 -0
- /package/src/{eventListenersManager.js → implementation/eventListenersManager.js} +0 -0
- /package/src/{subtitlesUtils.js → implementation/subtitlesUtils.js} +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RemotePlayer as RemotePlayerInterface } from "../interface/remotePlayer";
|
|
1
2
|
import {
|
|
2
3
|
getFCID,
|
|
3
4
|
isAudioSyncConfigured,
|
|
@@ -68,6 +69,7 @@ function setPlaybackInfo(playbackInfo) {
|
|
|
68
69
|
* @typedef {Object} Config
|
|
69
70
|
* @property {string} preferredAudioLanguage
|
|
70
71
|
* @property {string} preferredSubtitlesLanguage
|
|
72
|
+
* @property {number} minSuggestedPresentationDelay - minimal delay allowed for live playback in seconds
|
|
71
73
|
* @property {boolean} autoPlay - (Not implemented yet) upon loading start playing automatically
|
|
72
74
|
*/
|
|
73
75
|
|
|
@@ -78,11 +80,11 @@ function setPlaybackInfo(playbackInfo) {
|
|
|
78
80
|
* @fires ended
|
|
79
81
|
* @fires error
|
|
80
82
|
* @fires onloadmodechange
|
|
83
|
+
* @fires playing
|
|
81
84
|
* @fires seeking (Not implemented yet)
|
|
82
85
|
* @fires seeked (Not implemented yet)
|
|
83
|
-
* @fires loadedmetadata (Not implemented yet)
|
|
84
86
|
*/
|
|
85
|
-
class RemotePlayer extends
|
|
87
|
+
class RemotePlayer extends RemotePlayerInterface {
|
|
86
88
|
constructor() {
|
|
87
89
|
super();
|
|
88
90
|
/**
|
|
@@ -91,7 +93,8 @@ class RemotePlayer extends EventTarget {
|
|
|
91
93
|
*/
|
|
92
94
|
this._config = {
|
|
93
95
|
preferredAudioLanguage: "",
|
|
94
|
-
preferredSubtitlesLanguage: ""
|
|
96
|
+
preferredSubtitlesLanguage: "",
|
|
97
|
+
minSuggestedPresentationDelay: 0
|
|
95
98
|
};
|
|
96
99
|
/**
|
|
97
100
|
* @type {string}
|
|
@@ -524,10 +527,10 @@ class RemotePlayer extends EventTarget {
|
|
|
524
527
|
|
|
525
528
|
/** setting values for properties in the player configuration using an object.
|
|
526
529
|
* If the config does not support a property this is a no-op.
|
|
527
|
-
* @param {
|
|
530
|
+
* @param {Config} props the object with all the different properties to change.
|
|
528
531
|
* @example
|
|
529
532
|
* remotePlayer.configure({ preferredAudioLanguage: 'en-US' })
|
|
530
|
-
*
|
|
533
|
+
* remotePlayer.configure({ minSuggestedPresentationDelay: 6 })
|
|
531
534
|
* */
|
|
532
535
|
configure(props) {
|
|
533
536
|
Object.entries(props).forEach(([key, value]) => {
|
|
@@ -896,6 +899,9 @@ class RemotePlayer extends EventTarget {
|
|
|
896
899
|
this._updateSeekListeners(video);
|
|
897
900
|
}
|
|
898
901
|
this._videoElement = video;
|
|
902
|
+
|
|
903
|
+
// Emit a custom event to notify about the attachment of the video element
|
|
904
|
+
this.dispatchEvent(new Event("videoelementattached"));
|
|
899
905
|
}
|
|
900
906
|
}
|
|
901
907
|
|
|
@@ -911,7 +917,7 @@ class RemotePlayer extends EventTarget {
|
|
|
911
917
|
/** Tell the remote player to load the given URL.
|
|
912
918
|
* @param {string} url url to load
|
|
913
919
|
* @param {number} [position] start position in seconds (if not provided, start from beginning (VOD) or current time (LTV))
|
|
914
|
-
|
|
920
|
+
* @returns {Promise}
|
|
915
921
|
* @throws {RemotePlayerError} error object contains code & msg
|
|
916
922
|
*
|
|
917
923
|
* */
|
|
@@ -976,6 +982,11 @@ class RemotePlayer extends EventTarget {
|
|
|
976
982
|
message.action = "load";
|
|
977
983
|
message.audioLanguage = audioLanguage;
|
|
978
984
|
message.subtitlesLanguage = subtitlesLanguage;
|
|
985
|
+
if (this.getConfiguration().minSuggestedPresentationDelay > 0) {
|
|
986
|
+
message.cloudPlayerParams = {
|
|
987
|
+
"mspd": this.getConfiguration().minSuggestedPresentationDelay
|
|
988
|
+
};
|
|
989
|
+
}
|
|
979
990
|
} else {
|
|
980
991
|
message.type = "setPlayableUri";
|
|
981
992
|
}
|
|
@@ -1133,13 +1144,8 @@ class RemotePlayer extends EventTarget {
|
|
|
1133
1144
|
|
|
1134
1145
|
// If seeking in progress, wait for seek to complete before playing
|
|
1135
1146
|
if (this._isSeekingByApplication) {
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
this._targetSeekPlayingState = TargetPlayingState.PLAYING_UI;
|
|
1139
|
-
} else {
|
|
1140
|
-
sdkLogger.info("application requesting play during seek. setting targetSeekPlayingState to PLAYING_ABR");
|
|
1141
|
-
this._targetSeekPlayingState = TargetPlayingState.PLAYING_ABR;
|
|
1142
|
-
}
|
|
1147
|
+
sdkLogger.info("application requesting play during seek");
|
|
1148
|
+
this._targetSeekPlayingState = TargetPlayingState.PLAYING_UI;
|
|
1143
1149
|
return Promise.resolve(true);
|
|
1144
1150
|
}
|
|
1145
1151
|
/*
|
|
@@ -1661,7 +1667,9 @@ class RemotePlayer extends EventTarget {
|
|
|
1661
1667
|
}
|
|
1662
1668
|
}
|
|
1663
1669
|
|
|
1664
|
-
|
|
1670
|
+
// Only allow seeking in foreground. Still ignore the initialized local player seeking event above
|
|
1671
|
+
if (this._remotePlayerApiVersion >= 2 && !this._isSeekingByPlatform && !this._isSeekingByApplication &&
|
|
1672
|
+
(lifecycle.state === lifecycle.UiState.FOREGROUND || lifecycle.state === lifecycle.UiState.IN_TRANSITION_TO_FOREGROUND)) {
|
|
1665
1673
|
this._atomicSeek();
|
|
1666
1674
|
} else {
|
|
1667
1675
|
sdkLogger.info(`Seeking: skipping seeking event to currentTime: ${playbackPosition}, internalSeek: ${this._isSeekingByPlatform}, localPlayerSeek: ${this._isSeekingByApplication}, state: ${lifecycle.state}`);
|
|
@@ -1680,16 +1688,16 @@ class RemotePlayer extends EventTarget {
|
|
|
1680
1688
|
* */
|
|
1681
1689
|
async _atomicSeek() {
|
|
1682
1690
|
sdkLogger.info("Seeking: local video element seeking start while isPlaying: ", this._isPlaying);
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1691
|
+
|
|
1692
|
+
// Initialize the target playing state unless changed during the seek process
|
|
1693
|
+
// In the future, we should allow for seeking in background. Currently, there's no
|
|
1694
|
+
// way to know when the web application will call moveToForeground (i.e Before/After seek)
|
|
1695
|
+
// Therefore, for now, we will assume the target is either paused or playing in ui unless
|
|
1696
|
+
// specifically receiving a moveToBackground during the process.
|
|
1697
|
+
// if (this._isPlaying && (lifecycle.state === lifecycle.UiState.BACKGROUND || lifecycle.state === lifecycle.UiState.IN_TRANSITION_TO_BACKGROUND)) {
|
|
1698
|
+
// this._targetSeekPlayingState = TargetPlayingState.PLAYING_ABR;
|
|
1699
|
+
// }
|
|
1700
|
+
this._targetSeekPlayingState = this._isPlaying ? TargetPlayingState.PLAYING_UI : TargetPlayingState.PAUSED;
|
|
1693
1701
|
|
|
1694
1702
|
// The platform could be currently syncing audio/video using playback rate. Reset when performing seek.
|
|
1695
1703
|
if (this._videoElement) {
|
|
@@ -1756,7 +1764,7 @@ class RemotePlayer extends EventTarget {
|
|
|
1756
1764
|
|
|
1757
1765
|
// If in TargetPlayingState.PAUSE, no need to resume.
|
|
1758
1766
|
// Resume without awaiting to avoid blocking the seek process anymore
|
|
1759
|
-
// In case where we aborted
|
|
1767
|
+
// In case where we aborted, we don't want to resume playback.
|
|
1760
1768
|
if (!this._abortSeeking) {
|
|
1761
1769
|
if (this._targetSeekPlayingState === TargetPlayingState.PLAYING_UI) {
|
|
1762
1770
|
if (!this._isAudioSyncEnabled()) {
|
|
@@ -1765,8 +1773,6 @@ class RemotePlayer extends EventTarget {
|
|
|
1765
1773
|
// resume audio play only if _isAudioSyncEnabled
|
|
1766
1774
|
this._play(StreamType.AUDIO);
|
|
1767
1775
|
} else if (this._targetSeekPlayingState === TargetPlayingState.PLAYING_ABR) {
|
|
1768
|
-
// When moving back to background, we need to put the remote player back into play mode
|
|
1769
|
-
this._changePlayMode(true);
|
|
1770
1776
|
lifecycle._moveToBackground();
|
|
1771
1777
|
}
|
|
1772
1778
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { shaka } from "../interface/senzaShakaPlayer";
|
|
2
|
+
|
|
2
3
|
import { remotePlayer, lifecycle, getPlatformInfo } from "./api";
|
|
3
4
|
import { sdkLogger, iso6393to1 } from "./utils";
|
|
5
|
+
import moment from "moment";
|
|
6
|
+
|
|
4
7
|
|
|
5
8
|
// Define custom error category
|
|
6
9
|
shaka.util.Error.Category.SENZA_PLAYER_ERROR = 50;
|
|
@@ -30,11 +33,6 @@ class SenzaError extends shaka.util.Error {
|
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
|
|
33
|
-
// Copy the shaka module and replace the Player class with SenzaShakaPlayer
|
|
34
|
-
// if we don't Copy the shaka module, the Player class will be replaced for all the other modules that import shaka
|
|
35
|
-
const senzaShaka = { ...shaka };
|
|
36
|
-
|
|
37
|
-
|
|
38
36
|
/**
|
|
39
37
|
* SenzaShakaPlayer subclass of Shaka that handles both local and remote playback.
|
|
40
38
|
*
|
|
@@ -76,7 +74,7 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
76
74
|
* @private
|
|
77
75
|
* @type {number}
|
|
78
76
|
* @description Timeout in milliseconds to wait for playing event
|
|
79
|
-
* @default
|
|
77
|
+
* @default 4000
|
|
80
78
|
*/
|
|
81
79
|
_playingTimeout = 4000;
|
|
82
80
|
|
|
@@ -185,7 +183,7 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
185
183
|
originatesFromRemotePlayer: true
|
|
186
184
|
};
|
|
187
185
|
|
|
188
|
-
const response = await this.getNetworkingEngine().request(
|
|
186
|
+
const response = await this.getNetworkingEngine().request(shaka.net.NetworkingEngine.RequestType.LICENSE, request).promise;
|
|
189
187
|
|
|
190
188
|
let responseBody = response.data;
|
|
191
189
|
if (response.status < 200 || response.status >= 300) {
|
|
@@ -305,6 +303,45 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
305
303
|
|
|
306
304
|
}
|
|
307
305
|
|
|
306
|
+
/**
|
|
307
|
+
* @private
|
|
308
|
+
* @type {number}
|
|
309
|
+
* @description Minimum suggested presentation delay in seconds
|
|
310
|
+
* @default 15
|
|
311
|
+
*/
|
|
312
|
+
_minSuggestedPresentationDelay = 15;
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Modifies the suggestedPresentationDelay in the manifest text
|
|
316
|
+
* @private
|
|
317
|
+
* @param {string} manifestText - The MPD manifest text
|
|
318
|
+
* @returns {string} - Modified manifest text , or undefined if no modification was done
|
|
319
|
+
*/
|
|
320
|
+
_updateManifestDelayIfBelowMinimum(manifestText) {
|
|
321
|
+
// Look for suggestedPresentationDelay attribute
|
|
322
|
+
const match = manifestText.match(/suggestedPresentationDelay="([^"]+)"/);
|
|
323
|
+
if (match) {
|
|
324
|
+
const durationString = match[1];
|
|
325
|
+
const duration = moment.duration(durationString);
|
|
326
|
+
const currentDelay = duration.asSeconds();
|
|
327
|
+
|
|
328
|
+
sdkLogger.info(`Found suggestedPresentationDelay in manifest: ${currentDelay.toFixed(3)}s`);
|
|
329
|
+
|
|
330
|
+
if (currentDelay < this._minSuggestedPresentationDelay) {
|
|
331
|
+
// Replace the value in the manifest text with 3 decimal places
|
|
332
|
+
manifestText = manifestText.replace(
|
|
333
|
+
/suggestedPresentationDelay="[^"]+"/,
|
|
334
|
+
`suggestedPresentationDelay="PT${this._minSuggestedPresentationDelay.toFixed(3)}S"`
|
|
335
|
+
);
|
|
336
|
+
sdkLogger.info(`Updated manifest suggestedPresentationDelay to ${this._minSuggestedPresentationDelay.toFixed(3)}s`);
|
|
337
|
+
return manifestText;
|
|
338
|
+
}
|
|
339
|
+
} else {
|
|
340
|
+
sdkLogger.info("suggestedPresentationDelay is not defined at the manifest");
|
|
341
|
+
}
|
|
342
|
+
return undefined;
|
|
343
|
+
}
|
|
344
|
+
|
|
308
345
|
/**
|
|
309
346
|
* Creates an instance of SenzaShakaPlayer, which is a subclass of shaka.Player.
|
|
310
347
|
*
|
|
@@ -332,14 +369,38 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
332
369
|
const playTimeout = getPlatformInfo()?.sessionInfo?.settings?.["ui-streamer"]?.playingEventTimeout;
|
|
333
370
|
this._playingTimeout = (playTimeout >= 0) ? playTimeout*1000 : this._playingTimeout;
|
|
334
371
|
|
|
372
|
+
// Initialize minSuggestedPresentationDelay from UI settings or use default
|
|
373
|
+
const uiSettings = getPlatformInfo()?.sessionInfo?.settings?.["ui-streamer"];
|
|
374
|
+
if (uiSettings?.minSuggestedPresentationDelay !== undefined) {
|
|
375
|
+
this._minSuggestedPresentationDelay = uiSettings.minSuggestedPresentationDelay;
|
|
376
|
+
sdkLogger.info(`Using configured minSuggestedPresentationDelay: ${this._minSuggestedPresentationDelay}s`);
|
|
377
|
+
}
|
|
378
|
+
|
|
335
379
|
// if video element is provided, add the listeres here. In this case ,there is no need to call attach.
|
|
336
380
|
if (videoElement) {
|
|
337
381
|
this._attach(videoElement);
|
|
338
382
|
sdkLogger.warn("SenzaShakaPlayer constructor Adding videoElement in the constructor is going to be deprecated in the future. Please use attach method instead.");
|
|
339
383
|
}
|
|
340
384
|
|
|
385
|
+
this.configure({
|
|
386
|
+
manifest: {
|
|
387
|
+
defaultPresentationDelay: this._minSuggestedPresentationDelay // in seconds
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
remotePlayer.configure({
|
|
392
|
+
minSuggestedPresentationDelay: this._minSuggestedPresentationDelay
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
this.addEventListener("buffering", () => {
|
|
396
|
+
if (this.videoElement) {
|
|
397
|
+
sdkLogger.info("Buffering at time:", this.videoElement.currentTime);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
|
|
341
401
|
}
|
|
342
402
|
|
|
403
|
+
|
|
343
404
|
_attach(videoElement) {
|
|
344
405
|
this.videoElement = videoElement;
|
|
345
406
|
|
|
@@ -618,16 +679,30 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
618
679
|
|
|
619
680
|
// This callbakc will be activated when the manifest is loaded. It will trigger load of the remote player.
|
|
620
681
|
// This will ensure that the remote player is loaded only after the manifest is loaded by local player.
|
|
621
|
-
const responseFilterCallback = async (type) => {
|
|
622
|
-
if (type === shaka.net.NetworkingEngine.RequestType.MANIFEST
|
|
623
|
-
manifestLoadHandled = true;
|
|
682
|
+
const responseFilterCallback = async (type, response) => {
|
|
683
|
+
if (type === shaka.net.NetworkingEngine.RequestType.MANIFEST) {
|
|
624
684
|
try {
|
|
625
|
-
|
|
626
|
-
|
|
685
|
+
if (response.data && this._minSuggestedPresentationDelay > 0) {
|
|
686
|
+
const manifestText = new TextDecoder().decode(response.data);
|
|
687
|
+
const modifiedText = this._updateManifestDelayIfBelowMinimum(manifestText);
|
|
688
|
+
if (modifiedText) {
|
|
689
|
+
const responseData = new TextEncoder().encode(modifiedText).buffer;
|
|
690
|
+
response.data = responseData;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
627
693
|
} catch (error) {
|
|
628
|
-
|
|
694
|
+
sdkLogger.error("Error processing manifest:", error);
|
|
629
695
|
}
|
|
630
696
|
|
|
697
|
+
if (!manifestLoadHandled) {
|
|
698
|
+
manifestLoadHandled = true;
|
|
699
|
+
try {
|
|
700
|
+
await this._remotePlayerLoad(url, startTime);
|
|
701
|
+
remoteLoadResolver();
|
|
702
|
+
} catch (error) {
|
|
703
|
+
remoteLoadRejecter(error);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
631
706
|
}
|
|
632
707
|
};
|
|
633
708
|
|
|
@@ -810,5 +885,5 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
810
885
|
|
|
811
886
|
}
|
|
812
887
|
|
|
813
|
-
|
|
814
|
-
export {
|
|
888
|
+
shaka.Player = SenzaShakaPlayer;
|
|
889
|
+
export { shaka };
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { getPlatformInfo } from "./api";
|
|
2
|
-
import pack from "../package.json";
|
|
3
2
|
import { sessionInfo } from "./SessionInfo";
|
|
4
|
-
const { version } = pack;
|
|
5
3
|
|
|
6
4
|
const REST_RESPONSE_TIMEOUT_SECONDS = 5;
|
|
7
5
|
|
|
6
|
+
export function getVersion() {
|
|
7
|
+
return typeof IMPLEMENTATION_VERSION !== "undefined"
|
|
8
|
+
// eslint-disable-next-line no-undef
|
|
9
|
+
? IMPLEMENTATION_VERSION
|
|
10
|
+
: "unknown";
|
|
11
|
+
};
|
|
12
|
+
|
|
8
13
|
export function getFCID() {
|
|
9
14
|
return Math.round(Math.random() * 100000) + "-" + getPlatformInfo().sessionInfo?.connectionId;
|
|
10
15
|
}
|
|
@@ -42,7 +47,7 @@ class SdkLogger {
|
|
|
42
47
|
console.info(`[hs-sdk] [metrics] ${JSON.stringify(metricObj)}`);
|
|
43
48
|
}
|
|
44
49
|
withFields(logFields) {
|
|
45
|
-
return new SdkLogger({...this.logFields, ...logFields});
|
|
50
|
+
return new SdkLogger({ ...this.logFields, ...logFields });
|
|
46
51
|
}
|
|
47
52
|
formatLogString(data) {
|
|
48
53
|
let logString = "[hs-sdk] " + data.join(" ");
|
|
@@ -51,9 +56,13 @@ class SdkLogger {
|
|
|
51
56
|
}
|
|
52
57
|
return logString;
|
|
53
58
|
}
|
|
59
|
+
addfields(fields) {
|
|
60
|
+
this.logFields = { ...this.logFields, ...fields };
|
|
61
|
+
return this;
|
|
62
|
+
}
|
|
54
63
|
}
|
|
55
64
|
|
|
56
|
-
export const sdkLogger = new SdkLogger({sdkVersion:
|
|
65
|
+
export const sdkLogger = new SdkLogger({ sdkVersion: getVersion(), url: window?.location?.href ?? "" });
|
|
57
66
|
|
|
58
67
|
export async function getRestResponse(messageName) {
|
|
59
68
|
|
|
@@ -64,14 +73,14 @@ export async function getRestResponse(messageName) {
|
|
|
64
73
|
|
|
65
74
|
return new Promise((resolve, reject) => {
|
|
66
75
|
const FCID = getFCID();
|
|
67
|
-
const logger = sdkLogger.withFields({FCID});
|
|
76
|
+
const logger = sdkLogger.withFields({ FCID });
|
|
68
77
|
const message = {
|
|
69
78
|
type: "restRequest",
|
|
70
79
|
name: messageName,
|
|
71
80
|
method: "GET",
|
|
72
81
|
fcid: FCID
|
|
73
82
|
};
|
|
74
|
-
const request = {target: "TC", waitForResponse: true, message: JSON.stringify(message)};
|
|
83
|
+
const request = { target: "TC", waitForResponse: true, message: JSON.stringify(message) };
|
|
75
84
|
let timeoutHandler = 0;
|
|
76
85
|
const queryId = window.cefQuery({
|
|
77
86
|
request: JSON.stringify(request),
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { noop } from "./utils";
|
|
2
|
+
/**
|
|
3
|
+
* @class AlarmManager
|
|
4
|
+
* AlarmManager is a singleton class that manages the alarms in the application. It fires events whose types are the names of the alarms.
|
|
5
|
+
* @fires MyAlarm
|
|
6
|
+
*/
|
|
7
|
+
export class AlarmManager extends EventTarget {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* alarm event
|
|
11
|
+
*
|
|
12
|
+
* @event AlarmManager#MyAlarm
|
|
13
|
+
* @description Fired when time of 'MyAlarm' arrives. If this alarm triggers the application load and the application doesn't call
|
|
14
|
+
* lifecycle.moveToForeground() in the alarm callback (i.e. the application remains in the background after the callback is completed),
|
|
15
|
+
* the application will be unloaded.
|
|
16
|
+
* NOTE: If you perform async operations in the callback (without moving to foreground), you must wait for the async
|
|
17
|
+
* operation to finish before returning from the callback, otherwise the application will be unloaded before the async operation is finished.<br>
|
|
18
|
+
* @example
|
|
19
|
+
* alarmManager.addEventListener("MyAlarm", async (e) => {
|
|
20
|
+
* console.log("alarm MyAlarm arrived with data", e.detail);
|
|
21
|
+
* await fetch("http://www.example.com");
|
|
22
|
+
* });
|
|
23
|
+
* alarmManager.addAlarm("MyAlarm", Date.now() + 60*60*1000, "MyData");
|
|
24
|
+
*/
|
|
25
|
+
constructor() {
|
|
26
|
+
super();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
addEventListener(type, callback) {
|
|
30
|
+
noop("AlarmManager.addEventListener", type, callback);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
removeEventListener(type, callback) {
|
|
34
|
+
noop("AlarmManager.removeEventListener", type, callback);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Set alarm to be fired at the specified time, event when ui is released
|
|
38
|
+
* @param {string} alarmName unique name for the alarm
|
|
39
|
+
* @param {number} alarmTime target time for the alarm to be fired, represented by the number of milliseconds elapsed since the epoch
|
|
40
|
+
* @param {string} [data] data to be passed back when the alarm is fired
|
|
41
|
+
* */
|
|
42
|
+
addAlarm(alarmName, alarmTime, data = "", toleranceBefore = 0, toleranceAfter = 0) {
|
|
43
|
+
noop("AlarmManager.addAlarm", alarmName, alarmTime, data, toleranceBefore, toleranceAfter);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Delete the specified alarm
|
|
47
|
+
* @param {string} alarmName name of alarm to be deleted
|
|
48
|
+
*
|
|
49
|
+
* */
|
|
50
|
+
deleteAlarm(alarmName) {
|
|
51
|
+
noop("AlarmManager.deleteAlarm", alarmName);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Delete all alarms
|
|
55
|
+
*
|
|
56
|
+
* */
|
|
57
|
+
deleteAllAlarms() {
|
|
58
|
+
noop("AlarmManager.deleteAllAlarms");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Async function that asks for all active alarms
|
|
62
|
+
* @returns {Promise} when resolved, returns an array of objects containing alarmName and alarmTime fields
|
|
63
|
+
* @throws {string} error string in case of an error
|
|
64
|
+
*
|
|
65
|
+
* */
|
|
66
|
+
getActiveAlarms() {
|
|
67
|
+
return noop("AlarmManager.getActiveAlarms");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { Lifecycle } from "./lifecycle.js";
|
|
2
|
+
export { DeviceManager } from "./deviceManager.js";
|
|
3
|
+
export { PlatformManager } from "./platformManager.js";
|
|
4
|
+
export { AlarmManager } from "./alarmManager.js";
|
|
5
|
+
export { MessageManager } from "./messageManager.js";
|
|
6
|
+
export { RemotePlayer } from "./remotePlayer.js";
|
|
7
|
+
export { SenzaShakaPlayer as ShakaPlayer, shaka } from "./senzaShakaPlayer.js";
|
|
8
|
+
export { showSequence, initSequence } from "./devSequence.js";
|
|
@@ -204,6 +204,7 @@ const setupSequence = (components, items) => {
|
|
|
204
204
|
};
|
|
205
205
|
methodInject(components, inject, (name) => name.startsWith("_") || name.startsWith("get"));
|
|
206
206
|
handleKeys(items);
|
|
207
|
+
playersEvents(components, items);
|
|
207
208
|
sdkLogger.log("Sequence initialized.");
|
|
208
209
|
};
|
|
209
210
|
|
|
@@ -257,3 +258,37 @@ export const showSequence = (visible = true) => {
|
|
|
257
258
|
}
|
|
258
259
|
container.style.visibility = visible ? "visible" : "hidden";
|
|
259
260
|
};
|
|
261
|
+
function playersEvents(components, items) {
|
|
262
|
+
components.remotePlayer.addEventListener("videoelementattached", () => {
|
|
263
|
+
const video = components.remotePlayer._videoElement;
|
|
264
|
+
if (video && !video._devSequenceRateChangeHandler) {
|
|
265
|
+
video._devSequenceRateChangeHandler = () => {
|
|
266
|
+
items.push({
|
|
267
|
+
component: "localPlayer",
|
|
268
|
+
id: "ratechange=" + video.playbackRate,
|
|
269
|
+
time: performance.now() - currentTime
|
|
270
|
+
});
|
|
271
|
+
};
|
|
272
|
+
video.addEventListener("ratechange", video._devSequenceRateChangeHandler);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (video && !video._devSequencePlayingHandler) {
|
|
276
|
+
video._devSequencePlayingHandler = () => {
|
|
277
|
+
items.push({
|
|
278
|
+
component: "localPlayer",
|
|
279
|
+
id: "playing event",
|
|
280
|
+
time: performance.now() - currentTime
|
|
281
|
+
});
|
|
282
|
+
};
|
|
283
|
+
video.addEventListener("playing", video._devSequencePlayingHandler);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
components.remotePlayer.addEventListener("playing", () => {
|
|
287
|
+
items.push({
|
|
288
|
+
component: "remotePlayer",
|
|
289
|
+
id: "playing event",
|
|
290
|
+
time: performance.now() - currentTime
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { sdkLogger, noop } from "./utils.js";
|
|
2
|
+
|
|
3
|
+
const wifiInfo = {};
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @class DeviceManager
|
|
7
|
+
* DeviceManager is a singleton class that manages the device
|
|
8
|
+
*/
|
|
9
|
+
export class DeviceManager extends EventTarget {
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
super();
|
|
13
|
+
wifiInfo.level = 0;
|
|
14
|
+
wifiInfo.quality = 0;
|
|
15
|
+
wifiInfo.ssid = "unknown";
|
|
16
|
+
wifiInfo.bssid = "unknown";
|
|
17
|
+
/**
|
|
18
|
+
* @deprecated Instead, call deviceManager.getWifiInfo() periodically
|
|
19
|
+
* @event DeviceManager#wifiInfoUpdated
|
|
20
|
+
* @example
|
|
21
|
+
* deviceManager.addEventListener("wifiInfoUpdated", () => {
|
|
22
|
+
* console.info("Wifi info has been updated to", deviceManager.wifiInfo);
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
*/
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @property {object} DeviceInfo
|
|
30
|
+
* @property {string} DeviceInfo.deviceId
|
|
31
|
+
* @property {string} DeviceInfo.modelNumber
|
|
32
|
+
* @property {string} DeviceInfo.connectionId
|
|
33
|
+
* @property {string} DeviceInfo.community
|
|
34
|
+
* @property {string} DeviceInfo.tenant
|
|
35
|
+
* @property {string} DeviceInfo.clientIp
|
|
36
|
+
* @property {string} DeviceInfo.countryCode A 2-letter code as defined in ISO_3166-1
|
|
37
|
+
* @property {string} DeviceInfo.connectionType The type of device used during the current connection. Possible values are "device" which mean real device, "simulator" - simulated device - that used during development.
|
|
38
|
+
*/
|
|
39
|
+
get deviceInfo() {
|
|
40
|
+
sdkLogger.log("getDeviceInfo running locally, returning dummy info");
|
|
41
|
+
return {
|
|
42
|
+
deviceId: "123456789",
|
|
43
|
+
modelNumber: "ABC",
|
|
44
|
+
connectionId: "dummy",
|
|
45
|
+
community: "LocalDev",
|
|
46
|
+
tenant: "XXXXXX",
|
|
47
|
+
clientIp: "0.0.0.0",
|
|
48
|
+
countryCode: "XX",
|
|
49
|
+
connectionType: "simulator"
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @deprecated use deviceManager.getWifiInfo() instead
|
|
56
|
+
* @property {object} WifiInfo
|
|
57
|
+
* @property {number} WifiInfo.level
|
|
58
|
+
* @property {number} WifiInfo.quality
|
|
59
|
+
* @property {string} WifiInfo.ssid
|
|
60
|
+
* @property {string} WifiInfo.bssid
|
|
61
|
+
*/
|
|
62
|
+
get wifiInfo() {
|
|
63
|
+
return wifiInfo;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Reboot the device
|
|
68
|
+
* @return {Promise} Promise which is resolved when the reboot command has been successfully processed.
|
|
69
|
+
* Failure to process the reboot command will result in the promise being rejected.
|
|
70
|
+
*/
|
|
71
|
+
reboot() {
|
|
72
|
+
return noop("DeviceManager.reboot");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Delete current wifi configuration and forget network
|
|
77
|
+
* @return {Promise} Promise which is resolved when the clearWifi command has been successfully processed.
|
|
78
|
+
* Failure to process the clearWifi command will result in the promise being rejected.
|
|
79
|
+
*/
|
|
80
|
+
clearWifi() {
|
|
81
|
+
return noop("DeviceManager.clearWifi");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Send raw data directly to a customer's device via the USB serial connection of a Senza device.
|
|
86
|
+
* This function is specifically designed for customers who have their devices connected to a Senza device.
|
|
87
|
+
* Using this API, these customers can transmit messages or data directly to their connected devices.
|
|
88
|
+
* The transmission occurs through the Senza device's USB serial interface, facilitating direct communication
|
|
89
|
+
* between the customer's web application and their device.
|
|
90
|
+
* @param {String} data raw data to be passed to the device
|
|
91
|
+
* @return {Promise} Promise which is resolved when the command has been successfully processed.
|
|
92
|
+
* Failure to process the command will result in the promise being rejected.
|
|
93
|
+
*/
|
|
94
|
+
sendDataToDevice(data) {
|
|
95
|
+
return noop("DeviceManager.sendDataToDevice", data);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Perform device factory reset.
|
|
100
|
+
* @param {Boolean} [reboot=true] a flag that is passed to the device to indicate whether it should reboot after the factory reset. defaults to true.
|
|
101
|
+
* @return {Promise} Promise which is resolved when factoryReset has been successfully performed
|
|
102
|
+
* Failure to factoryReset for any reason, result in the promise being rejected.
|
|
103
|
+
*/
|
|
104
|
+
async factoryReset(reboot = true) {
|
|
105
|
+
return noop("DeviceManager.factoryReset", reboot);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @typedef {Object} WiFiInfo
|
|
110
|
+
* @property {string} ssid the name of the Wi-Fi network that the device is connected to
|
|
111
|
+
* @property {string} bssid the unique identifier of the Wi-Fi access point
|
|
112
|
+
* @property {string} standard the Wi-Fi standard in use, such as 802.11a/b/g/n/ac/ax
|
|
113
|
+
* @property {string} security the type of security protocol used by the Wi-Fi network, such as WEP, WPA, WPA2, or WPA3
|
|
114
|
+
* @property {string} device-mac the MAC address of the device
|
|
115
|
+
* @property {string} device-ip4 the IPv4 address assigned to the device on the Wi-Fi network
|
|
116
|
+
* @property {string} dhcp-server the IP address of the DHCP server that assigned the device's network configuration
|
|
117
|
+
* @property {string[]} dns-server array of IP addresses of the DNS servers the device uses to resolve domain names
|
|
118
|
+
* @property {number} channel the number of the Wi-Fi channel currently being used
|
|
119
|
+
* @property {number} width width of the Wi-Fi channel in megahertz, e.g. 20MHz or 40 MHz channel
|
|
120
|
+
* @property {number} level a measure of the received signal strength, in the range 0 to 100 (the higher, the better). The level value is 100+RSSI (RSSI is the signal strength, measured in decibels)
|
|
121
|
+
* @property {number} quality a measure of the signal quality, in the range 0 to 100 (the higher, the better). The quality value is derived from the signal EVM.
|
|
122
|
+
* */
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Get Wi-Fi info - access point data and status (the status is cached for 5 seconds)
|
|
126
|
+
* @returns {WiFiInfo} An object containing the Wi-Fi info
|
|
127
|
+
* @alpha API has not yet been released
|
|
128
|
+
* */
|
|
129
|
+
// This api is part of epic HSDEV-4185
|
|
130
|
+
async getWifiInfo() {
|
|
131
|
+
return Promise.resolve({});
|
|
132
|
+
}
|
|
133
|
+
}
|