senza-sdk 4.2.64-2642526.0 → 4.2.64
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/bundle.js.LICENSE.txt +4 -0
- package/package.json +10 -16
- package/src/{implementation/alarmManager.js → alarmManager.js} +52 -15
- package/src/api.js +329 -247
- package/src/{interface/devSequence.js → devSequence.js} +35 -0
- package/src/{implementation/deviceManager.js → deviceManager.js} +65 -4
- package/src/{implementation/lifecycle.js → lifecycle.js} +181 -5
- package/src/{implementation/messageManager.js → messageManager.js} +6 -6
- package/src/{implementation/platformManager.js → platformManager.js} +4 -5
- package/src/{implementation/remotePlayer.js → remotePlayer.js} +16 -7
- package/src/{implementation/senzaShakaPlayer.js → senzaShakaPlayer.js} +114 -25
- package/src/{implementation/utils.js → utils.js} +6 -15
- package/src/implementation/api.js +0 -367
- package/src/interface/alarmManager.js +0 -69
- package/src/interface/api.js +0 -8
- package/src/interface/deviceManager.js +0 -133
- package/src/interface/lifecycle.js +0 -278
- package/src/interface/messageManager.js +0 -46
- package/src/interface/platformManager.js +0 -35
- package/src/interface/remotePlayer.js +0 -441
- package/src/interface/senzaShakaPlayer.js +0 -171
- package/src/interface/utils.js +0 -45
- /package/src/{implementation/SessionInfo.js → SessionInfo.js} +0 -0
- /package/src/{implementation/devHelper.js → devHelper.js} +0 -0
- /package/src/{implementation/eventListenersManager.js → eventListenersManager.js} +0 -0
- /package/src/{implementation/subtitlesUtils.js → subtitlesUtils.js} +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import * as shaka from "shaka-player";
|
|
3
2
|
import { remotePlayer, lifecycle, getPlatformInfo } from "./api";
|
|
4
3
|
import { sdkLogger, iso6393to1 } from "./utils";
|
|
4
|
+
import moment from "moment";
|
|
5
|
+
|
|
5
6
|
|
|
6
7
|
// Define custom error category
|
|
7
8
|
shaka.util.Error.Category.SENZA_PLAYER_ERROR = 50;
|
|
@@ -31,6 +32,11 @@ class SenzaError extends shaka.util.Error {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
|
|
35
|
+
// Copy the shaka module and replace the Player class with SenzaShakaPlayer
|
|
36
|
+
// if we don't Copy the shaka module, the Player class will be replaced for all the other modules that import shaka
|
|
37
|
+
const senzaShaka = { ...shaka };
|
|
38
|
+
|
|
39
|
+
|
|
34
40
|
/**
|
|
35
41
|
* SenzaShakaPlayer subclass of Shaka that handles both local and remote playback.
|
|
36
42
|
*
|
|
@@ -72,9 +78,9 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
72
78
|
* @private
|
|
73
79
|
* @type {number}
|
|
74
80
|
* @description Timeout in milliseconds to wait for playing event
|
|
75
|
-
* @default
|
|
81
|
+
* @default 4000
|
|
76
82
|
*/
|
|
77
|
-
_playingTimeout =
|
|
83
|
+
_playingTimeout = 4000;
|
|
78
84
|
|
|
79
85
|
/**
|
|
80
86
|
* @private
|
|
@@ -89,7 +95,7 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
89
95
|
* @description Whether to stop remote player on error
|
|
90
96
|
* @default false
|
|
91
97
|
*/
|
|
92
|
-
|
|
98
|
+
_shouldStopOnRemotePlayerError = false;
|
|
93
99
|
|
|
94
100
|
/**
|
|
95
101
|
* @private
|
|
@@ -181,7 +187,7 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
181
187
|
originatesFromRemotePlayer: true
|
|
182
188
|
};
|
|
183
189
|
|
|
184
|
-
const response = await this.getNetworkingEngine().request(
|
|
190
|
+
const response = await this.getNetworkingEngine().request(senzaShaka.net.NetworkingEngine.RequestType.LICENSE, request).promise;
|
|
185
191
|
|
|
186
192
|
let responseBody = response.data;
|
|
187
193
|
if (response.status < 200 || response.status >= 300) {
|
|
@@ -280,13 +286,15 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
280
286
|
|
|
281
287
|
|
|
282
288
|
/**
|
|
283
|
-
* Handles errors
|
|
289
|
+
* Handles errors received by remote player while waiting for the playing event.
|
|
290
|
+
* The promise returned to the call for video element play will be rejected.
|
|
284
291
|
* @private
|
|
285
292
|
* @param {Error} error - The error object.
|
|
286
293
|
*/
|
|
287
294
|
_handlePlayPromiseError(error) {
|
|
288
295
|
|
|
289
296
|
sdkLogger.error("Error while waiting for playing event:", error);
|
|
297
|
+
|
|
290
298
|
if (this._playPromiseReject) {
|
|
291
299
|
this._playPromiseReject(error);
|
|
292
300
|
this._playPromiseResolve = null;
|
|
@@ -296,6 +304,46 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
296
304
|
clearTimeout(this._playTimeoutId);
|
|
297
305
|
this._playTimeoutId = null;
|
|
298
306
|
}
|
|
307
|
+
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* @private
|
|
312
|
+
* @type {number}
|
|
313
|
+
* @description Minimum suggested presentation delay in seconds
|
|
314
|
+
* @default 15
|
|
315
|
+
*/
|
|
316
|
+
_minSuggestedPresentationDelay = 15;
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Modifies the suggestedPresentationDelay in the manifest text
|
|
320
|
+
* @private
|
|
321
|
+
* @param {string} manifestText - The MPD manifest text
|
|
322
|
+
* @returns {string} - Modified manifest text , or undefined if no modification was done
|
|
323
|
+
*/
|
|
324
|
+
_updateManifestDelayIfBelowMinimum(manifestText) {
|
|
325
|
+
// Look for suggestedPresentationDelay attribute
|
|
326
|
+
const match = manifestText.match(/suggestedPresentationDelay="([^"]+)"/);
|
|
327
|
+
if (match) {
|
|
328
|
+
const durationString = match[1];
|
|
329
|
+
const duration = moment.duration(durationString);
|
|
330
|
+
const currentDelay = duration.asSeconds();
|
|
331
|
+
|
|
332
|
+
sdkLogger.info(`Found suggestedPresentationDelay in manifest: ${currentDelay.toFixed(3)}s`);
|
|
333
|
+
|
|
334
|
+
if (currentDelay < this._minSuggestedPresentationDelay) {
|
|
335
|
+
// Replace the value in the manifest text with 3 decimal places
|
|
336
|
+
manifestText = manifestText.replace(
|
|
337
|
+
/suggestedPresentationDelay="[^"]+"/,
|
|
338
|
+
`suggestedPresentationDelay="PT${this._minSuggestedPresentationDelay.toFixed(3)}S"`
|
|
339
|
+
);
|
|
340
|
+
sdkLogger.info(`Updated manifest suggestedPresentationDelay to ${this._minSuggestedPresentationDelay.toFixed(3)}s`);
|
|
341
|
+
return manifestText;
|
|
342
|
+
}
|
|
343
|
+
} else {
|
|
344
|
+
sdkLogger.info("suggestedPresentationDelay is not defined at the manifest");
|
|
345
|
+
}
|
|
346
|
+
return undefined;
|
|
299
347
|
}
|
|
300
348
|
|
|
301
349
|
/**
|
|
@@ -325,14 +373,38 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
325
373
|
const playTimeout = getPlatformInfo()?.sessionInfo?.settings?.["ui-streamer"]?.playingEventTimeout;
|
|
326
374
|
this._playingTimeout = (playTimeout >= 0) ? playTimeout*1000 : this._playingTimeout;
|
|
327
375
|
|
|
376
|
+
// Initialize minSuggestedPresentationDelay from UI settings or use default
|
|
377
|
+
const uiSettings = getPlatformInfo()?.sessionInfo?.settings?.["ui-streamer"];
|
|
378
|
+
if (uiSettings?.minSuggestedPresentationDelay !== undefined) {
|
|
379
|
+
this._minSuggestedPresentationDelay = uiSettings.minSuggestedPresentationDelay;
|
|
380
|
+
sdkLogger.info(`Using configured minSuggestedPresentationDelay: ${this._minSuggestedPresentationDelay}s`);
|
|
381
|
+
}
|
|
382
|
+
|
|
328
383
|
// if video element is provided, add the listeres here. In this case ,there is no need to call attach.
|
|
329
384
|
if (videoElement) {
|
|
330
385
|
this._attach(videoElement);
|
|
331
386
|
sdkLogger.warn("SenzaShakaPlayer constructor Adding videoElement in the constructor is going to be deprecated in the future. Please use attach method instead.");
|
|
332
387
|
}
|
|
333
388
|
|
|
389
|
+
this.configure({
|
|
390
|
+
manifest: {
|
|
391
|
+
defaultPresentationDelay: this._minSuggestedPresentationDelay // in seconds
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
remotePlayer.configure({
|
|
396
|
+
minSuggestedPresentationDelay: this._minSuggestedPresentationDelay
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
this.addEventListener("buffering", () => {
|
|
400
|
+
if (this.videoElement) {
|
|
401
|
+
sdkLogger.info("Buffering at time:", this.videoElement.currentTime);
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
|
|
334
405
|
}
|
|
335
406
|
|
|
407
|
+
|
|
336
408
|
_attach(videoElement) {
|
|
337
409
|
this.videoElement = videoElement;
|
|
338
410
|
|
|
@@ -556,11 +628,12 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
556
628
|
const isCritical = this._isErrorCritical(remotePlayerErrorCode);
|
|
557
629
|
const error = this._createSenzaError(remotePlayerErrorCode, message, isCritical);
|
|
558
630
|
const errorMap = new Map();
|
|
631
|
+
const shouldStopPlayback = this._shouldStopOnRemotePlayerError && this.videoElement && isCritical;
|
|
559
632
|
errorMap.set("detail", error);
|
|
560
633
|
|
|
561
634
|
// Check if we should stop playback - only for critical errors when configured
|
|
562
|
-
|
|
563
|
-
|
|
635
|
+
|
|
636
|
+
if (shouldStopPlayback) {
|
|
564
637
|
try {
|
|
565
638
|
sdkLogger.warn("Stopping local player playback due to critical error");
|
|
566
639
|
// Stop only local playback
|
|
@@ -568,9 +641,11 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
568
641
|
} catch (stopError) {
|
|
569
642
|
sdkLogger.error("Error while trying to stop video element playback:", stopError);
|
|
570
643
|
}
|
|
644
|
+
// Handle error while waiting for play event. If the error is not critical or the system is configured not to stop remote player on error,
|
|
645
|
+
// the playback timeout will start the local playback
|
|
646
|
+
this._handlePlayPromiseError(error);
|
|
571
647
|
}
|
|
572
|
-
|
|
573
|
-
this._handlePlayPromiseError(error);
|
|
648
|
+
|
|
574
649
|
this.dispatchEvent(new shaka.util.FakeEvent("error", errorMap));
|
|
575
650
|
}
|
|
576
651
|
|
|
@@ -608,16 +683,30 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
608
683
|
|
|
609
684
|
// This callbakc will be activated when the manifest is loaded. It will trigger load of the remote player.
|
|
610
685
|
// This will ensure that the remote player is loaded only after the manifest is loaded by local player.
|
|
611
|
-
const responseFilterCallback = async (type) => {
|
|
612
|
-
if (type === shaka.net.NetworkingEngine.RequestType.MANIFEST
|
|
613
|
-
manifestLoadHandled = true;
|
|
686
|
+
const responseFilterCallback = async (type, response) => {
|
|
687
|
+
if (type === shaka.net.NetworkingEngine.RequestType.MANIFEST) {
|
|
614
688
|
try {
|
|
615
|
-
|
|
616
|
-
|
|
689
|
+
if (response.data && this._minSuggestedPresentationDelay > 0) {
|
|
690
|
+
const manifestText = new TextDecoder().decode(response.data);
|
|
691
|
+
const modifiedText = this._updateManifestDelayIfBelowMinimum(manifestText);
|
|
692
|
+
if (modifiedText) {
|
|
693
|
+
const responseData = new TextEncoder().encode(modifiedText).buffer;
|
|
694
|
+
response.data = responseData;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
617
697
|
} catch (error) {
|
|
618
|
-
|
|
698
|
+
sdkLogger.error("Error processing manifest:", error);
|
|
619
699
|
}
|
|
620
700
|
|
|
701
|
+
if (!manifestLoadHandled) {
|
|
702
|
+
manifestLoadHandled = true;
|
|
703
|
+
try {
|
|
704
|
+
await this._remotePlayerLoad(url, startTime);
|
|
705
|
+
remoteLoadResolver();
|
|
706
|
+
} catch (error) {
|
|
707
|
+
remoteLoadRejecter(error);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
621
710
|
}
|
|
622
711
|
};
|
|
623
712
|
|
|
@@ -680,14 +769,14 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
680
769
|
/**
|
|
681
770
|
* Override the configure method to add custom configuration handling
|
|
682
771
|
* Supports the following additional configuration options:
|
|
683
|
-
* -
|
|
772
|
+
* - shouldStopOnRemotePlayerError: boolean - If true, local player will be stopped on remote player error
|
|
684
773
|
*
|
|
685
774
|
* @override
|
|
686
775
|
* @param {Object} config - Configuration object to be merged with existing config
|
|
687
|
-
* @param {boolean} [config.
|
|
776
|
+
* @param {boolean} [config.shouldStopOnRemotePlayerError=true] - Whether to stop local player on remote player error
|
|
688
777
|
* @example
|
|
689
778
|
* player.configure({
|
|
690
|
-
*
|
|
779
|
+
* shouldStopOnRemotePlayerError: false, // Don't stop local playback on remote player error
|
|
691
780
|
* // ... other shaka configurations
|
|
692
781
|
* });
|
|
693
782
|
*/
|
|
@@ -695,12 +784,12 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
695
784
|
sdkLogger.log("configure player with: ", JSON.stringify(config));
|
|
696
785
|
|
|
697
786
|
// Handle custom configuration
|
|
698
|
-
if (config.
|
|
699
|
-
this.
|
|
787
|
+
if (config.shouldStopOnRemotePlayerError !== undefined) {
|
|
788
|
+
this._shouldStopOnRemotePlayerError = !!config.shouldStopOnRemotePlayerError;
|
|
700
789
|
// Remove our custom config so it doesn't get passed to parent
|
|
701
790
|
// Use rest operator without creating a named variable for the removed property
|
|
702
791
|
// eslint-disable-next-line no-unused-vars
|
|
703
|
-
const {
|
|
792
|
+
const { shouldStopOnRemotePlayerError, ...shakaConfig } = config;
|
|
704
793
|
config = shakaConfig;
|
|
705
794
|
}
|
|
706
795
|
|
|
@@ -800,5 +889,5 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
800
889
|
|
|
801
890
|
}
|
|
802
891
|
|
|
803
|
-
|
|
804
|
-
export { shaka };
|
|
892
|
+
senzaShaka.Player = SenzaShakaPlayer;
|
|
893
|
+
export { senzaShaka as shaka };
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import { getPlatformInfo } from "./api";
|
|
2
|
+
import pack from "../package.json";
|
|
2
3
|
import { sessionInfo } from "./SessionInfo";
|
|
4
|
+
const { version } = pack;
|
|
3
5
|
|
|
4
6
|
const REST_RESPONSE_TIMEOUT_SECONDS = 5;
|
|
5
7
|
|
|
6
|
-
export function getVersion() {
|
|
7
|
-
return typeof IMPLEMENTATION_VERSION !== "undefined"
|
|
8
|
-
// eslint-disable-next-line no-undef
|
|
9
|
-
? IMPLEMENTATION_VERSION
|
|
10
|
-
: "unknown";
|
|
11
|
-
};
|
|
12
|
-
|
|
13
8
|
export function getFCID() {
|
|
14
9
|
return Math.round(Math.random() * 100000) + "-" + getPlatformInfo().sessionInfo?.connectionId;
|
|
15
10
|
}
|
|
@@ -47,7 +42,7 @@ class SdkLogger {
|
|
|
47
42
|
console.info(`[hs-sdk] [metrics] ${JSON.stringify(metricObj)}`);
|
|
48
43
|
}
|
|
49
44
|
withFields(logFields) {
|
|
50
|
-
return new SdkLogger({
|
|
45
|
+
return new SdkLogger({...this.logFields, ...logFields});
|
|
51
46
|
}
|
|
52
47
|
formatLogString(data) {
|
|
53
48
|
let logString = "[hs-sdk] " + data.join(" ");
|
|
@@ -56,13 +51,9 @@ class SdkLogger {
|
|
|
56
51
|
}
|
|
57
52
|
return logString;
|
|
58
53
|
}
|
|
59
|
-
addfields(fields) {
|
|
60
|
-
this.logFields = { ...this.logFields, ...fields };
|
|
61
|
-
return this;
|
|
62
|
-
}
|
|
63
54
|
}
|
|
64
55
|
|
|
65
|
-
export const sdkLogger = new SdkLogger({
|
|
56
|
+
export const sdkLogger = new SdkLogger({sdkVersion: version, url: window?.location?.href ?? ""});
|
|
66
57
|
|
|
67
58
|
export async function getRestResponse(messageName) {
|
|
68
59
|
|
|
@@ -73,14 +64,14 @@ export async function getRestResponse(messageName) {
|
|
|
73
64
|
|
|
74
65
|
return new Promise((resolve, reject) => {
|
|
75
66
|
const FCID = getFCID();
|
|
76
|
-
const logger = sdkLogger.withFields({
|
|
67
|
+
const logger = sdkLogger.withFields({FCID});
|
|
77
68
|
const message = {
|
|
78
69
|
type: "restRequest",
|
|
79
70
|
name: messageName,
|
|
80
71
|
method: "GET",
|
|
81
72
|
fcid: FCID
|
|
82
73
|
};
|
|
83
|
-
const request = {
|
|
74
|
+
const request = {target: "TC", waitForResponse: true, message: JSON.stringify(message)};
|
|
84
75
|
let timeoutHandler = 0;
|
|
85
76
|
const queryId = window.cefQuery({
|
|
86
77
|
request: JSON.stringify(request),
|
|
@@ -1,367 +0,0 @@
|
|
|
1
|
-
import { getFCID, sdkLogger, getVersion } from "./utils.js";
|
|
2
|
-
import { sessionInfo } from "./SessionInfo.js";
|
|
3
|
-
import { lifecycle } from "./lifecycle.js";
|
|
4
|
-
import { alarmManager } from "./alarmManager.js";
|
|
5
|
-
|
|
6
|
-
let authToken;
|
|
7
|
-
|
|
8
|
-
const API_VERSION = "1.0";
|
|
9
|
-
let interfaceVersion;
|
|
10
|
-
|
|
11
|
-
typeof document !== "undefined" && document.addEventListener("keydown", (event) => {
|
|
12
|
-
sdkLogger.log(`Got ${event.key} key`);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
/** @namespace auth
|
|
16
|
-
*@example
|
|
17
|
-
* import { auth } from "senza-sdk";
|
|
18
|
-
**/
|
|
19
|
-
export const auth = {
|
|
20
|
-
|
|
21
|
-
/** Should be called upon startup and be embedded in future requests */
|
|
22
|
-
getToken,
|
|
23
|
-
|
|
24
|
-
/** Should be called upon '401' event (unauthorized) */
|
|
25
|
-
forceTokenUpdate,
|
|
26
|
-
|
|
27
|
-
getClientAssertion
|
|
28
|
-
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
import { remotePlayer } from "./remotePlayer.js";
|
|
32
|
-
export { remotePlayer };
|
|
33
|
-
|
|
34
|
-
/** Should be called once to init the library
|
|
35
|
-
*@example
|
|
36
|
-
* import { init } from "senza-sdk";
|
|
37
|
-
* await init();
|
|
38
|
-
**/
|
|
39
|
-
export async function init(interfaceApiVersion, showSequenceFunc, initSequenceFunc) {
|
|
40
|
-
interfaceVersion = interfaceApiVersion;
|
|
41
|
-
sdkLogger.addfields({ interfaceVersion });
|
|
42
|
-
sdkLogger.log(`init. Interface version: ${interfaceVersion}. Implementation version: ${getVersion()}`);
|
|
43
|
-
|
|
44
|
-
if (!window.diagnostics) {
|
|
45
|
-
// ------------------------------------------------------------------------------------------------
|
|
46
|
-
// -- Do NOT change this log, as ui-streamer is checking this string to detect abnormal behavior --
|
|
47
|
-
// ------------------------------------------------------------------------------------------------
|
|
48
|
-
sdkLogger.error("[ init ] window.diagnostics is undefined");
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (window.cefQuery) {
|
|
52
|
-
|
|
53
|
-
// First, check compatability with ui-streamer api version
|
|
54
|
-
await new Promise((resolve, reject) => {
|
|
55
|
-
window.cefQuery({
|
|
56
|
-
request: "apiVersion " + API_VERSION,
|
|
57
|
-
persistent: false,
|
|
58
|
-
onSuccess: () => {
|
|
59
|
-
sdkLogger.log("api version compatability check succeeded");
|
|
60
|
-
resolve();
|
|
61
|
-
},
|
|
62
|
-
onFailure: (code, msg) => {
|
|
63
|
-
sdkLogger.error("api version compatability check failed: " + msg);
|
|
64
|
-
reject(msg);
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
const sessionInfoStr = await new Promise((resolve) => {
|
|
70
|
-
window.cefQuery({
|
|
71
|
-
request: "sessionInfo",
|
|
72
|
-
persistent: false,
|
|
73
|
-
onSuccess: (response) => {
|
|
74
|
-
sdkLogger.log("sessionInfo request successfully returned " + response);
|
|
75
|
-
resolve(response);
|
|
76
|
-
},
|
|
77
|
-
onFailure: (code, msg) => {
|
|
78
|
-
sdkLogger.error(`sessionInfo request failed: ${code} ${msg}`);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
sessionInfo.setSessionInfoStr(sessionInfoStr);
|
|
84
|
-
const sessionInfoObj = JSON.parse(sessionInfoStr);
|
|
85
|
-
authToken = sessionInfoObj?.settings?.webUI?.backendHeaders?.Authorization;
|
|
86
|
-
sdkLogger.log(`authToken: token = ${authToken}`);
|
|
87
|
-
// Listen to updateSession event to set the new token
|
|
88
|
-
document.addEventListener("updateSession", (e) => {
|
|
89
|
-
authToken = e.detail?.updateObj;
|
|
90
|
-
sdkLogger.log(`onUpdateSessionEvent: token = ${authToken}`);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
// Set default alarm timeout using UI-Streamer settings
|
|
94
|
-
const alarmTimeout = sessionInfoObj?.settings?.["ui-streamer"]?.alarmTimeout;
|
|
95
|
-
if (alarmTimeout) {
|
|
96
|
-
alarmManager._setDefaultTimeout(alarmTimeout);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Get trigger event
|
|
100
|
-
const triggerEventStr = await new Promise((resolve) => {
|
|
101
|
-
const FCID = getFCID();
|
|
102
|
-
const logger = sdkLogger.withFields({ FCID });
|
|
103
|
-
const message = { type: "triggerEvent", fcid: FCID };
|
|
104
|
-
const request = { target: "UI-Streamer", waitForResponse: false, message: JSON.stringify(message) };
|
|
105
|
-
window.cefQuery({
|
|
106
|
-
request: JSON.stringify(request),
|
|
107
|
-
persistent: false,
|
|
108
|
-
onSuccess: (response) => {
|
|
109
|
-
logger.log(`triggerEvent request successfully returned '${response}'`);
|
|
110
|
-
resolve(response);
|
|
111
|
-
},
|
|
112
|
-
onFailure: (code, msg) => {
|
|
113
|
-
logger.error(`triggerEvent request failed: ${code} ${msg}`);
|
|
114
|
-
resolve("");
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
let triggerEvent = {};
|
|
119
|
-
if (triggerEventStr) {
|
|
120
|
-
try {
|
|
121
|
-
triggerEvent = JSON.parse(triggerEventStr);
|
|
122
|
-
} catch (e) {
|
|
123
|
-
sdkLogger.error(`failed to parse trigger event string ${triggerEventStr}: ${e.message}`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Initialize lifecycle first to make sure the state is updated.
|
|
128
|
-
await lifecycle._init(sessionInfoObj?.settings?.["ui-streamer"], triggerEvent);
|
|
129
|
-
await remotePlayer._init(sessionInfoObj?.settings?.["ui-streamer"], triggerEvent);
|
|
130
|
-
|
|
131
|
-
const devSequence = sessionInfoObj?.settings?.["ui-streamer"]?.devSequence;
|
|
132
|
-
if (devSequence) {
|
|
133
|
-
initSequenceFunc({ lifecycle, remotePlayer });
|
|
134
|
-
showSequenceFunc(true);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
} else {
|
|
138
|
-
authToken = getPlatformInfo().sessionInfo?.settings?.webUI?.backendHeaders?.Authorization;
|
|
139
|
-
sdkLogger.log(`authToken dummy: token = ${authToken}`);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// override window.close() since it's not allowed to close the application this way
|
|
143
|
-
window.close = () => {
|
|
144
|
-
sdkLogger.warn("window.close is disabled on Senza platform. Use lifecycle.exitApplication() instead.");
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Returns the platform information, including version, pod, pod ip and session info.
|
|
151
|
-
export function getPlatformInfo() {
|
|
152
|
-
if (typeof window !== "undefined" && window.diagnostics) {
|
|
153
|
-
try {
|
|
154
|
-
const platformInfo = window.diagnostics() || {};
|
|
155
|
-
platformInfo.sessionInfo = sessionInfo.sessionInfoObj;
|
|
156
|
-
return platformInfo;
|
|
157
|
-
} catch (e) {
|
|
158
|
-
sdkLogger.error("Could not get platform info", e.stack);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
} else {
|
|
162
|
-
if (typeof window !== "undefined" && !window.diagnostics) {
|
|
163
|
-
sdkLogger.error("[ getPlatformInfo ] window.diagnostics is undefined");
|
|
164
|
-
}
|
|
165
|
-
return {
|
|
166
|
-
version: "X.X.XX-X",
|
|
167
|
-
pod: "ui-streamer-X.X.XX-X-QWERT-ASDFG-XXX-XXXXXX-XXXXX",
|
|
168
|
-
podIP: "0.0.0.0",
|
|
169
|
-
sessionInfo: {
|
|
170
|
-
userAgent: "SynamediaSenza/XX.YY.ZZ",
|
|
171
|
-
connectionId: "dummy",
|
|
172
|
-
deviceId: "123456789",
|
|
173
|
-
community: "LocalDev",
|
|
174
|
-
tenant: "XXXXXX",
|
|
175
|
-
tenantId: "XXXXXX",
|
|
176
|
-
manifest: {
|
|
177
|
-
transcontainer: "X.X.XX-X"
|
|
178
|
-
},
|
|
179
|
-
settings: {
|
|
180
|
-
webUI: {
|
|
181
|
-
backendHeaders: {
|
|
182
|
-
Authorization: "Bearer dummytoken"
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
},
|
|
186
|
-
homeSessionInfo: {
|
|
187
|
-
tenantId: "XXXXXX",
|
|
188
|
-
community: "LocalDev"
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
async function getToken() {
|
|
196
|
-
if (!authToken) {
|
|
197
|
-
sdkLogger.log("getToken wait for promise updateSession event");
|
|
198
|
-
return new Promise((resolve) => {
|
|
199
|
-
// Listen to updateSession event to set the new token
|
|
200
|
-
document.addEventListener("updateSession", (e) => {
|
|
201
|
-
authToken = e.detail?.updateObj;
|
|
202
|
-
sdkLogger.log(`onUpdateSessionEvent: token= ${authToken}`);
|
|
203
|
-
resolve(authToken);
|
|
204
|
-
}, { once: true });
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
return Promise.resolve(authToken);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function forceTokenUpdate() {
|
|
211
|
-
authToken = null;
|
|
212
|
-
|
|
213
|
-
if (window.cefQuery) {
|
|
214
|
-
const FCID = getFCID();
|
|
215
|
-
const logger = sdkLogger.withFields({ FCID });
|
|
216
|
-
logger.log("forceTokenUpdate: sending updateSessionRequest");
|
|
217
|
-
const message = {
|
|
218
|
-
type: "updateSessionRequest",
|
|
219
|
-
updateKey: "authorization",
|
|
220
|
-
parentPath: "settings.webUI.backendHeaders.Authorization",
|
|
221
|
-
fcid: FCID
|
|
222
|
-
};
|
|
223
|
-
const request = { target: "TC", waitForResponse: false, message: JSON.stringify(message) };
|
|
224
|
-
window.cefQuery({
|
|
225
|
-
request: JSON.stringify(request),
|
|
226
|
-
persistent: false,
|
|
227
|
-
onSuccess: () => {
|
|
228
|
-
logger.log("updateSessionRequest successfully sent");
|
|
229
|
-
},
|
|
230
|
-
onFailure: (code, msg) => {
|
|
231
|
-
logger.error(`updateSessionRequest failed: ${code} ${msg}`);
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
} else {
|
|
235
|
-
sdkLogger.error("forceTokenUpdate: window.cefQuery is undefined");
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/** Returns a boolean that indicates whether we are running in an e2e environment, or on local browser */
|
|
240
|
-
export function isRunningE2E() {
|
|
241
|
-
return !!(typeof window !== "undefined" && window.cefQuery);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/** Call this API once after application startup, when the ui is ready to accept keys/events */
|
|
245
|
-
export function uiReady() {
|
|
246
|
-
if (window.cefQuery) {
|
|
247
|
-
window.cefQuery({
|
|
248
|
-
request: "uiReady",
|
|
249
|
-
persistent: false,
|
|
250
|
-
onSuccess: () => {
|
|
251
|
-
sdkLogger.log("uiReady request successfully sent");
|
|
252
|
-
},
|
|
253
|
-
onFailure: (code, msg) => {
|
|
254
|
-
sdkLogger.error(`uiReady request failed: ${code} ${msg}`);
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
} else {
|
|
258
|
-
sdkLogger.error("uiReady: window.cefQuery is undefined");
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
export { lifecycle } from "./lifecycle.js";
|
|
263
|
-
export { deviceManager } from "./deviceManager.js";
|
|
264
|
-
export { platformManager } from "./platformManager.js";
|
|
265
|
-
export { alarmManager };
|
|
266
|
-
export { messageManager } from "./messageManager.js";
|
|
267
|
-
export { SenzaShakaPlayer as ShakaPlayer, shaka } from "./senzaShakaPlayer.js";
|
|
268
|
-
|
|
269
|
-
import "./devHelper.js";
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* The function receives a license response and passes it to platform.
|
|
273
|
-
* @param {number} statusCode status code that was received from the license server
|
|
274
|
-
* @param {ArrayBuffer|string} licenseResponse a license response that was received from the license server to be passed to platform.
|
|
275
|
-
* @param {string} fcid a fcid received with the license request
|
|
276
|
-
* @param {string} sessionId a sessionId received with the license request
|
|
277
|
-
* In case of success licenceResponse is of type @type {ArrayBuffer}
|
|
278
|
-
* In case of error licenseResponse is of type @type {string}
|
|
279
|
-
*/
|
|
280
|
-
export function writeLicenseResponse(statusCode, licenseResponse, fcid, sessionId) {
|
|
281
|
-
|
|
282
|
-
if (statusCode >= 200 && statusCode < 300) {
|
|
283
|
-
licenseResponse = window.btoa(String.fromCharCode.apply(null, new Uint8Array(licenseResponse))); // to base64
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
if (window.cefQuery) {
|
|
287
|
-
const message = {
|
|
288
|
-
type: "updateLicense",
|
|
289
|
-
sessionId,
|
|
290
|
-
fcid
|
|
291
|
-
};
|
|
292
|
-
message[statusCode >= 200 && statusCode < 300 ? "response" : "error"] = licenseResponse;
|
|
293
|
-
const request = { target: "TC", waitForResponse: false, message: JSON.stringify(message) };
|
|
294
|
-
window.cefQuery({
|
|
295
|
-
request: JSON.stringify(request),
|
|
296
|
-
persistent: false,
|
|
297
|
-
onSuccess: () => {
|
|
298
|
-
sdkLogger.log("updateLicense request successfully sent");
|
|
299
|
-
},
|
|
300
|
-
onFailure: (code, msg) => {
|
|
301
|
-
sdkLogger.error(`updateLicense request failed: ${code} ${msg}`);
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
export class ClientAssertionError extends Error {
|
|
309
|
-
constructor(code, message) {
|
|
310
|
-
super(message);
|
|
311
|
-
this.code = code;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* @typedef Token
|
|
317
|
-
* @property {string} hostplatform_assertion The client assertion token.
|
|
318
|
-
*/
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Async function that returns the client assertion
|
|
322
|
-
* @return {Promise<Token>} Promise which is resolved to a client assertion object when getClientAssertion has been successfully performed. * client assertion object contains hostplatform_assertion property which holds the client assertion token.
|
|
323
|
-
* Failure to getClientAssertion for any reason, result in the promise being rejected.
|
|
324
|
-
* Error status codes:
|
|
325
|
-
* Status code 400 - Tenant configuration is missing
|
|
326
|
-
* Status code 0 - General error
|
|
327
|
-
* @example
|
|
328
|
-
* try {
|
|
329
|
-
* const client_assertion = await auth.getClientAssertion();
|
|
330
|
-
* console.log("Client assertion token is", client_assertion.hostplatform_assertion);
|
|
331
|
-
* } catch (e) {
|
|
332
|
-
* console.error("getClientAssertion failed", e);
|
|
333
|
-
* }
|
|
334
|
-
*/
|
|
335
|
-
export function getClientAssertion() {
|
|
336
|
-
if (window.cefQuery) {
|
|
337
|
-
sdkLogger.log("getClientAssertion is called");
|
|
338
|
-
|
|
339
|
-
return new Promise((resolve, reject) => {
|
|
340
|
-
window.cefQuery({
|
|
341
|
-
request: "client_assertion",
|
|
342
|
-
persistent: false,
|
|
343
|
-
onSuccess: (response) => {
|
|
344
|
-
try {
|
|
345
|
-
const json_response = JSON.parse(response);
|
|
346
|
-
sdkLogger.log(`client_assertion request successfully returned ${response}`);
|
|
347
|
-
resolve(json_response);
|
|
348
|
-
} catch (e) {
|
|
349
|
-
sdkLogger.error(`Failed to parse client assertion ${response}: ${e.message}`);
|
|
350
|
-
reject(new ClientAssertionError(0, "Failed to parse client assertion"));
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
},
|
|
354
|
-
onFailure: (code, msg) => {
|
|
355
|
-
sdkLogger.log(`client_assertion request failed: ${code} ${msg}`);
|
|
356
|
-
reject(new ClientAssertionError(code, msg));
|
|
357
|
-
}
|
|
358
|
-
});
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
sdkLogger.warn("getClientAssertion is not supported if NOT running e2e");
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
import * as senzaSDK from "./api.js";
|
|
365
|
-
if (typeof window !== "undefined") {
|
|
366
|
-
window.senzaSDKImplementation = window.senzaSDKImplementation || senzaSDK; // this is only for testing purposes which allows us to use and test senza APIs in pipeline tests
|
|
367
|
-
}
|