senza-sdk 4.2.64 → 4.2.65-157c9bb.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/dist/bundle.js.LICENSE.txt +0 -4
- package/package.json +3 -5
- package/src/devSequence.js +0 -35
- package/src/lifecycle.js +35 -24
- package/src/remotePlayer.js +27 -32
- package/src/senzaShakaPlayer.js +7 -86
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "senza-sdk",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.65-157c9bb.0",
|
|
4
4
|
"main": "./src/api.js",
|
|
5
5
|
"description": "API for Senza application",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"eslint": "eslint --max-warnings 0 src test",
|
|
16
16
|
"build": "npx webpack --config webpack.config.js",
|
|
17
17
|
"test": "jest --coverage --verbose",
|
|
18
|
-
"testall"
|
|
18
|
+
"testall": "jest --coverage --verbose && npm run eslint --fix"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@babel/cli": "^7.13.16",
|
|
@@ -32,7 +32,6 @@
|
|
|
32
32
|
"jsdoc-to-markdown": "^7.1.1",
|
|
33
33
|
"webpack": "^5.72.1",
|
|
34
34
|
"webpack-cli": "^5.1.4"
|
|
35
|
-
|
|
36
35
|
},
|
|
37
36
|
"jest": {
|
|
38
37
|
"verbose": false,
|
|
@@ -51,7 +50,6 @@
|
|
|
51
50
|
}
|
|
52
51
|
},
|
|
53
52
|
"dependencies": {
|
|
54
|
-
"shaka-player": "^4.12.5"
|
|
55
|
-
"moment": "^2.30.1"
|
|
53
|
+
"shaka-player": "^4.12.5"
|
|
56
54
|
}
|
|
57
55
|
}
|
package/src/devSequence.js
CHANGED
|
@@ -204,7 +204,6 @@ 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);
|
|
208
207
|
sdkLogger.log("Sequence initialized.");
|
|
209
208
|
};
|
|
210
209
|
|
|
@@ -258,37 +257,3 @@ export const showSequence = (visible = true) => {
|
|
|
258
257
|
}
|
|
259
258
|
container.style.visibility = visible ? "visible" : "hidden";
|
|
260
259
|
};
|
|
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
|
-
|
package/src/lifecycle.js
CHANGED
|
@@ -102,7 +102,9 @@ class Lifecycle extends EventTarget {
|
|
|
102
102
|
* @private
|
|
103
103
|
*/
|
|
104
104
|
this._isInitialized = false;
|
|
105
|
-
this.
|
|
105
|
+
this._inTransitionToForeground = false;
|
|
106
|
+
this._inTransitionToBackground = false;
|
|
107
|
+
this._inTransitionToStandby = false;
|
|
106
108
|
|
|
107
109
|
/**
|
|
108
110
|
* Event listeners manager for the userdisconnected event
|
|
@@ -384,7 +386,7 @@ class Lifecycle extends EventTarget {
|
|
|
384
386
|
// This api is part of epic HSDEV-713
|
|
385
387
|
_moveToUiStandby() {
|
|
386
388
|
if (window.cefQuery) {
|
|
387
|
-
this.
|
|
389
|
+
this._inTransitionToStandby = true;
|
|
388
390
|
return new Promise((resolve, reject) => {
|
|
389
391
|
const FCID = getFCID();
|
|
390
392
|
const request = { target: "TC", waitForResponse: false, internalAction: "uiExit", message: JSON.stringify({ type: "uiStandbyRequest", fcid: FCID }) };
|
|
@@ -395,12 +397,12 @@ class Lifecycle extends EventTarget {
|
|
|
395
397
|
persistent: false,
|
|
396
398
|
onSuccess: () => {
|
|
397
399
|
logger.log("[ moveToUiStandby ] moveToUiStandby successfully sent");
|
|
398
|
-
this.
|
|
400
|
+
this._inTransitionToStandby = false;
|
|
399
401
|
resolve(true);
|
|
400
402
|
},
|
|
401
403
|
onFailure: (code, msg) => {
|
|
402
404
|
logger.error(`[ moveToUiStandby ] moveToUiStandby failed: ${code} ${msg}`);
|
|
403
|
-
this.
|
|
405
|
+
this._inTransitionToStandby = false;
|
|
404
406
|
reject(`moveToUiStandby failed: ${code} ${msg}`);
|
|
405
407
|
}
|
|
406
408
|
});
|
|
@@ -534,6 +536,14 @@ class Lifecycle extends EventTarget {
|
|
|
534
536
|
this._countdown = null;
|
|
535
537
|
}
|
|
536
538
|
|
|
539
|
+
/**
|
|
540
|
+
* @private
|
|
541
|
+
*/
|
|
542
|
+
_isInTransition() {
|
|
543
|
+
return this._inTransitionToForeground || this._inTransitionToBackground || this._inTransitionToStandby;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
|
|
537
547
|
/**
|
|
538
548
|
* @deprecated use lifecycle.state instead.
|
|
539
549
|
* Async function that returns the ui lifecycle state
|
|
@@ -576,14 +586,19 @@ class Lifecycle extends EventTarget {
|
|
|
576
586
|
*/
|
|
577
587
|
moveToForeground() {
|
|
578
588
|
if (window.cefQuery) {
|
|
579
|
-
|
|
580
|
-
|
|
589
|
+
const inTransition = this._isInTransition();
|
|
590
|
+
if (inTransition || this._state === this.UiState.FOREGROUND || this._state === this.UiState.IN_TRANSITION_TO_FOREGROUND) {
|
|
591
|
+
sdkLogger.warn(`lifecycle moveToForeground: No need to transition to foreground, state: ${this._state} transition: ${inTransition}`);
|
|
581
592
|
return Promise.resolve(false);
|
|
582
593
|
}
|
|
583
|
-
this.
|
|
594
|
+
this._inTransitionToForeground = true;
|
|
584
595
|
alarmManager._moveToForegroundCalled();
|
|
585
596
|
const FCID = getFCID();
|
|
586
597
|
if (this._remotePlayerApiVersion >= 2) {
|
|
598
|
+
// 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.
|
|
599
|
+
if (remotePlayer._isSeekingByApplication && remotePlayer._targetSeekPlayingState === TargetPlayingState.PLAYING_ABR) {
|
|
600
|
+
remotePlayer._targetSeekPlayingState = TargetPlayingState.PLAYING_UI;
|
|
601
|
+
}
|
|
587
602
|
return new Promise((resolve, reject) => {
|
|
588
603
|
const FCID = getFCID();
|
|
589
604
|
const logger = sdkLogger.withFields({ FCID });
|
|
@@ -603,14 +618,14 @@ class Lifecycle extends EventTarget {
|
|
|
603
618
|
onSuccess: () => {
|
|
604
619
|
const duration = Date.now() - timeBeforeSendingRequest;
|
|
605
620
|
logger.withFields({ duration }).log(`stop completed successfully after ${duration} ms`);
|
|
606
|
-
this.
|
|
621
|
+
this._inTransitionToForeground = false;
|
|
607
622
|
timerId = clearTimer(timerId);
|
|
608
623
|
resolve(true);
|
|
609
624
|
},
|
|
610
625
|
onFailure: (code, msg) => {
|
|
611
626
|
const duration = Date.now() - timeBeforeSendingRequest;
|
|
612
627
|
logger.withFields({ duration }).log(`stop failed after ${duration} ms. Error code: ${code}, error message: ${msg}`);
|
|
613
|
-
this.
|
|
628
|
+
this._inTransitionToForeground = false;
|
|
614
629
|
timerId = clearTimer(timerId);
|
|
615
630
|
reject(new SenzaError(code, msg));
|
|
616
631
|
}
|
|
@@ -619,7 +634,7 @@ class Lifecycle extends EventTarget {
|
|
|
619
634
|
const timeout = this._remotePlayerConfirmationTimeout + 1000;
|
|
620
635
|
timerId = setTimeout(() => {
|
|
621
636
|
logger.log(`stop reached timeout of ${timeout} ms, canceling query id ${queryId}`);
|
|
622
|
-
this.
|
|
637
|
+
this._inTransitionToForeground = false;
|
|
623
638
|
window.cefQueryCancel(queryId);
|
|
624
639
|
reject(new SenzaError(6000, `stop reached timeout of ${timeout} ms`));
|
|
625
640
|
}, timeout, queryId);
|
|
@@ -634,11 +649,11 @@ class Lifecycle extends EventTarget {
|
|
|
634
649
|
persistent: false,
|
|
635
650
|
onSuccess: () => {
|
|
636
651
|
logger.log("uiActiveRequest successfully sent");
|
|
637
|
-
this.
|
|
652
|
+
this._inTransitionToForeground = false;
|
|
638
653
|
resolve(true);
|
|
639
654
|
},
|
|
640
655
|
onFailure: (code, msg) => {
|
|
641
|
-
this.
|
|
656
|
+
this._inTransitionToForeground = false;
|
|
642
657
|
logger.error(`uiActiveRequest failed: ${code} ${msg}`);
|
|
643
658
|
reject(`uiActiveRequest failed: ${code} ${msg}`);
|
|
644
659
|
}
|
|
@@ -651,10 +666,6 @@ class Lifecycle extends EventTarget {
|
|
|
651
666
|
|
|
652
667
|
_moveToBackground() {
|
|
653
668
|
if (window.cefQuery) {
|
|
654
|
-
if (this._inTransition || this._state === this.UiState.BACKGROUND || this._state === this.UiState.IN_TRANSITION_TO_BACKGROUND) {
|
|
655
|
-
sdkLogger.warn(`lifecycle moveToBackground: No need to transition to background, state: ${this._state} transition: ${this._inTransition}`);
|
|
656
|
-
return Promise.resolve(false);
|
|
657
|
-
}
|
|
658
669
|
// If audio sync is disabled, we only need to sync before remote player starts playing
|
|
659
670
|
if (!isAudioSyncConfigured()) {
|
|
660
671
|
remotePlayer._syncRemotePlayerWithLocalPlayer();
|
|
@@ -666,7 +677,7 @@ class Lifecycle extends EventTarget {
|
|
|
666
677
|
return this._moveToUiStandby();
|
|
667
678
|
}
|
|
668
679
|
|
|
669
|
-
this.
|
|
680
|
+
this._inTransitionToBackground = true;
|
|
670
681
|
return new Promise((resolve, reject) => {
|
|
671
682
|
const FCID = getFCID();
|
|
672
683
|
const logger = sdkLogger.withFields({ FCID });
|
|
@@ -684,7 +695,7 @@ class Lifecycle extends EventTarget {
|
|
|
684
695
|
if (this._remotePlayerApiVersion >= 2) {
|
|
685
696
|
message.type = "remotePlayer.play";
|
|
686
697
|
message.class = "remotePlayer";
|
|
687
|
-
message.switchMode = remotePlayer._isAudioSyncEnabled() ? SwitchMode.SEAMLESS : SwitchMode.NON_SEAMLESS;
|
|
698
|
+
message.switchMode = remotePlayer._isAudioSyncEnabled() && this._state !== this.UiState.BACKGROUND ? SwitchMode.SEAMLESS : SwitchMode.NON_SEAMLESS;
|
|
688
699
|
message.streamType = remotePlayer.textTrackVisibility ? (StreamType.AUDIO | StreamType.VIDEO | StreamType.SUBTITLE) : (StreamType.AUDIO | StreamType.VIDEO);
|
|
689
700
|
request = {
|
|
690
701
|
target: "TC",
|
|
@@ -707,14 +718,14 @@ class Lifecycle extends EventTarget {
|
|
|
707
718
|
onSuccess: () => {
|
|
708
719
|
const duration = Date.now() - timeBeforeSendingRequest;
|
|
709
720
|
logger.withFields({ duration }).log(`play completed successfully after ${duration} ms`);
|
|
710
|
-
this.
|
|
721
|
+
this._inTransitionToBackground = false;
|
|
711
722
|
timerId = clearTimer(timerId);
|
|
712
723
|
resolve();
|
|
713
724
|
},
|
|
714
725
|
onFailure: (code, msg) => {
|
|
715
726
|
const duration = Date.now() - timeBeforeSendingRequest;
|
|
716
727
|
logger.withFields({ duration }).log(`play failed after ${duration} ms. Error code: ${code}, error message: ${msg}`);
|
|
717
|
-
this.
|
|
728
|
+
this._inTransitionToBackground = false;
|
|
718
729
|
timerId = clearTimer(timerId);
|
|
719
730
|
reject(new SenzaError(code, msg));
|
|
720
731
|
}
|
|
@@ -724,7 +735,7 @@ class Lifecycle extends EventTarget {
|
|
|
724
735
|
const timeout = this._remotePlayerConfirmationTimeout + 1000;
|
|
725
736
|
timerId = setTimeout(() => {
|
|
726
737
|
logger.log(`play reached timeout of ${timeout} ms, canceling query id ${queryId}`);
|
|
727
|
-
this.
|
|
738
|
+
this._inTransitionToBackground = false;
|
|
728
739
|
window.cefQueryCancel(queryId);
|
|
729
740
|
reject(new SenzaError(6000, `play reached timeout of ${timeout} ms`));
|
|
730
741
|
}, timeout, queryId);
|
|
@@ -748,11 +759,11 @@ class Lifecycle extends EventTarget {
|
|
|
748
759
|
*/
|
|
749
760
|
moveToBackground() {
|
|
750
761
|
if (window.cefQuery) {
|
|
751
|
-
|
|
752
|
-
|
|
762
|
+
const inTransition = this._isInTransition();
|
|
763
|
+
if (inTransition || this._state === this.UiState.BACKGROUND || this._state === this.UiState.IN_TRANSITION_TO_BACKGROUND) {
|
|
764
|
+
sdkLogger.warn(`lifecycle moveToBackground: No need to transition to background, state: ${this._state} transition: ${inTransition}`);
|
|
753
765
|
return Promise.resolve(false);
|
|
754
766
|
}
|
|
755
|
-
|
|
756
767
|
if (remotePlayer._isSeekingByApplication) {
|
|
757
768
|
remotePlayer._targetSeekPlayingState = TargetPlayingState.PLAYING_ABR;
|
|
758
769
|
return Promise.resolve(true);
|
package/src/remotePlayer.js
CHANGED
|
@@ -68,7 +68,6 @@ function setPlaybackInfo(playbackInfo) {
|
|
|
68
68
|
* @typedef {Object} Config
|
|
69
69
|
* @property {string} preferredAudioLanguage
|
|
70
70
|
* @property {string} preferredSubtitlesLanguage
|
|
71
|
-
* @property {number} minSuggestedPresentationDelay - minimal delay allowed for live playback in seconds
|
|
72
71
|
* @property {boolean} autoPlay - (Not implemented yet) upon loading start playing automatically
|
|
73
72
|
*/
|
|
74
73
|
|
|
@@ -79,9 +78,9 @@ function setPlaybackInfo(playbackInfo) {
|
|
|
79
78
|
* @fires ended
|
|
80
79
|
* @fires error
|
|
81
80
|
* @fires onloadmodechange
|
|
82
|
-
* @fires playing
|
|
83
81
|
* @fires seeking (Not implemented yet)
|
|
84
82
|
* @fires seeked (Not implemented yet)
|
|
83
|
+
* @fires loadedmetadata (Not implemented yet)
|
|
85
84
|
*/
|
|
86
85
|
class RemotePlayer extends EventTarget {
|
|
87
86
|
constructor() {
|
|
@@ -92,8 +91,7 @@ class RemotePlayer extends EventTarget {
|
|
|
92
91
|
*/
|
|
93
92
|
this._config = {
|
|
94
93
|
preferredAudioLanguage: "",
|
|
95
|
-
preferredSubtitlesLanguage: ""
|
|
96
|
-
minSuggestedPresentationDelay: 0
|
|
94
|
+
preferredSubtitlesLanguage: ""
|
|
97
95
|
};
|
|
98
96
|
/**
|
|
99
97
|
* @type {string}
|
|
@@ -526,10 +524,10 @@ class RemotePlayer extends EventTarget {
|
|
|
526
524
|
|
|
527
525
|
/** setting values for properties in the player configuration using an object.
|
|
528
526
|
* If the config does not support a property this is a no-op.
|
|
529
|
-
* @param {
|
|
527
|
+
* @param {Object} props the object with all the different properties to change
|
|
530
528
|
* @example
|
|
531
529
|
* remotePlayer.configure({ preferredAudioLanguage: 'en-US' })
|
|
532
|
-
*
|
|
530
|
+
*
|
|
533
531
|
* */
|
|
534
532
|
configure(props) {
|
|
535
533
|
Object.entries(props).forEach(([key, value]) => {
|
|
@@ -722,7 +720,7 @@ class RemotePlayer extends EventTarget {
|
|
|
722
720
|
};
|
|
723
721
|
let waitForResponse = false;
|
|
724
722
|
if (this._remotePlayerApiVersion >= 2) {
|
|
725
|
-
message.switchMode = this._isAudioSyncEnabled() ? SwitchMode.SEAMLESS : SwitchMode.NON_SEAMLESS;
|
|
723
|
+
message.switchMode = this._isAudioSyncEnabled() && lifecycle.state !== lifecycle.UiState.BACKGROUND ? SwitchMode.SEAMLESS : SwitchMode.NON_SEAMLESS;
|
|
726
724
|
message.streamType = streamType;
|
|
727
725
|
waitForResponse = true;
|
|
728
726
|
|
|
@@ -898,9 +896,6 @@ class RemotePlayer extends EventTarget {
|
|
|
898
896
|
this._updateSeekListeners(video);
|
|
899
897
|
}
|
|
900
898
|
this._videoElement = video;
|
|
901
|
-
|
|
902
|
-
// Emit a custom event to notify about the attachment of the video element
|
|
903
|
-
this.dispatchEvent(new Event("videoelementattached"));
|
|
904
899
|
}
|
|
905
900
|
}
|
|
906
901
|
|
|
@@ -916,7 +911,7 @@ class RemotePlayer extends EventTarget {
|
|
|
916
911
|
/** Tell the remote player to load the given URL.
|
|
917
912
|
* @param {string} url url to load
|
|
918
913
|
* @param {number} [position] start position in seconds (if not provided, start from beginning (VOD) or current time (LTV))
|
|
919
|
-
|
|
914
|
+
* @returns {Promise}
|
|
920
915
|
* @throws {RemotePlayerError} error object contains code & msg
|
|
921
916
|
*
|
|
922
917
|
* */
|
|
@@ -981,11 +976,6 @@ class RemotePlayer extends EventTarget {
|
|
|
981
976
|
message.action = "load";
|
|
982
977
|
message.audioLanguage = audioLanguage;
|
|
983
978
|
message.subtitlesLanguage = subtitlesLanguage;
|
|
984
|
-
if (this.getConfiguration().minSuggestedPresentationDelay > 0) {
|
|
985
|
-
message.cloudPlayerParams = {
|
|
986
|
-
"mspd": this.getConfiguration().minSuggestedPresentationDelay
|
|
987
|
-
};
|
|
988
|
-
}
|
|
989
979
|
} else {
|
|
990
980
|
message.type = "setPlayableUri";
|
|
991
981
|
}
|
|
@@ -1143,8 +1133,13 @@ class RemotePlayer extends EventTarget {
|
|
|
1143
1133
|
|
|
1144
1134
|
// If seeking in progress, wait for seek to complete before playing
|
|
1145
1135
|
if (this._isSeekingByApplication) {
|
|
1146
|
-
|
|
1147
|
-
|
|
1136
|
+
if (lifecycle.state === lifecycle.UiState.FOREGROUND) {
|
|
1137
|
+
sdkLogger.info("application requesting play during seek. setting targetSeekPlayingState to PLAYING_UI");
|
|
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
|
+
}
|
|
1148
1143
|
return Promise.resolve(true);
|
|
1149
1144
|
}
|
|
1150
1145
|
/*
|
|
@@ -1666,9 +1661,7 @@ class RemotePlayer extends EventTarget {
|
|
|
1666
1661
|
}
|
|
1667
1662
|
}
|
|
1668
1663
|
|
|
1669
|
-
|
|
1670
|
-
if (this._remotePlayerApiVersion >= 2 && !this._isSeekingByPlatform && !this._isSeekingByApplication &&
|
|
1671
|
-
(lifecycle.state === lifecycle.UiState.FOREGROUND || lifecycle.state === lifecycle.UiState.IN_TRANSITION_TO_FOREGROUND)) {
|
|
1664
|
+
if (this._remotePlayerApiVersion >= 2 && !this._isSeekingByPlatform && !this._isSeekingByApplication) {
|
|
1672
1665
|
this._atomicSeek();
|
|
1673
1666
|
} else {
|
|
1674
1667
|
sdkLogger.info(`Seeking: skipping seeking event to currentTime: ${playbackPosition}, internalSeek: ${this._isSeekingByPlatform}, localPlayerSeek: ${this._isSeekingByApplication}, state: ${lifecycle.state}`);
|
|
@@ -1687,16 +1680,16 @@ class RemotePlayer extends EventTarget {
|
|
|
1687
1680
|
* */
|
|
1688
1681
|
async _atomicSeek() {
|
|
1689
1682
|
sdkLogger.info("Seeking: local video element seeking start while isPlaying: ", this._isPlaying);
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1683
|
+
if (this._isPlaying) {
|
|
1684
|
+
if (!lifecycle._inTransitionToForeground && (lifecycle._inTransitionToBackground || lifecycle.state === lifecycle.UiState.BACKGROUND || lifecycle.state === lifecycle.UiState.IN_TRANSITION_TO_BACKGROUND)) {
|
|
1685
|
+
sdkLogger.info("seek in background", this._isPlaying);
|
|
1686
|
+
this._targetSeekPlayingState = TargetPlayingState.PLAYING_ABR;
|
|
1687
|
+
} else {
|
|
1688
|
+
this._targetSeekPlayingState = TargetPlayingState.PLAYING_UI;
|
|
1689
|
+
}
|
|
1690
|
+
} else {
|
|
1691
|
+
this._targetSeekPlayingState = TargetPlayingState.PAUSED;
|
|
1692
|
+
}
|
|
1700
1693
|
|
|
1701
1694
|
// The platform could be currently syncing audio/video using playback rate. Reset when performing seek.
|
|
1702
1695
|
if (this._videoElement) {
|
|
@@ -1763,7 +1756,7 @@ class RemotePlayer extends EventTarget {
|
|
|
1763
1756
|
|
|
1764
1757
|
// If in TargetPlayingState.PAUSE, no need to resume.
|
|
1765
1758
|
// Resume without awaiting to avoid blocking the seek process anymore
|
|
1766
|
-
// In case where we aborted, we don't want to resume playback.
|
|
1759
|
+
// In case where we aborted (new load or unload called), we don't want to resume playback.
|
|
1767
1760
|
if (!this._abortSeeking) {
|
|
1768
1761
|
if (this._targetSeekPlayingState === TargetPlayingState.PLAYING_UI) {
|
|
1769
1762
|
if (!this._isAudioSyncEnabled()) {
|
|
@@ -1772,6 +1765,8 @@ class RemotePlayer extends EventTarget {
|
|
|
1772
1765
|
// resume audio play only if _isAudioSyncEnabled
|
|
1773
1766
|
this._play(StreamType.AUDIO);
|
|
1774
1767
|
} 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);
|
|
1775
1770
|
lifecycle._moveToBackground();
|
|
1776
1771
|
}
|
|
1777
1772
|
}
|
package/src/senzaShakaPlayer.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import * as shaka from "shaka-player";
|
|
2
2
|
import { remotePlayer, lifecycle, getPlatformInfo } from "./api";
|
|
3
3
|
import { sdkLogger, iso6393to1 } from "./utils";
|
|
4
|
-
import moment from "moment";
|
|
5
|
-
|
|
6
4
|
|
|
7
5
|
// Define custom error category
|
|
8
6
|
shaka.util.Error.Category.SENZA_PLAYER_ERROR = 50;
|
|
@@ -78,7 +76,7 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
78
76
|
* @private
|
|
79
77
|
* @type {number}
|
|
80
78
|
* @description Timeout in milliseconds to wait for playing event
|
|
81
|
-
* @default
|
|
79
|
+
* @default 3000
|
|
82
80
|
*/
|
|
83
81
|
_playingTimeout = 4000;
|
|
84
82
|
|
|
@@ -307,45 +305,6 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
307
305
|
|
|
308
306
|
}
|
|
309
307
|
|
|
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;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
308
|
/**
|
|
350
309
|
* Creates an instance of SenzaShakaPlayer, which is a subclass of shaka.Player.
|
|
351
310
|
*
|
|
@@ -373,38 +332,14 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
373
332
|
const playTimeout = getPlatformInfo()?.sessionInfo?.settings?.["ui-streamer"]?.playingEventTimeout;
|
|
374
333
|
this._playingTimeout = (playTimeout >= 0) ? playTimeout*1000 : this._playingTimeout;
|
|
375
334
|
|
|
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
|
-
|
|
383
335
|
// if video element is provided, add the listeres here. In this case ,there is no need to call attach.
|
|
384
336
|
if (videoElement) {
|
|
385
337
|
this._attach(videoElement);
|
|
386
338
|
sdkLogger.warn("SenzaShakaPlayer constructor Adding videoElement in the constructor is going to be deprecated in the future. Please use attach method instead.");
|
|
387
339
|
}
|
|
388
340
|
|
|
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
|
-
|
|
405
341
|
}
|
|
406
342
|
|
|
407
|
-
|
|
408
343
|
_attach(videoElement) {
|
|
409
344
|
this.videoElement = videoElement;
|
|
410
345
|
|
|
@@ -683,30 +618,16 @@ export class SenzaShakaPlayer extends shaka.Player {
|
|
|
683
618
|
|
|
684
619
|
// This callbakc will be activated when the manifest is loaded. It will trigger load of the remote player.
|
|
685
620
|
// This will ensure that the remote player is loaded only after the manifest is loaded by local player.
|
|
686
|
-
const responseFilterCallback = async (type
|
|
687
|
-
if (type === shaka.net.NetworkingEngine.RequestType.MANIFEST) {
|
|
621
|
+
const responseFilterCallback = async (type) => {
|
|
622
|
+
if (type === shaka.net.NetworkingEngine.RequestType.MANIFEST && !manifestLoadHandled) {
|
|
623
|
+
manifestLoadHandled = true;
|
|
688
624
|
try {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
const modifiedText = this._updateManifestDelayIfBelowMinimum(manifestText);
|
|
692
|
-
if (modifiedText) {
|
|
693
|
-
const responseData = new TextEncoder().encode(modifiedText).buffer;
|
|
694
|
-
response.data = responseData;
|
|
695
|
-
}
|
|
696
|
-
}
|
|
625
|
+
await this._remotePlayerLoad(url, startTime);
|
|
626
|
+
remoteLoadResolver();
|
|
697
627
|
} catch (error) {
|
|
698
|
-
|
|
628
|
+
remoteLoadRejecter(error);
|
|
699
629
|
}
|
|
700
630
|
|
|
701
|
-
if (!manifestLoadHandled) {
|
|
702
|
-
manifestLoadHandled = true;
|
|
703
|
-
try {
|
|
704
|
-
await this._remotePlayerLoad(url, startTime);
|
|
705
|
-
remoteLoadResolver();
|
|
706
|
-
} catch (error) {
|
|
707
|
-
remoteLoadRejecter(error);
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
631
|
}
|
|
711
632
|
};
|
|
712
633
|
|