senza-sdk 4.5.8 → 4.6.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/implementation.bundle.js +1 -1
- package/package.json +3 -1
- package/src/implementation/api.js +7 -5
- package/src/implementation/displayManager.js +7 -0
- package/src/implementation/lifecycle.js +105 -0
- package/src/implementation/remotePlayer.js +241 -27
- package/src/implementation/senzaShakaPlayer.js +22 -4
- package/src/implementation/utils.js +28 -1
- package/src/interface/overlay.js +0 -1
- package/src/interface/remotePlayer.js +44 -1
- package/src/interface/version.js +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SenzaShakaPlayer as SenzaShakaInterface, shaka } from "../interface/senzaShakaPlayer";
|
|
2
2
|
import * as shakaDebug from "shaka-player/dist/shaka-player.compiled.debug.js";
|
|
3
3
|
import { remotePlayer, lifecycle, getPlatformInfo } from "./api";
|
|
4
|
-
import { ONE_DAY_SECONDS } from "./remotePlayer.js";
|
|
4
|
+
import { ONE_DAY_SECONDS, VOD_INIT_SEEK_EPSILON_SEC } from "./remotePlayer.js";
|
|
5
5
|
import { sdkLogger, SwitchMode } from "./utils";
|
|
6
6
|
import moment from "moment";
|
|
7
7
|
import set from "lodash.set";
|
|
@@ -156,12 +156,19 @@ export class SenzaShakaPlayer extends SenzaShakaInterface {
|
|
|
156
156
|
_seekCounterAfterLoad = 0;
|
|
157
157
|
|
|
158
158
|
/**
|
|
159
|
-
* When true, the next `seeked` is Shaka jumping to live-edge
|
|
159
|
+
* When true, the next `seeked` is Shaka jumping to live-edge / VOD startTime after load; skip background pause logic.
|
|
160
160
|
* @private
|
|
161
161
|
* @type {boolean}
|
|
162
162
|
*/
|
|
163
163
|
_ignoreNextSeekedForInit = false;
|
|
164
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Start position (seconds) from the most recent load(). Used to ignore Shaka's VOD init seeking/seeked.
|
|
167
|
+
* @private
|
|
168
|
+
* @type {number}
|
|
169
|
+
*/
|
|
170
|
+
_loadStartPosition = 0;
|
|
171
|
+
|
|
165
172
|
/**
|
|
166
173
|
* Whether the player should call lifecycle.moveToForeground on pause, remote ended/error, unload, and destroy.
|
|
167
174
|
* Only when auto-background is enabled (including streamer overrides) and the UI moved to background via the
|
|
@@ -185,8 +192,16 @@ export class SenzaShakaPlayer extends SenzaShakaInterface {
|
|
|
185
192
|
this._ignoreNextSeekedForInit = false;
|
|
186
193
|
},
|
|
187
194
|
"seeking": () => {
|
|
188
|
-
//
|
|
189
|
-
|
|
195
|
+
// Ignore the first seeking after load when it is Shaka's initialization jump:
|
|
196
|
+
// - Live: currentTime is a UTC wall-clock time (> one day in seconds)
|
|
197
|
+
// - VOD: currentTime is within epsilon of this._loadStartPosition
|
|
198
|
+
const isFirstSeekAfterLoadAtZero = this._seekCounterAfterLoad < 1 && this._loadStartedAtZero;
|
|
199
|
+
const isLiveInitSeek = isFirstSeekAfterLoadAtZero && this.videoElement.currentTime > ONE_DAY_SECONDS;
|
|
200
|
+
const isVodInitSeek = isFirstSeekAfterLoadAtZero
|
|
201
|
+
&& this._loadStartPosition > 0
|
|
202
|
+
&& Math.abs(this.videoElement.currentTime - this._loadStartPosition) <= VOD_INIT_SEEK_EPSILON_SEC;
|
|
203
|
+
if (isLiveInitSeek || isVodInitSeek) {
|
|
204
|
+
sdkLogger.info("senzaShakaPlayer seeking: ignoring next seeked for init");
|
|
190
205
|
this._ignoreNextSeekedForInit = true;
|
|
191
206
|
} else {
|
|
192
207
|
// Another seeking before seeked means this is no longer the load initialization jump.
|
|
@@ -820,6 +835,9 @@ export class SenzaShakaPlayer extends SenzaShakaInterface {
|
|
|
820
835
|
startTime = -minInitialLiveOffset;
|
|
821
836
|
}
|
|
822
837
|
|
|
838
|
+
// Used to ignore Shaka's init seeking/seeked when currentTime matches load start.
|
|
839
|
+
this._loadStartPosition = startTime ?? 0;
|
|
840
|
+
|
|
823
841
|
// This callback will be activated when the manifest is loaded. It will trigger load of the remote player.
|
|
824
842
|
// This will ensure that the remote player is loaded only after the manifest is loaded by local player.
|
|
825
843
|
const responseFilterCallback = async (type, response) => {
|
|
@@ -140,6 +140,26 @@ export function isAudioSyncConfigured() {
|
|
|
140
140
|
return clientUiAudioSettings?.enabled && clientUiAudioSettings?.from_cdn && clientUiAudioSettings?.ui_sync_enabled;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
/** Dual decode is enabled only when both the client capability and the common settings report it as enabled.
|
|
144
|
+
* @returns {boolean}
|
|
145
|
+
*/
|
|
146
|
+
export function isDualDecodeEnabled() {
|
|
147
|
+
const sessionInfoObj = sessionInfo.sessionInfoObj;
|
|
148
|
+
return !!(sessionInfoObj?.capabilities?.dualDecode?.enabled && sessionInfoObj?.settings?.common?.dualDecode?.enabled);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Get the ABR surface size that dual decode video should be scaled to before being sent to the client.
|
|
152
|
+
* The values are read from the client capabilities and coerced to numbers (the platform may report them as strings).
|
|
153
|
+
* @returns {{width: number, height: number}}
|
|
154
|
+
*/
|
|
155
|
+
export function getDualDecodeAbrSurfaceSize() {
|
|
156
|
+
const abrSurfaceSize = sessionInfo.sessionInfoObj?.capabilities?.dualDecode?.abrSurfaceSize;
|
|
157
|
+
return {
|
|
158
|
+
width: Number(abrSurfaceSize?.width ?? 1280),
|
|
159
|
+
height: Number(abrSurfaceSize?.height ?? 720)
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
143
163
|
export function isSubtitlesTranslationAllowed() {
|
|
144
164
|
return sessionInfo.sessionInfoObj?.settings?.["ui-streamer"]?.allowSubtitlesTranslation === true;
|
|
145
165
|
}
|
|
@@ -181,7 +201,14 @@ export const StreamType = Object.freeze({
|
|
|
181
201
|
|
|
182
202
|
export const SwitchMode = Object.freeze({
|
|
183
203
|
NON_SEAMLESS: 0,
|
|
184
|
-
SEAMLESS: 1
|
|
204
|
+
SEAMLESS: 1,
|
|
205
|
+
DUAL_DECODE: 2
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
/** Layer on which dual-decode ABR video is composited (remotePlayer.setVideoRect). */
|
|
209
|
+
export const VideoLayer = Object.freeze({
|
|
210
|
+
FRONT: 0,
|
|
211
|
+
BACK: 1
|
|
185
212
|
});
|
|
186
213
|
|
|
187
214
|
export const SeekState = Object.freeze({
|
package/src/interface/overlay.js
CHANGED
|
@@ -10,7 +10,6 @@ import { noop } from "./utils.js";
|
|
|
10
10
|
/**
|
|
11
11
|
* Overlay is a singleton class that manages displaying UI frames as image overlays. The image can be displayed over background video playback.
|
|
12
12
|
* It can be used in any lifecycle state.
|
|
13
|
-
* @private
|
|
14
13
|
* @fires error
|
|
15
14
|
*/
|
|
16
15
|
class Overlay extends EventTarget {
|
|
@@ -132,6 +132,8 @@ export class RemotePlayerError extends Error {
|
|
|
132
132
|
* | 6502 | Player | unload() was called while previous unload/load was still in progress |
|
|
133
133
|
* | 6503 | Player | The remote player api call has invalid parameters |
|
|
134
134
|
* | 6504 | Player | The remote player api internal error |
|
|
135
|
+
* | 6505 | Player | setVideoRect() was called with an invalid rectangle (out of the window bounds or negative) |
|
|
136
|
+
* | 6506 | Player | setVideoRect() or setVideoFullscreen() was called when dual decode is not enabled |
|
|
135
137
|
* | 8001 | Player | Error pulling manifest. bad parameters |
|
|
136
138
|
* | 8002 | Player | Error pulling manifest. filters returned no data |
|
|
137
139
|
* | 8003 | Player | Error pulling manifest. fetch error |
|
|
@@ -246,6 +248,19 @@ class RemotePlayer extends EventTarget {
|
|
|
246
248
|
SPOKEN_SUBTITLES: "9"
|
|
247
249
|
};
|
|
248
250
|
|
|
251
|
+
/**
|
|
252
|
+
* @typedef {Object} VideoLayer
|
|
253
|
+
* @property {number} FRONT - The ABR video is rendered in front of the UI video.
|
|
254
|
+
* @property {number} BACK - The ABR video is rendered behind the UI video.
|
|
255
|
+
*/
|
|
256
|
+
/** The layer on which the remote player (ABR) video is rendered when dual decode is enabled.
|
|
257
|
+
* @type {VideoLayer}
|
|
258
|
+
*/
|
|
259
|
+
VideoLayer = Object.freeze({
|
|
260
|
+
FRONT: 0,
|
|
261
|
+
BACK: 1
|
|
262
|
+
});
|
|
263
|
+
|
|
249
264
|
/** get the player configuration.
|
|
250
265
|
* @returns {Config}
|
|
251
266
|
* */
|
|
@@ -325,7 +340,7 @@ class RemotePlayer extends EventTarget {
|
|
|
325
340
|
return noop("RemotePlayer.pause");
|
|
326
341
|
}
|
|
327
342
|
|
|
328
|
-
/** Stop playback
|
|
343
|
+
/** Stop playback of all streams (audio, video and subtitles).
|
|
329
344
|
* @returns {Promise}
|
|
330
345
|
* @throws {RemotePlayerError} error object contains code & msg
|
|
331
346
|
* */
|
|
@@ -333,6 +348,34 @@ class RemotePlayer extends EventTarget {
|
|
|
333
348
|
return noop("RemotePlayer.stop");
|
|
334
349
|
}
|
|
335
350
|
|
|
351
|
+
/** Set the position and size of the remote player (ABR) video on screen, or make it fullscreen.
|
|
352
|
+
* Only available when dual decode is enabled, otherwise throws.
|
|
353
|
+
* The given rectangle is expressed in the UI coordinate space (window.innerWidth/window.innerHeight)
|
|
354
|
+
* and is validated and scaled to the client's ABR surface size before being sent to the client.
|
|
355
|
+
* @param {Object} rect
|
|
356
|
+
* @param {number} [rect.x] horizontal position in px (UI coordinate space)
|
|
357
|
+
* @param {number} [rect.y] vertical position in px (UI coordinate space)
|
|
358
|
+
* @param {number} [rect.width] width in px (UI coordinate space)
|
|
359
|
+
* @param {number} [rect.height] height in px (UI coordinate space)
|
|
360
|
+
* @param {boolean} [rect.fullScreen=false] when true, the video is rendered fullscreen and the rect is ignored
|
|
361
|
+
* @param {VideoLayer} [rect.layer=VideoLayer.FRONT] which layer the ABR video should be rendered on
|
|
362
|
+
* @returns {Promise}
|
|
363
|
+
* @throws {RemotePlayerError} error object contains code & msg
|
|
364
|
+
*/
|
|
365
|
+
setVideoRect(rect) {
|
|
366
|
+
return noop("RemotePlayer.setVideoRect", rect);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/** Make the remote player (ABR) video fullscreen on the given layer.
|
|
370
|
+
* Only available when dual decode is enabled, otherwise throws.
|
|
371
|
+
* @param {VideoLayer} [layer=VideoLayer.FRONT] which layer the ABR video should be rendered on
|
|
372
|
+
* @returns {Promise}
|
|
373
|
+
* @throws {RemotePlayerError} error object contains code & msg
|
|
374
|
+
*/
|
|
375
|
+
setVideoFullscreen(layer = this.VideoLayer.FRONT) {
|
|
376
|
+
return noop("RemotePlayer.setVideoFullscreen", layer);
|
|
377
|
+
}
|
|
378
|
+
|
|
336
379
|
/** Get the currently loaded uri, or empty string is player is not loaded.
|
|
337
380
|
* @returns {string} loaded uri
|
|
338
381
|
* @throws {RemotePlayerError} error object contains code & msg
|
package/src/interface/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "4.
|
|
1
|
+
export const version = "4.6.0";
|