senza-sdk 4.3.1-ca3d96f.0 → 4.3.1-e113d43.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 +8 -9
- package/src/api.js +2 -14
- package/src/implementation/api.js +4 -0
- package/src/implementation/lifecycle.js +10 -9
- package/src/implementation/messageManager.js +33 -0
- package/src/implementation/platformManager.js +19 -0
- package/src/implementation/remotePlayer.js +215 -17
- package/src/implementation/senzaShakaPlayer.js +127 -104
- package/src/interface/alarmManager.js +21 -28
- package/src/interface/devSequence.js +0 -35
- package/src/interface/deviceManager.js +21 -30
- package/src/interface/lifecycle.js +39 -44
- package/src/interface/messageManager.js +27 -34
- package/src/interface/platformManager.js +5 -11
- package/src/interface/remotePlayer.js +180 -209
- package/src/interface/senzaShakaPlayer.js +5 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "senza-sdk",
|
|
3
|
-
"version": "4.3.1-
|
|
3
|
+
"version": "4.3.1-e113d43.0",
|
|
4
4
|
"main": "./src/api.js",
|
|
5
5
|
"description": "API for Senza application",
|
|
6
6
|
"license": "MIT",
|
|
@@ -46,19 +46,18 @@
|
|
|
46
46
|
"global": {
|
|
47
47
|
"branches": 88,
|
|
48
48
|
"functions": 92.36,
|
|
49
|
-
"lines": 93.
|
|
50
|
-
"statements": 93.
|
|
49
|
+
"lines": 93.83,
|
|
50
|
+
"statements": 93.81
|
|
51
51
|
},
|
|
52
52
|
"src/interface": {
|
|
53
|
-
"branches":
|
|
54
|
-
"functions":
|
|
55
|
-
"lines":
|
|
56
|
-
"statements":
|
|
53
|
+
"branches": 69.38,
|
|
54
|
+
"functions": 52.72,
|
|
55
|
+
"lines": 71.95,
|
|
56
|
+
"statements": 72.16
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"shaka-player": "^4.12.5"
|
|
62
|
-
"moment": "^2.30.1"
|
|
61
|
+
"shaka-player": "^4.12.5"
|
|
63
62
|
}
|
|
64
63
|
}
|
package/src/api.js
CHANGED
|
@@ -4,11 +4,6 @@ import { Lifecycle, RemotePlayer, DeviceManager, PlatformManager, AlarmManager,
|
|
|
4
4
|
|
|
5
5
|
const { version } = pack;
|
|
6
6
|
|
|
7
|
-
typeof document !== "undefined" && document.addEventListener("keydown", (event) => {
|
|
8
|
-
sdkLogger.log(`Got ${event.key} key`);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
|
|
12
7
|
let authToken;
|
|
13
8
|
|
|
14
9
|
/** @namespace auth
|
|
@@ -198,7 +193,6 @@ export function getClientAssertion() {
|
|
|
198
193
|
|
|
199
194
|
/**
|
|
200
195
|
* @module
|
|
201
|
-
* @private
|
|
202
196
|
* @type {Lifecycle}
|
|
203
197
|
* @example
|
|
204
198
|
* import { lifecycle } from "senza-sdk";
|
|
@@ -209,7 +203,6 @@ let lifecycle;
|
|
|
209
203
|
|
|
210
204
|
/**
|
|
211
205
|
* @module
|
|
212
|
-
* @private
|
|
213
206
|
* @type {RemotePlayer}
|
|
214
207
|
* @example
|
|
215
208
|
* import { init, remotePlayer } from "senza-sdk";
|
|
@@ -228,7 +221,6 @@ let remotePlayer;
|
|
|
228
221
|
|
|
229
222
|
/**
|
|
230
223
|
* @module
|
|
231
|
-
* @private
|
|
232
224
|
* @type {AlarmManager}
|
|
233
225
|
* @example
|
|
234
226
|
* import { alarmManager } from "senza-sdk";
|
|
@@ -239,7 +231,6 @@ let alarmManager;
|
|
|
239
231
|
|
|
240
232
|
/**
|
|
241
233
|
* @module
|
|
242
|
-
* @private
|
|
243
234
|
* @type {DeviceManager}
|
|
244
235
|
* @example
|
|
245
236
|
* import { deviceManager } from "senza-sdk";
|
|
@@ -255,7 +246,6 @@ let deviceManager;
|
|
|
255
246
|
|
|
256
247
|
/**
|
|
257
248
|
* @module
|
|
258
|
-
* @private
|
|
259
249
|
* @type {PlatformManager}
|
|
260
250
|
* @example
|
|
261
251
|
* import { platformManager } from "senza-sdk";
|
|
@@ -264,11 +254,11 @@ let deviceManager;
|
|
|
264
254
|
*
|
|
265
255
|
* @return {PlatformManager} pointer to the PlatformManager singleton
|
|
266
256
|
*/
|
|
267
|
-
let platformManager;
|
|
268
257
|
|
|
258
|
+
|
|
259
|
+
let platformManager;
|
|
269
260
|
/**
|
|
270
261
|
* @module
|
|
271
|
-
* @private
|
|
272
262
|
* @type {MessageManager}
|
|
273
263
|
* @example
|
|
274
264
|
* import { MessageManager } from "senza-sdk";
|
|
@@ -282,7 +272,6 @@ let messageManager;
|
|
|
282
272
|
* ShakaPlayer subclass of Shaka that handles both local and remote playback.
|
|
283
273
|
*
|
|
284
274
|
* @class ShakaPlayer
|
|
285
|
-
* @private
|
|
286
275
|
* @type {new|ShakaPlayer}
|
|
287
276
|
* @example
|
|
288
277
|
* import { ShakaPlayer } from "senza-sdk";
|
|
@@ -302,7 +291,6 @@ let ShakaPlayerImplementation;
|
|
|
302
291
|
|
|
303
292
|
/**
|
|
304
293
|
* @module
|
|
305
|
-
* @private
|
|
306
294
|
* @type {shaka}
|
|
307
295
|
*/
|
|
308
296
|
let shakaImplementation;
|
|
@@ -8,6 +8,10 @@ let authToken;
|
|
|
8
8
|
const API_VERSION = "1.0";
|
|
9
9
|
let interfaceVersion;
|
|
10
10
|
|
|
11
|
+
typeof document !== "undefined" && document.addEventListener("keydown", (event) => {
|
|
12
|
+
sdkLogger.log(`Got ${event.key} key`);
|
|
13
|
+
});
|
|
14
|
+
|
|
11
15
|
/** @namespace auth
|
|
12
16
|
*@example
|
|
13
17
|
* import { auth } from "senza-sdk";
|
|
@@ -20,6 +20,12 @@ const DEFAULT_AUTO_BACKGROUND_VIDEO_DELAY = 30;
|
|
|
20
20
|
const DEFAULT_AUTO_BACKGROUND_UI_DELAY = -1;
|
|
21
21
|
const DEFAULT_AUTO_BACKGROUND_ENABLED = false;
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Lifecycle is a singleton class that manages the application lifecycle states.<br>
|
|
25
|
+
* @fires onstatechange
|
|
26
|
+
* @fires userinactivity
|
|
27
|
+
* @fires userdisconnected
|
|
28
|
+
*/
|
|
23
29
|
class Lifecycle extends LifecycleInterface {
|
|
24
30
|
constructor() {
|
|
25
31
|
super();
|
|
@@ -106,8 +112,7 @@ class Lifecycle extends LifecycleInterface {
|
|
|
106
112
|
});
|
|
107
113
|
}
|
|
108
114
|
|
|
109
|
-
/**
|
|
110
|
-
* @private Initialize the lifecycle
|
|
115
|
+
/** @private Initialize the lifecycle
|
|
111
116
|
* @param {Object} uiStreamerSettings - UI-streamer portion of the settings taken from session info
|
|
112
117
|
* @param {Object} [uiStreamerSettings.autoBackground] - Auto background mode configuration
|
|
113
118
|
* @param {boolean} [uiStreamerSettings.autoBackground.enabled=false] - Enable/disable auto background
|
|
@@ -204,16 +209,14 @@ class Lifecycle extends LifecycleInterface {
|
|
|
204
209
|
}
|
|
205
210
|
}
|
|
206
211
|
|
|
207
|
-
/**
|
|
208
|
-
* @private Checks if auto background is enabled including overrides.
|
|
212
|
+
/** @private Checks if auto background is enabled including overrides.
|
|
209
213
|
* @returns {boolean}
|
|
210
214
|
*/
|
|
211
215
|
_isAutoBackgroundEnabled() {
|
|
212
216
|
return this._autoBackgroundOverrides?.enabled ?? this._autoBackground;
|
|
213
217
|
}
|
|
214
218
|
|
|
215
|
-
/**
|
|
216
|
-
* @private Gets the auto background video delay including overrides.
|
|
219
|
+
/** @private Gets the auto background video delay including overrides.
|
|
217
220
|
* @returns {number}
|
|
218
221
|
*/
|
|
219
222
|
_getAutoBackgroundOnVideoDelay() {
|
|
@@ -224,8 +227,7 @@ class Lifecycle extends LifecycleInterface {
|
|
|
224
227
|
return this._autoBackgroundOnVideoDelay;
|
|
225
228
|
}
|
|
226
229
|
|
|
227
|
-
/**
|
|
228
|
-
* @private Gets the auto background UI delay including overrides.
|
|
230
|
+
/** @private Gets the auto background UI delay including overrides.
|
|
229
231
|
* @returns {number}
|
|
230
232
|
*/
|
|
231
233
|
_getAutoBackgroundOnUIDelay() {
|
|
@@ -288,7 +290,6 @@ class Lifecycle extends LifecycleInterface {
|
|
|
288
290
|
}
|
|
289
291
|
|
|
290
292
|
/**
|
|
291
|
-
* @private
|
|
292
293
|
* This method moves the application into standby mode, i.e. last ui frame is displayed and ui resources are released.
|
|
293
294
|
* It should be called whenever the application wishes to go into standby mode and release resources.
|
|
294
295
|
* @example
|
|
@@ -1,8 +1,35 @@
|
|
|
1
1
|
import { MessageManager as MessageManagerInterface } from "../interface/messageManager";
|
|
2
2
|
import { getFCID, sdkLogger } from "./utils";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* MessageManager is a singleton class that manages the external messages received by the application. It fires custom events as "message" with the payload as the content
|
|
6
|
+
* @fires MessageManager#message
|
|
7
|
+
*/
|
|
8
|
+
|
|
4
9
|
class MessageManager extends MessageManagerInterface {
|
|
5
10
|
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {object} MessageDetails - object which contains the content of the message
|
|
13
|
+
* @property {string} eventName - The name of the event message, a property of MessageDetails
|
|
14
|
+
* @property {object} payload - The payload for this event, a property of MessageDetails
|
|
15
|
+
* @property {string} fcid - The flow context for this message, a property of MessageDetails
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* message event
|
|
20
|
+
*
|
|
21
|
+
* @event MessageManager#message
|
|
22
|
+
* @type {CustomEvent}
|
|
23
|
+
* @property {MessageDetails} detail - object containing data related to the event:
|
|
24
|
+
|
|
25
|
+
*
|
|
26
|
+
* @description Fired when an external event arrives. This is a generic handler for all messages received for any registered group <br>
|
|
27
|
+
* @example
|
|
28
|
+
* messageManager.addEventListener("message", (e) => {
|
|
29
|
+
* console.log("message arrived with data", e.detail);
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
*/
|
|
6
33
|
constructor() {
|
|
7
34
|
super();
|
|
8
35
|
typeof document !== "undefined" && document.addEventListener("hs/externalEvent", (e) => {
|
|
@@ -11,6 +38,12 @@ class MessageManager extends MessageManagerInterface {
|
|
|
11
38
|
});
|
|
12
39
|
}
|
|
13
40
|
|
|
41
|
+
/** Register to specific group(s). This function replaces the previously registered groups
|
|
42
|
+
* @param {Array<String>} groups group events to receive messages.
|
|
43
|
+
* @return {Promise} Promise which is resolved when the registerGroups command has been successfully processed.
|
|
44
|
+
* Failure to process the registerGroups command will result in the promise being rejected.
|
|
45
|
+
* messageManager.registerGroups(["A","B"]);
|
|
46
|
+
* */
|
|
14
47
|
async registerGroups(groups) {
|
|
15
48
|
sdkLogger.log(`register called for ${groups}`);
|
|
16
49
|
return new Promise((resolve, reject) => {
|
|
@@ -2,12 +2,24 @@ import { PlatformManager as PlatformManagerInterface } from "../interface/platfo
|
|
|
2
2
|
import { sdkLogger } from "./utils";
|
|
3
3
|
import { sessionInfo } from "./SessionInfo";
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* PlatformManager is a singleton class that manages the platform
|
|
8
|
+
*/
|
|
5
9
|
class PlatformManager extends PlatformManagerInterface {
|
|
6
10
|
|
|
7
11
|
constructor() {
|
|
8
12
|
super();
|
|
9
13
|
}
|
|
10
14
|
|
|
15
|
+
/**
|
|
16
|
+
* @returns {Object} appConfig object
|
|
17
|
+
* @property {String[]} territories - a list of territories configured for the tenant.
|
|
18
|
+
* if the list is undefined or empty - there are no restrictions.
|
|
19
|
+
* @example
|
|
20
|
+
* import { platformManager } from "senza-sdk";
|
|
21
|
+
* const appConfig = platformManager.appConfig
|
|
22
|
+
* */
|
|
11
23
|
get appConfig() {
|
|
12
24
|
const sessionInfoObj = sessionInfo.sessionInfoObj;
|
|
13
25
|
const appConfig = sessionInfoObj.homeSessionInfo?.["appConfig"] || {};
|
|
@@ -15,6 +27,13 @@ class PlatformManager extends PlatformManagerInterface {
|
|
|
15
27
|
return appConfig;
|
|
16
28
|
}
|
|
17
29
|
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
* @param {string} timezone the timezone to set to
|
|
33
|
+
* the format of the timezone is according to the standard TZ identifier
|
|
34
|
+
* (e.g. America/Los_Angeles, Asia/Tokyo, Europe/Brussels)
|
|
35
|
+
* for a full list of TZ identifiers, see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
|
36
|
+
*/
|
|
18
37
|
setTimezone(timezone) {
|
|
19
38
|
if (window.cefQuery) {
|
|
20
39
|
const request = { message: JSON.stringify({ type: "setTimeZone", timezone }), waitForResponse: false, target: "UI-Streamer" };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import { RemotePlayer as RemotePlayerInterface, RemotePlayerError as RemotePlayerErrorInterface, Config } from "../interface/remotePlayer";
|
|
1
|
+
import { RemotePlayer as RemotePlayerInterface } from "../interface/remotePlayer";
|
|
3
2
|
import {
|
|
4
3
|
getFCID,
|
|
5
4
|
isAudioSyncConfigured,
|
|
@@ -29,7 +28,11 @@ const cloneDeep = (element) => {
|
|
|
29
28
|
return JSON.parse(JSON.stringify(element));
|
|
30
29
|
};
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
// TODO: check that the link below to the error list is working on dashreadme
|
|
32
|
+
/** Error object to be thrown on remotePlayer api failures.
|
|
33
|
+
* [See error list]{@link RemotePlayer#error}
|
|
34
|
+
*/
|
|
35
|
+
export class RemotePlayerError extends Error {
|
|
33
36
|
constructor(code, message) {
|
|
34
37
|
super(message);
|
|
35
38
|
this.code = code;
|
|
@@ -61,6 +64,25 @@ function setPlaybackInfo(playbackInfo) {
|
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @typedef {Object} Config
|
|
70
|
+
* @property {string} preferredAudioLanguage
|
|
71
|
+
* @property {string} preferredSubtitlesLanguage
|
|
72
|
+
* @property {boolean} autoPlay - (Not implemented yet) upon loading start playing automatically
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* RemotePlayer a singleton class to communicate with remote player
|
|
77
|
+
* @fires timeupdate
|
|
78
|
+
* @fires tracksupdate
|
|
79
|
+
* @fires ended
|
|
80
|
+
* @fires error
|
|
81
|
+
* @fires onloadmodechange
|
|
82
|
+
* @fires seeking (Not implemented yet)
|
|
83
|
+
* @fires seeked (Not implemented yet)
|
|
84
|
+
* @fires loadedmetadata (Not implemented yet)
|
|
85
|
+
*/
|
|
64
86
|
class RemotePlayer extends RemotePlayerInterface {
|
|
65
87
|
constructor() {
|
|
66
88
|
super();
|
|
@@ -70,8 +92,7 @@ class RemotePlayer extends RemotePlayerInterface {
|
|
|
70
92
|
*/
|
|
71
93
|
this._config = {
|
|
72
94
|
preferredAudioLanguage: "",
|
|
73
|
-
preferredSubtitlesLanguage: ""
|
|
74
|
-
minSuggestedPresentationDelay: 0
|
|
95
|
+
preferredSubtitlesLanguage: ""
|
|
75
96
|
};
|
|
76
97
|
/**
|
|
77
98
|
* @type {string}
|
|
@@ -141,11 +162,49 @@ class RemotePlayer extends RemotePlayerInterface {
|
|
|
141
162
|
*/
|
|
142
163
|
this._isPlaying = false;
|
|
143
164
|
|
|
165
|
+
/**
|
|
166
|
+
* @event RemotePlayer#canplay
|
|
167
|
+
* @description canplay event will be dispatched when the remote player can start play the event
|
|
168
|
+
* @example
|
|
169
|
+
* remotePlayer.addEventListener("canplay", () => {
|
|
170
|
+
* console.info("remotePlayer canplay");
|
|
171
|
+
* remotePlayer.play();
|
|
172
|
+
* });
|
|
173
|
+
* */
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @event RemotePlayer#playing
|
|
177
|
+
* @description playing event will be dispatched when the remote player started playback of the first audio frame. This event can be used to synchronize the local player with the remote player.
|
|
178
|
+
* @example
|
|
179
|
+
* remotePlayer.addEventListener("playing", () => {
|
|
180
|
+
* console.info("remotePlayer playing");
|
|
181
|
+
* });
|
|
182
|
+
* */
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @event RemotePlayer#loadedmetadata
|
|
186
|
+
* @description loadedmetadata event will be dispatched when the remote player metadata is loaded
|
|
187
|
+
* and the audio/video tracks are available
|
|
188
|
+
* @example
|
|
189
|
+
* remotePlayer.addEventListener("loadedmetadata", () => {
|
|
190
|
+
* console.info("remotePlayer loadedmetadata", remotePlayer.getAudioTracks(), remotePlayer.getTextTracks());
|
|
191
|
+
* });
|
|
192
|
+
* */
|
|
144
193
|
typeof document !== "undefined" && document.addEventListener("hs/remotePlayerEvent", (e) => {
|
|
145
194
|
sdkLogger.info("Got hs/remotePlayerEvent event with detail", JSON.stringify(e?.detail));
|
|
146
195
|
this.dispatchEvent(new Event(e?.detail?.eventName));
|
|
147
196
|
});
|
|
148
197
|
|
|
198
|
+
/**
|
|
199
|
+
*
|
|
200
|
+
* @event RemotePlayer#timeupdate
|
|
201
|
+
* @example
|
|
202
|
+
* remotePlayer.addEventListener("timeupdate", () => {
|
|
203
|
+
* console.info("remotePlayer timeupdate", remotePlayer.currentTime);
|
|
204
|
+
* localPlayer.getMediaElement().currentTime = remotePlayer.currentTime || 0;
|
|
205
|
+
* });
|
|
206
|
+
*
|
|
207
|
+
*/
|
|
149
208
|
typeof document !== "undefined" && document.addEventListener("hs/playbackInfoEvent", () => {
|
|
150
209
|
sdkLogger.info("Got hs/playbackInfoEvent");
|
|
151
210
|
// When attached, the sdk controls the synchronization between the local and remote player.
|
|
@@ -159,6 +218,15 @@ class RemotePlayer extends RemotePlayerInterface {
|
|
|
159
218
|
}
|
|
160
219
|
});
|
|
161
220
|
|
|
221
|
+
/**
|
|
222
|
+
*
|
|
223
|
+
* @event RemotePlayer#tracksupdate
|
|
224
|
+
* @example
|
|
225
|
+
* remotePlayer.addEventListener("tracksupdate", () => {
|
|
226
|
+
* console.info("remotePlayer tracksupdate", remotePlayer.getAudioTracks(), remotePlayer.getTextTracks());
|
|
227
|
+
* });
|
|
228
|
+
*
|
|
229
|
+
*/
|
|
162
230
|
typeof document !== "undefined" && document.addEventListener("hs/playback", (e) => {
|
|
163
231
|
sdkLogger.info("Got hs/playback event with detail", JSON.stringify(e?.detail));
|
|
164
232
|
this._availabilityStartTime = e?.detail?.availabilityStartTime;
|
|
@@ -166,6 +234,13 @@ class RemotePlayer extends RemotePlayerInterface {
|
|
|
166
234
|
this.dispatchEvent(new Event("tracksupdate"));
|
|
167
235
|
});
|
|
168
236
|
|
|
237
|
+
/**
|
|
238
|
+
* @event RemotePlayer#ended
|
|
239
|
+
* @example
|
|
240
|
+
* remotePlayer.addEventListener("ended", () => {
|
|
241
|
+
* console.info("remotePlayer ended");
|
|
242
|
+
* });
|
|
243
|
+
*/
|
|
169
244
|
typeof document !== "undefined" && document.addEventListener("hs/EOS", () => {
|
|
170
245
|
sdkLogger.info("Got hs/EOS event");
|
|
171
246
|
this.dispatchEvent(new Event("ended"));
|
|
@@ -198,7 +273,72 @@ class RemotePlayer extends RemotePlayerInterface {
|
|
|
198
273
|
sdkLogger.info(`Adding ${event.detail} seconds, previousTime=${previousCurrentTime} currentTime=${this._videoElement.currentTime}`);
|
|
199
274
|
});
|
|
200
275
|
|
|
201
|
-
|
|
276
|
+
/**
|
|
277
|
+
*
|
|
278
|
+
* @event RemotePlayer#error
|
|
279
|
+
* @type {object}
|
|
280
|
+
* @property {int} detail.errorCode
|
|
281
|
+
* @property {string} detail.message
|
|
282
|
+
*
|
|
283
|
+
* @see Possible error codes:
|
|
284
|
+
*
|
|
285
|
+
* | Code | Domain | Description |
|
|
286
|
+
* | :-------- | :---------------- | :-----------------------------------------------------------------------------------------------|
|
|
287
|
+
* | 23 | Player | load() failed due to remote player initialization error |
|
|
288
|
+
* | 98 | Player | load() failed due to remote player failure to send message to the client |
|
|
289
|
+
* | 99 | Player | load() failed due to remote player reporting invalid message |
|
|
290
|
+
* | 1000 | Encrypted content | Failed to create or initialise the CDM |
|
|
291
|
+
* | 1001 | Encrypted content | Failed to create a CDM session |
|
|
292
|
+
* | 1002 | Encrypted content | CDM failed to generate a license request |
|
|
293
|
+
* | 1003 | Encrypted content | The CDM rejected the license server response |
|
|
294
|
+
* | 1004 | Encrypted content | The CDM rejected the license server certificate |
|
|
295
|
+
* | 1005 | Encrypted content | All keys in the license have expired |
|
|
296
|
+
* | 1006 | Encrypted content | Output device is incompatible with the license requirements (HDCP) |
|
|
297
|
+
* | 1007 | Encrypted content | The device has been revoked |
|
|
298
|
+
* | 1008 | Encrypted content | The device secrets aren't available |
|
|
299
|
+
* | 1009 | Encrypted content | Keys are loaded but the KID requested by playback isn't found. The app has likely issued a license for the wrong content or there is a mismatch between the KIDs in the license and the data plane |
|
|
300
|
+
* | 1010 | Encrypted content | The CDM failed to provision, therefore it is not possible to play encrypted content |
|
|
301
|
+
* | 1100 | Encrypted content | The CDM session has already received a license response. The app has likely issued 2, or more, license responses for the same request. The subsequent licenses will be ignored so this error is informational only |
|
|
302
|
+
* | 1101 | Encrypted content | The license has been rejected since an error was received by the CDM. The app has likely sent a non-200 code to `WriteLicenseResponse` |
|
|
303
|
+
* | 1102 | Encrypted content | A license response wasn't received from the app within a pre-defined timeout |
|
|
304
|
+
* | 1103 | Encrypted content | The CDM session associated with this license response is in an invalid state. This is an internal Senza platform error |
|
|
305
|
+
* | 1104 | Encrypted content | The CDM failed to send a license request to the app. This is an internal Senza platform error |
|
|
306
|
+
* | 1999 | Encrypted content | An unknown encrypted content error |
|
|
307
|
+
* | 2000 | Player | Content makes reference to no or unsupported key system |
|
|
308
|
+
* | 3000 | Player | Unexpected problem with playback, only used if no more specific code in 3xxx range applies |
|
|
309
|
+
* | 3001 | Player | Problem accessing content manifest, only used if no more specific code in 8xxx range applies |
|
|
310
|
+
* | 3002 | Player | Unexpectedly stopped playback |
|
|
311
|
+
* | 3100 | Player | Problem parsing MP4 content |
|
|
312
|
+
* | 3200 | Player | Problem with decoder |
|
|
313
|
+
* | 3300 | Player | DRM keys unavailable, player waited for keys but none arrived |
|
|
314
|
+
* | 3400 | Player | Problem accessing segments, only used if no more specific code in 34xx range applies |
|
|
315
|
+
* | 3401 | Player | Problem accessing segments, connection issue or timeout |
|
|
316
|
+
* | 3402 | Player | Problem accessing segments, server returned HTTP error code |
|
|
317
|
+
* | 3403 | Player | Problem accessing segments, server authentication issue |
|
|
318
|
+
* | 3404 | Player | Problem accessing segments, server returned not found |
|
|
319
|
+
* | 3900-3999 | Player | Internal player error |
|
|
320
|
+
* | 6000 | Player | The remote player api call has reached the configurable timeout with no response from the remote player |
|
|
321
|
+
* | 6001 | Player | play() was called while the remote player is not loaded |
|
|
322
|
+
* | 6002 | Player | load() was called while the application was in state 'background' or 'inTransitionToBackground' |
|
|
323
|
+
* | 6500 | Player | remotePlayer api was called before initializing remotePlayer |
|
|
324
|
+
* | 6501 | Player | load() was called while previous load/unload was still in progress |
|
|
325
|
+
* | 6502 | Player | unload() was called while previous unload/load was still in progress |
|
|
326
|
+
* | 8001 | Player | Error pulling manifest. bad parameters |
|
|
327
|
+
* | 8002 | Player | Error pulling manifest. filters returned no data |
|
|
328
|
+
* | 8003 | Player | Error pulling manifest. fetch error |
|
|
329
|
+
* | 8004 | Player | Error pulling manifest. parse error |
|
|
330
|
+
* | 8005 | Player | Error pulling manifest. stale manifest detected |
|
|
331
|
+
* | 8006 | Player | Error updating manifest. internal cache error |
|
|
332
|
+
* | 8007 | Player | Error updating manifest. internal error during backoff |
|
|
333
|
+
* | 8008 | Player | Error pulling manifest. sidx parsing error |
|
|
334
|
+
* | 8009 | Player | Error pulling manifest. internal error |
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* remotePlayer.addEventListener("error", (event) => {
|
|
338
|
+
* console.error("received remotePlayer error:", event.detail.errorCode, event.detail.message);
|
|
339
|
+
* });
|
|
340
|
+
*
|
|
341
|
+
*/
|
|
202
342
|
typeof document !== "undefined" && document.addEventListener("hs/ERR", (event) => {
|
|
203
343
|
sdkLogger.info("Got hs/ERR event");
|
|
204
344
|
delete event?.detail?.type; // type is always videoPlaybackEvent, so no need to pass it
|
|
@@ -206,6 +346,58 @@ class RemotePlayer extends RemotePlayerInterface {
|
|
|
206
346
|
this.dispatchEvent(new CustomEvent("error", event));
|
|
207
347
|
});
|
|
208
348
|
|
|
349
|
+
/**
|
|
350
|
+
*
|
|
351
|
+
* @event RemotePlayer#license-request
|
|
352
|
+
* @description Fired whenever the platform requires a license to play encrypted content.
|
|
353
|
+
* The Web App is responsible for passing the (opaque) license request blob to the license server and passing the (opaque) license server response to the CDM by calling the `writeLicenseResponse` method on the event.
|
|
354
|
+
* @type {LicenseRequestEvent}
|
|
355
|
+
* @property {object} detail - Object containing ievent data
|
|
356
|
+
* @property {string} detail.licenseRequest - Base64 coded opaque license request. The app is responsible for decoding the request before sending to the license server. Note that after decoding, the request may still be in Base64 form and this form should be sent to the license server without further decoding
|
|
357
|
+
* @property {writeLicenseResponse} writeLicenseResponse - Write the license server response to the platform
|
|
358
|
+
* @example
|
|
359
|
+
* Whilst the payload structure and access controls are specific to each license server implementation, the Widevine UAT license server requires no authentication and minimal payload formatting and therefore serves as a useful case study that may be adapted.
|
|
360
|
+
*
|
|
361
|
+
* remotePlayer.addEventListener("license-request", async (event) => {
|
|
362
|
+
* console.log("Got license-request event");
|
|
363
|
+
* const requestBuffer = event?.detail?.licenseRequest;
|
|
364
|
+
* const requestBufferStr = String.fromCharCode.apply(null, new Uint8Array(requestBuffer));
|
|
365
|
+
* console.log("License Request in base64:", requestBufferStr);
|
|
366
|
+
* const decodedLicenseRequest = window.atob(requestBufferStr); // from base 64
|
|
367
|
+
* const licenseRequestBytes = Uint8Array.from(decodedLicenseRequest, (l) => l.charCodeAt(0));
|
|
368
|
+
* // call Google API
|
|
369
|
+
* const res = await getLicenseFromServer(licenseRequestBytes.buffer);
|
|
370
|
+
* console.log("Writing response to platform ", res.code, res.responseBody);
|
|
371
|
+
* event.writeLicenseResponse(res.code, res.responseBody);
|
|
372
|
+
* });
|
|
373
|
+
|
|
374
|
+
* async function getLicenseFromServer(licenseRequest) {
|
|
375
|
+
* console.log("Requesting License from Widevine server");
|
|
376
|
+
* const response = await fetch("https://proxy.uat.widevine.com/proxy", {
|
|
377
|
+
* "method": "POST",
|
|
378
|
+
* "body": licenseRequest,
|
|
379
|
+
* "headers" : {
|
|
380
|
+
* "Content-Type": "application/octet-stream"
|
|
381
|
+
* }
|
|
382
|
+
* });
|
|
383
|
+
* const code = response.status;
|
|
384
|
+
* if (code !== 200) {
|
|
385
|
+
* console.error("failed to to get response from widevine:", code);
|
|
386
|
+
* const responseBody = await response.text();
|
|
387
|
+
* console.error(responseBody);
|
|
388
|
+
* return {code, responseBody};
|
|
389
|
+
* }
|
|
390
|
+
* const responseBody = await response.arrayBuffer();
|
|
391
|
+
* console.info("Got response: ");
|
|
392
|
+
* return {code, responseBody};
|
|
393
|
+
* }
|
|
394
|
+
**/
|
|
395
|
+
/**
|
|
396
|
+
* @function writeLicenseResponse
|
|
397
|
+
* @param {number} statusCode - License server HTTP response code, e.g. 200, 401, etc. Must be 200 to indicate a successful license exchange.
|
|
398
|
+
* @param {string} response - License server response as opaque binary data in an ArrayBuffer.
|
|
399
|
+
*
|
|
400
|
+
* */
|
|
209
401
|
typeof document !== "undefined" && document.addEventListener("hs/getLicense", (event) => {
|
|
210
402
|
sdkLogger.info("Got hs/getLicense event");
|
|
211
403
|
const getLicenseEventData = event?.detail;
|
|
@@ -225,6 +417,20 @@ class RemotePlayer extends RemotePlayerInterface {
|
|
|
225
417
|
});
|
|
226
418
|
}
|
|
227
419
|
|
|
420
|
+
/**
|
|
421
|
+
* @typedef {Object} LoadMode
|
|
422
|
+
* @property {string} NOT_LOADED
|
|
423
|
+
* @property {string} LOADING
|
|
424
|
+
* @property {string} LOADED
|
|
425
|
+
* @property {string} UNLOADING
|
|
426
|
+
*/
|
|
427
|
+
LoadMode = Object.freeze({
|
|
428
|
+
NOT_LOADED: "notLoaded",
|
|
429
|
+
LOADING: "loading",
|
|
430
|
+
LOADED: "loaded",
|
|
431
|
+
UNLOADING: "unloading"
|
|
432
|
+
});
|
|
433
|
+
|
|
228
434
|
/** @private Initialize the remote player
|
|
229
435
|
* @param {Object} uiStreamerSettings ui-streamer portion of the settings taken from session info
|
|
230
436
|
* */
|
|
@@ -319,10 +525,10 @@ class RemotePlayer extends RemotePlayerInterface {
|
|
|
319
525
|
|
|
320
526
|
/** setting values for properties in the player configuration using an object.
|
|
321
527
|
* If the config does not support a property this is a no-op.
|
|
322
|
-
* @param {
|
|
528
|
+
* @param {Object} props the object with all the different properties to change
|
|
323
529
|
* @example
|
|
324
530
|
* remotePlayer.configure({ preferredAudioLanguage: 'en-US' })
|
|
325
|
-
*
|
|
531
|
+
*
|
|
326
532
|
* */
|
|
327
533
|
configure(props) {
|
|
328
534
|
Object.entries(props).forEach(([key, value]) => {
|
|
@@ -691,9 +897,6 @@ class RemotePlayer extends RemotePlayerInterface {
|
|
|
691
897
|
this._updateSeekListeners(video);
|
|
692
898
|
}
|
|
693
899
|
this._videoElement = video;
|
|
694
|
-
|
|
695
|
-
// Emit a custom event to notify about the attachment of the video element
|
|
696
|
-
this.dispatchEvent(new Event("videoelementattached"));
|
|
697
900
|
}
|
|
698
901
|
}
|
|
699
902
|
|
|
@@ -709,7 +912,7 @@ class RemotePlayer extends RemotePlayerInterface {
|
|
|
709
912
|
/** Tell the remote player to load the given URL.
|
|
710
913
|
* @param {string} url url to load
|
|
711
914
|
* @param {number} [position] start position in seconds (if not provided, start from beginning (VOD) or current time (LTV))
|
|
712
|
-
|
|
915
|
+
* @returns {Promise}
|
|
713
916
|
* @throws {RemotePlayerError} error object contains code & msg
|
|
714
917
|
*
|
|
715
918
|
* */
|
|
@@ -774,11 +977,6 @@ class RemotePlayer extends RemotePlayerInterface {
|
|
|
774
977
|
message.action = "load";
|
|
775
978
|
message.audioLanguage = audioLanguage;
|
|
776
979
|
message.subtitlesLanguage = subtitlesLanguage;
|
|
777
|
-
if (this.getConfiguration().minSuggestedPresentationDelay > 0) {
|
|
778
|
-
message.cloudPlayerParams = {
|
|
779
|
-
"mspd": this.getConfiguration().minSuggestedPresentationDelay
|
|
780
|
-
};
|
|
781
|
-
}
|
|
782
980
|
} else {
|
|
783
981
|
message.type = "setPlayableUri";
|
|
784
982
|
}
|