@ngxsp/engine-shaka 0.0.1-next.0 → 0.0.1-next.1
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/index.cjs +374 -0
- package/index.cjs.map +1 -0
- package/index.d.cts +30 -0
- package/index.d.ts +30 -0
- package/index.js +338 -0
- package/index.js.map +1 -0
- package/package.json +19 -12
package/index.cjs
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
ShakaEngine: () => ShakaEngine,
|
|
34
|
+
createShakaEngineFactory: () => createShakaEngineFactory
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
async function importShaka() {
|
|
38
|
+
const mod = await import("shaka-player");
|
|
39
|
+
return mod?.default ?? mod;
|
|
40
|
+
}
|
|
41
|
+
function sourceToUrl(source) {
|
|
42
|
+
const s = source;
|
|
43
|
+
if (typeof s.url === "string") return s.url;
|
|
44
|
+
throw new Error("Invalid source url");
|
|
45
|
+
}
|
|
46
|
+
function mapTracks(shaka) {
|
|
47
|
+
const out = [];
|
|
48
|
+
try {
|
|
49
|
+
const v = shaka.getVariantTracks?.() ?? [];
|
|
50
|
+
for (const t of v) {
|
|
51
|
+
out.push({
|
|
52
|
+
id: String(t.id),
|
|
53
|
+
kind: "audio",
|
|
54
|
+
language: t.language ?? "und",
|
|
55
|
+
label: t.label ?? t.language ?? "audio",
|
|
56
|
+
active: !!t.active
|
|
57
|
+
});
|
|
58
|
+
out.push({
|
|
59
|
+
id: `video:${t.id}`,
|
|
60
|
+
kind: "video",
|
|
61
|
+
label: formatVideoLabel(t),
|
|
62
|
+
active: !!t.active,
|
|
63
|
+
width: Number.isFinite(t.width) ? t.width : void 0,
|
|
64
|
+
height: Number.isFinite(t.height) ? t.height : void 0,
|
|
65
|
+
bandwidth: Number.isFinite(t.bandwidth) ? t.bandwidth : void 0
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const tt = shaka.getTextTracks?.() ?? [];
|
|
72
|
+
for (const t of tt) {
|
|
73
|
+
out.push({
|
|
74
|
+
id: String(t.id),
|
|
75
|
+
kind: "text",
|
|
76
|
+
language: t.language ?? "und",
|
|
77
|
+
label: t.label ?? t.language ?? "subtitles",
|
|
78
|
+
active: !!t.active
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
} catch {
|
|
82
|
+
}
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
function formatVideoLabel(track) {
|
|
86
|
+
const height = Number.isFinite(track?.height) ? `${track.height}p` : null;
|
|
87
|
+
const bandwidth = Number.isFinite(track?.bandwidth) ? `${(track.bandwidth / 1e6).toFixed(1)} Mbps` : null;
|
|
88
|
+
return [height, bandwidth].filter(Boolean).join(" \u2022 ") || "Quality";
|
|
89
|
+
}
|
|
90
|
+
var ShakaEngine = class {
|
|
91
|
+
id = "shaka";
|
|
92
|
+
shaka = null;
|
|
93
|
+
player = null;
|
|
94
|
+
video;
|
|
95
|
+
off = [];
|
|
96
|
+
emit;
|
|
97
|
+
lastAbrRestrictions = null;
|
|
98
|
+
async attach(videoEl) {
|
|
99
|
+
this.video = videoEl;
|
|
100
|
+
}
|
|
101
|
+
onEvent(cb) {
|
|
102
|
+
this.emit = cb;
|
|
103
|
+
return () => {
|
|
104
|
+
if (this.emit === cb) this.emit = void 0;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
fire(ev) {
|
|
108
|
+
try {
|
|
109
|
+
this.emit?.(ev);
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async load(source, opts) {
|
|
114
|
+
const shaka = await importShaka();
|
|
115
|
+
if (!shaka?.Player) throw new Error("Shaka Player not available");
|
|
116
|
+
this.shaka = shaka;
|
|
117
|
+
try {
|
|
118
|
+
shaka.polyfill?.installAll?.();
|
|
119
|
+
} catch {
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
await this.player?.destroy?.();
|
|
123
|
+
} catch {
|
|
124
|
+
}
|
|
125
|
+
this.player = new shaka.Player(this.video);
|
|
126
|
+
try {
|
|
127
|
+
await this.configureAbr(this.player, source);
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
const streamHints = source?._shakaStreaming;
|
|
131
|
+
if (streamHints) {
|
|
132
|
+
try {
|
|
133
|
+
this.player.configure({
|
|
134
|
+
streaming: {
|
|
135
|
+
...streamHints.lowLatencyMode != null ? { lowLatencyMode: streamHints.lowLatencyMode } : {},
|
|
136
|
+
...streamHints.bufferingGoalSec != null ? { bufferingGoal: streamHints.bufferingGoalSec } : {},
|
|
137
|
+
...streamHints.rebufferingGoalSec != null ? { rebufferingGoal: streamHints.rebufferingGoalSec } : {}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
} catch {
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const anySrc = source;
|
|
144
|
+
const drm = anySrc?.drm;
|
|
145
|
+
if (drm?.servers || drm?.keySystems) {
|
|
146
|
+
const servers = { ...drm?.servers ?? {} };
|
|
147
|
+
const advanced = {};
|
|
148
|
+
const licenseHeadersByKs = {};
|
|
149
|
+
if (drm?.keySystems && typeof drm.keySystems === "object") {
|
|
150
|
+
for (const [ks, v] of Object.entries(drm.keySystems)) {
|
|
151
|
+
if (v?.licenseServerUrl) servers[ks] = String(v.licenseServerUrl);
|
|
152
|
+
if (v?.videoRobustness || v?.audioRobustness) {
|
|
153
|
+
advanced[ks] = {
|
|
154
|
+
videoRobustness: v.videoRobustness,
|
|
155
|
+
audioRobustness: v.audioRobustness
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (v?.headers) licenseHeadersByKs[ks] = { ...v.headers };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const retry = drm?.licenseRetry ?? {};
|
|
162
|
+
const retryParameters = {
|
|
163
|
+
maxAttempts: retry.maxAttempts ?? 3,
|
|
164
|
+
baseDelay: retry.baseDelayMs ?? 500,
|
|
165
|
+
backoffFactor: retry.backoffFactor ?? 2,
|
|
166
|
+
fuzzFactor: retry.fuzzFactor ?? 0.5,
|
|
167
|
+
timeout: retry.timeoutMs ?? 0
|
|
168
|
+
};
|
|
169
|
+
this.player.configure({
|
|
170
|
+
drm: {
|
|
171
|
+
servers,
|
|
172
|
+
advanced: Object.keys(advanced).length ? advanced : void 0,
|
|
173
|
+
retryParameters,
|
|
174
|
+
persistentStateRequired: !!drm?.persistentLicense
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
try {
|
|
178
|
+
const net = this.player.getNetworkingEngine?.();
|
|
179
|
+
const ReqType = shaka.net?.NetworkingEngine?.RequestType;
|
|
180
|
+
if (net?.registerRequestFilter && ReqType?.LICENSE != null) {
|
|
181
|
+
net.registerRequestFilter((type, request) => {
|
|
182
|
+
if (type !== ReqType.LICENSE) return;
|
|
183
|
+
const headers = {};
|
|
184
|
+
for (const h of Object.values(licenseHeadersByKs)) Object.assign(headers, h);
|
|
185
|
+
request.headers = { ...request.headers ?? {}, ...headers };
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
} catch {
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const onErrorEvent = (evt) => {
|
|
192
|
+
const detail = evt?.detail ?? evt;
|
|
193
|
+
const code = String(detail?.code ?? "SHAKA_ERROR");
|
|
194
|
+
const msg = detail?.message ? String(detail.message) : "Shaka error";
|
|
195
|
+
this.fire({ type: "error", error: { code, message: msg, fatal: true, details: detail } });
|
|
196
|
+
};
|
|
197
|
+
this.player.addEventListener("error", onErrorEvent);
|
|
198
|
+
this.off.push(() => this.player?.removeEventListener?.("error", onErrorEvent));
|
|
199
|
+
const url = sourceToUrl(source);
|
|
200
|
+
this.fire({ type: "state", state: "loading" });
|
|
201
|
+
await this.player.load(url);
|
|
202
|
+
this.fire({ type: "tracks", tracks: mapTracks(this.player) });
|
|
203
|
+
if (opts?.startTimeSec != null && Number.isFinite(opts.startTimeSec)) {
|
|
204
|
+
try {
|
|
205
|
+
await this.seekTo(opts.startTimeSec);
|
|
206
|
+
} catch {
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
this.fire({ type: "state", state: this.video.paused ? "paused" : "playing" });
|
|
210
|
+
}
|
|
211
|
+
async configureAbr(player, source) {
|
|
212
|
+
const hints = source?.abr;
|
|
213
|
+
const restrictions = {};
|
|
214
|
+
let reason = "";
|
|
215
|
+
if (hints?.maxBandwidth != null) restrictions.maxBandwidth = hints.maxBandwidth;
|
|
216
|
+
if (hints?.maxHeight != null) restrictions.maxHeight = hints.maxHeight;
|
|
217
|
+
if (!Object.keys(restrictions).length) {
|
|
218
|
+
const tuned = await this.autoTuneAbrWithMediaCapabilities();
|
|
219
|
+
if (tuned) {
|
|
220
|
+
Object.assign(restrictions, tuned);
|
|
221
|
+
reason = "mediaCapabilities";
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
reason = "source.abr";
|
|
225
|
+
}
|
|
226
|
+
if (!Object.keys(restrictions).length) return;
|
|
227
|
+
try {
|
|
228
|
+
player.configure({ abr: { restrictions } });
|
|
229
|
+
this.lastAbrRestrictions = { ...restrictions, reason };
|
|
230
|
+
} catch {
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
async autoTuneAbrWithMediaCapabilities() {
|
|
234
|
+
const mc = globalThis.navigator?.mediaCapabilities;
|
|
235
|
+
if (!mc?.decodingInfo) return null;
|
|
236
|
+
try {
|
|
237
|
+
const info = await mc.decodingInfo({
|
|
238
|
+
type: "media-source",
|
|
239
|
+
video: {
|
|
240
|
+
contentType: 'video/mp4; codecs="avc1.640028"',
|
|
241
|
+
width: 1920,
|
|
242
|
+
height: 1080,
|
|
243
|
+
bitrate: 5e6,
|
|
244
|
+
framerate: 30
|
|
245
|
+
},
|
|
246
|
+
audio: {
|
|
247
|
+
contentType: 'audio/mp4; codecs="mp4a.40.2"',
|
|
248
|
+
channels: 2,
|
|
249
|
+
bitrate: 128e3,
|
|
250
|
+
samplerate: 48e3
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
if (info?.supported && info.smooth !== false && info.powerEfficient !== false) return null;
|
|
254
|
+
return { maxHeight: 720, maxBandwidth: 3e6 };
|
|
255
|
+
} catch {
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
async destroy() {
|
|
260
|
+
try {
|
|
261
|
+
for (const fn of this.off.splice(0)) fn();
|
|
262
|
+
} catch {
|
|
263
|
+
}
|
|
264
|
+
try {
|
|
265
|
+
await this.player?.destroy?.();
|
|
266
|
+
} catch {
|
|
267
|
+
}
|
|
268
|
+
this.player = null;
|
|
269
|
+
this.shaka = null;
|
|
270
|
+
}
|
|
271
|
+
async play() {
|
|
272
|
+
await this.video.play();
|
|
273
|
+
this.fire({ type: "state", state: "playing" });
|
|
274
|
+
}
|
|
275
|
+
async pause() {
|
|
276
|
+
this.video.pause();
|
|
277
|
+
this.fire({ type: "state", state: "paused" });
|
|
278
|
+
}
|
|
279
|
+
async seekTo(timeSec) {
|
|
280
|
+
this.video.currentTime = Math.max(0, timeSec);
|
|
281
|
+
this.fire({ type: "timeupdate", currentTime: this.video.currentTime, duration: this.video.duration || 0 });
|
|
282
|
+
}
|
|
283
|
+
async setPlaybackRate(rate) {
|
|
284
|
+
this.video.playbackRate = rate;
|
|
285
|
+
}
|
|
286
|
+
async setVolume(volume) {
|
|
287
|
+
this.video.volume = Math.min(1, Math.max(0, volume));
|
|
288
|
+
}
|
|
289
|
+
async setTextTrack(trackId) {
|
|
290
|
+
if (!this.player?.selectTextTrack) return;
|
|
291
|
+
if (!trackId) {
|
|
292
|
+
try {
|
|
293
|
+
this.player.setTextTrackVisibility(false);
|
|
294
|
+
} catch {
|
|
295
|
+
}
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
try {
|
|
299
|
+
const tracks = this.player.getTextTracks?.() ?? [];
|
|
300
|
+
const t = tracks.find((x) => String(x.id) === String(trackId));
|
|
301
|
+
if (t) {
|
|
302
|
+
this.player.selectTextTrack(t);
|
|
303
|
+
this.player.setTextTrackVisibility(true);
|
|
304
|
+
}
|
|
305
|
+
} catch {
|
|
306
|
+
}
|
|
307
|
+
this.fire({ type: "tracks", tracks: mapTracks(this.player) });
|
|
308
|
+
}
|
|
309
|
+
async setAudioTrack(trackId) {
|
|
310
|
+
if (!this.player?.selectVariantTrack || !trackId) return;
|
|
311
|
+
try {
|
|
312
|
+
const tracks = this.player.getVariantTracks?.() ?? [];
|
|
313
|
+
const t = tracks.find((x) => String(x.id) === String(trackId));
|
|
314
|
+
if (t) this.player.selectVariantTrack(t, true);
|
|
315
|
+
} catch {
|
|
316
|
+
}
|
|
317
|
+
this.fire({ type: "tracks", tracks: mapTracks(this.player) });
|
|
318
|
+
}
|
|
319
|
+
async setVideoTrack(trackId) {
|
|
320
|
+
if (!this.player?.selectVariantTrack) return;
|
|
321
|
+
try {
|
|
322
|
+
if (!trackId) {
|
|
323
|
+
this.player.configure?.({ abr: { enabled: true } });
|
|
324
|
+
} else {
|
|
325
|
+
const normalizedTrackId = String(trackId).replace(/^video:/, "");
|
|
326
|
+
const tracks = this.player.getVariantTracks?.() ?? [];
|
|
327
|
+
const t = tracks.find((x) => String(x.id) === normalizedTrackId);
|
|
328
|
+
if (t) {
|
|
329
|
+
this.player.configure?.({ abr: { enabled: false } });
|
|
330
|
+
this.player.selectVariantTrack(t, true);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
} catch {
|
|
334
|
+
}
|
|
335
|
+
this.fire({ type: "tracks", tracks: mapTracks(this.player) });
|
|
336
|
+
}
|
|
337
|
+
async getTracks() {
|
|
338
|
+
if (!this.player) return [];
|
|
339
|
+
return mapTracks(this.player);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
function createShakaEngineFactory() {
|
|
343
|
+
return {
|
|
344
|
+
id: "shaka",
|
|
345
|
+
// Higher than native; only selected when it *should* be used.
|
|
346
|
+
priority: 50,
|
|
347
|
+
supports: (cfg) => {
|
|
348
|
+
const t = cfg.source.type;
|
|
349
|
+
const url = t === "url" ? cfg.source.url : cfg.source.url;
|
|
350
|
+
const looksLikeHls = typeof url === "string" && /\.m3u8($|\?)/i.test(url);
|
|
351
|
+
const looksLikeDash = typeof url === "string" && /\.mpd($|\?)/i.test(url);
|
|
352
|
+
const hasDrm = !!(cfg.drm ?? cfg.source.drm);
|
|
353
|
+
return t === "hls" || t === "dash" || looksLikeHls || looksLikeDash || hasDrm;
|
|
354
|
+
},
|
|
355
|
+
supportsWithCaps: (cfg, caps) => {
|
|
356
|
+
const t = cfg.source.type;
|
|
357
|
+
const url = t === "url" ? cfg.source.url : cfg.source.url;
|
|
358
|
+
const looksLikeHls = typeof url === "string" && /\.m3u8($|\?)/i.test(url);
|
|
359
|
+
const looksLikeDash = typeof url === "string" && /\.mpd($|\?)/i.test(url);
|
|
360
|
+
const drm = cfg.drm ?? cfg.source.drm;
|
|
361
|
+
const hasDrm = !!(drm && (drm.widevine || drm.playready || drm.fairplay || Object.keys(drm).length));
|
|
362
|
+
if (!caps.mse) return false;
|
|
363
|
+
if (hasDrm && !caps.eme) return false;
|
|
364
|
+
return t === "hls" || t === "dash" || looksLikeHls || looksLikeDash || hasDrm;
|
|
365
|
+
},
|
|
366
|
+
create: () => new ShakaEngine()
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
370
|
+
0 && (module.exports = {
|
|
371
|
+
ShakaEngine,
|
|
372
|
+
createShakaEngineFactory
|
|
373
|
+
});
|
|
374
|
+
//# sourceMappingURL=index.cjs.map
|
package/index.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type {\n PlaybackEngine,\n EngineEvent,\n LoadOptions,\n PlayerSource,\n MediaTrack,\n EngineFactory,\n PlayerConfig,\n PlaybackCapabilities\n} from '@ngxsp/core';\n\ntype ShakaNS = any;\n\nasync function importShaka(): Promise<ShakaNS> {\n // Use dynamic import to keep Shaka optional and avoid bundler static resolution issues.\n const mod: any = await import('shaka-player');\n return (mod?.default ?? mod) as ShakaNS;\n}\n\nfunction sourceToUrl(source: PlayerSource): string {\n const s: any = source as any;\n if (typeof s.url === 'string') return s.url;\n throw new Error('Invalid source url');\n}\n\nfunction mapTracks(shaka: any): MediaTrack[] {\n const out: MediaTrack[] = [];\n try {\n const v = shaka.getVariantTracks?.() ?? [];\n for (const t of v) {\n out.push({\n id: String(t.id),\n kind: 'audio',\n language: t.language ?? 'und',\n label: t.label ?? t.language ?? 'audio',\n active: !!t.active\n });\n out.push({\n id: `video:${t.id}`,\n kind: 'video',\n label: formatVideoLabel(t),\n active: !!t.active,\n width: Number.isFinite(t.width) ? t.width : undefined,\n height: Number.isFinite(t.height) ? t.height : undefined,\n bandwidth: Number.isFinite(t.bandwidth) ? t.bandwidth : undefined\n });\n }\n } catch {}\n try {\n const tt = shaka.getTextTracks?.() ?? [];\n for (const t of tt) {\n out.push({\n id: String(t.id),\n kind: 'text',\n language: t.language ?? 'und',\n label: t.label ?? t.language ?? 'subtitles',\n active: !!t.active\n });\n }\n } catch {}\n return out;\n}\n\nfunction formatVideoLabel(track: any): string {\n const height = Number.isFinite(track?.height) ? `${track.height}p` : null;\n const bandwidth =\n Number.isFinite(track?.bandwidth) ? `${(track.bandwidth / 1_000_000).toFixed(1)} Mbps` : null;\n return [height, bandwidth].filter(Boolean).join(' • ') || 'Quality';\n}\n\nexport class ShakaEngine implements PlaybackEngine {\n readonly id = 'shaka';\n\n private shaka: ShakaNS | null = null;\n private player: any | null = null;\n private video!: HTMLVideoElement;\n private off: Array<() => void> = [];\n private emit?: (ev: EngineEvent) => void;\n\n private lastAbrRestrictions: { maxHeight?: number; maxBandwidth?: number; reason?: string } | null = null;\n\n async attach(videoEl: HTMLVideoElement): Promise<void> {\n this.video = videoEl;\n }\n\n onEvent(cb: (ev: EngineEvent) => void): () => void {\n this.emit = cb;\n return () => { if (this.emit === cb) this.emit = undefined; };\n }\n\n private fire(ev: EngineEvent): void {\n try { this.emit?.(ev); } catch {}\n }\n\n async load(source: PlayerSource, opts?: LoadOptions): Promise<void> {\n const shaka: ShakaNS = await importShaka();\n if (!shaka?.Player) throw new Error('Shaka Player not available');\n this.shaka = shaka;\n\n try { shaka.polyfill?.installAll?.(); } catch {}\n\n // Clean previous player if any\n try { await this.player?.destroy?.(); } catch {}\n this.player = new shaka.Player(this.video);\n\n // ABR tuning (best-effort):\n // - explicit hints from source.abr\n // - implicit hints via MediaCapabilities probes\n try { await this.configureAbr(this.player, source); } catch {}\n\n // Profile streaming hints (best-effort): filled by core via `source._shakaStreaming`.\n const streamHints = (source as any)?._shakaStreaming as\n | { lowLatencyMode?: boolean; bufferingGoalSec?: number; rebufferingGoalSec?: number }\n | undefined;\n if (streamHints) {\n try {\n this.player.configure({\n streaming: {\n ...(streamHints.lowLatencyMode != null ? { lowLatencyMode: streamHints.lowLatencyMode } : {}),\n ...(streamHints.bufferingGoalSec != null ? { bufferingGoal: streamHints.bufferingGoalSec } : {}),\n ...(streamHints.rebufferingGoalSec != null ? { rebufferingGoal: streamHints.rebufferingGoalSec } : {})\n }\n });\n } catch {}\n }\n\n // DRM config if present\n const anySrc: any = source as any;\n const drm: any = anySrc?.drm;\n if (drm?.servers || drm?.keySystems) {\n const servers: Record<string, string> = { ...(drm?.servers ?? {}) };\n const advanced: Record<string, any> = {};\n const licenseHeadersByKs: Record<string, Record<string, string>> = {};\n\n if (drm?.keySystems && typeof drm.keySystems === \"object\") {\n for (const [ks, v] of Object.entries<any>(drm.keySystems)) {\n if (v?.licenseServerUrl) servers[ks] = String(v.licenseServerUrl);\n if (v?.videoRobustness || v?.audioRobustness) {\n advanced[ks] = {\n videoRobustness: v.videoRobustness,\n audioRobustness: v.audioRobustness\n };\n }\n if (v?.headers) licenseHeadersByKs[ks] = { ...v.headers };\n }\n }\n\n const retry = drm?.licenseRetry ?? {};\n const retryParameters = {\n maxAttempts: retry.maxAttempts ?? 3,\n baseDelay: retry.baseDelayMs ?? 500,\n backoffFactor: retry.backoffFactor ?? 2,\n fuzzFactor: retry.fuzzFactor ?? 0.5,\n timeout: retry.timeoutMs ?? 0\n };\n\n this.player.configure({\n drm: {\n servers,\n advanced: Object.keys(advanced).length ? advanced : undefined,\n retryParameters,\n persistentStateRequired: !!drm?.persistentLicense\n }\n });\n\n // Inject per-keysystem license headers (Widevine/PlayReady etc.)\n try {\n const net = this.player.getNetworkingEngine?.();\n const ReqType = (shaka as any).net?.NetworkingEngine?.RequestType;\n if (net?.registerRequestFilter && ReqType?.LICENSE != null) {\n net.registerRequestFilter((type: any, request: any) => {\n if (type !== ReqType.LICENSE) return;\n const headers: Record<string, string> = {};\n for (const h of Object.values(licenseHeadersByKs)) Object.assign(headers, h);\n request.headers = { ...(request.headers ?? {}), ...headers };\n });\n }\n } catch {}\n }\n\n // forward shaka errors\n const onErrorEvent = (evt: any) => {\n const detail = evt?.detail ?? evt;\n const code = String(detail?.code ?? 'SHAKA_ERROR');\n const msg = detail?.message ? String(detail.message) : 'Shaka error';\n this.fire({ type: 'error', error: { code, message: msg, fatal: true, details: detail } });\n };\n this.player.addEventListener('error', onErrorEvent);\n this.off.push(() => this.player?.removeEventListener?.('error', onErrorEvent));\n\n const url = sourceToUrl(source);\n this.fire({ type: 'state', state: 'loading' });\n await this.player.load(url);\n\n // initial tracks\n this.fire({ type: 'tracks', tracks: mapTracks(this.player) });\n\n // start time\n if (opts?.startTimeSec != null && Number.isFinite(opts.startTimeSec)) {\n try { await this.seekTo(opts.startTimeSec); } catch {}\n }\n\n this.fire({ type: 'state', state: this.video.paused ? 'paused' : 'playing' });\n }\n\n private async configureAbr(player: any, source: PlayerSource): Promise<void> {\n const hints = (source as any)?.abr as { maxHeight?: number; maxBandwidth?: number } | undefined;\n\n const restrictions: any = {};\n let reason = '';\n\n if (hints?.maxBandwidth != null) restrictions.maxBandwidth = hints.maxBandwidth;\n if (hints?.maxHeight != null) restrictions.maxHeight = hints.maxHeight;\n\n if (!Object.keys(restrictions).length) {\n const tuned = await this.autoTuneAbrWithMediaCapabilities();\n if (tuned) {\n Object.assign(restrictions, tuned);\n reason = 'mediaCapabilities';\n }\n } else {\n reason = 'source.abr';\n }\n\n if (!Object.keys(restrictions).length) return;\n\n try {\n player.configure({ abr: { restrictions } });\n this.lastAbrRestrictions = { ...restrictions, reason };\n } catch {\n // ignore\n }\n }\n\n private async autoTuneAbrWithMediaCapabilities(): Promise<{ maxHeight?: number; maxBandwidth?: number } | null> {\n const mc: any = (globalThis as any).navigator?.mediaCapabilities;\n if (!mc?.decodingInfo) return null;\n\n try {\n const info = await mc.decodingInfo({\n type: 'media-source',\n video: {\n contentType: 'video/mp4; codecs=\"avc1.640028\"',\n width: 1920,\n height: 1080,\n bitrate: 5000000,\n framerate: 30\n },\n audio: {\n contentType: 'audio/mp4; codecs=\"mp4a.40.2\"',\n channels: 2,\n bitrate: 128000,\n samplerate: 48000\n }\n });\n // If 1080p H264 is not power-efficient or not smooth, cap to conservative defaults.\n if (info?.supported && info.smooth !== false && info.powerEfficient !== false) return null;\n return { maxHeight: 720, maxBandwidth: 3000000 };\n } catch {\n return null;\n }\n }\n\n async destroy(): Promise<void> {\n try { for (const fn of this.off.splice(0)) fn(); } catch {}\n try { await this.player?.destroy?.(); } catch {}\n this.player = null;\n this.shaka = null;\n }\n\n async play(): Promise<void> {\n await this.video.play();\n this.fire({ type: 'state', state: 'playing' });\n }\n\n async pause(): Promise<void> {\n this.video.pause();\n this.fire({ type: 'state', state: 'paused' });\n }\n\n async seekTo(timeSec: number): Promise<void> {\n this.video.currentTime = Math.max(0, timeSec);\n this.fire({ type: 'timeupdate', currentTime: this.video.currentTime, duration: this.video.duration || 0 });\n }\n\n async setPlaybackRate(rate: number): Promise<void> {\n this.video.playbackRate = rate;\n }\n\n async setVolume(volume: number): Promise<void> {\n this.video.volume = Math.min(1, Math.max(0, volume));\n }\n\n async setTextTrack(trackId: string | null): Promise<void> {\n if (!this.player?.selectTextTrack) return;\n if (!trackId) {\n try { this.player.setTextTrackVisibility(false); } catch {}\n return;\n }\n try {\n const tracks = this.player.getTextTracks?.() ?? [];\n const t = tracks.find((x: any) => String(x.id) === String(trackId));\n if (t) {\n this.player.selectTextTrack(t);\n this.player.setTextTrackVisibility(true);\n }\n } catch {}\n this.fire({ type: 'tracks', tracks: mapTracks(this.player) });\n }\n\n async setAudioTrack(trackId: string | null): Promise<void> {\n if (!this.player?.selectVariantTrack || !trackId) return;\n try {\n const tracks = this.player.getVariantTracks?.() ?? [];\n const t = tracks.find((x: any) => String(x.id) === String(trackId));\n if (t) this.player.selectVariantTrack(t, true);\n } catch {}\n this.fire({ type: 'tracks', tracks: mapTracks(this.player) });\n }\n\n async setVideoTrack(trackId: string | null): Promise<void> {\n if (!this.player?.selectVariantTrack) return;\n try {\n if (!trackId) {\n this.player.configure?.({ abr: { enabled: true } });\n } else {\n const normalizedTrackId = String(trackId).replace(/^video:/, '');\n const tracks = this.player.getVariantTracks?.() ?? [];\n const t = tracks.find((x: any) => String(x.id) === normalizedTrackId);\n if (t) {\n this.player.configure?.({ abr: { enabled: false } });\n this.player.selectVariantTrack(t, true);\n }\n }\n } catch {}\n this.fire({ type: 'tracks', tracks: mapTracks(this.player) });\n }\n\n async getTracks(): Promise<MediaTrack[]> {\n if (!this.player) return [];\n return mapTracks(this.player);\n }\n}\n\nexport function createShakaEngineFactory(): EngineFactory {\n return {\n id: 'shaka',\n // Higher than native; only selected when it *should* be used.\n priority: 50,\n supports: (cfg: PlayerConfig) => {\n const t = cfg.source.type as any;\n const url = t === 'url' ? (cfg.source as any).url : (cfg.source as any).url;\n const looksLikeHls = typeof url === 'string' && /\\.m3u8($|\\?)/i.test(url);\n const looksLikeDash = typeof url === 'string' && /\\.mpd($|\\?)/i.test(url);\n const hasDrm = !!((cfg as any).drm ?? (cfg.source as any).drm);\n return t === 'hls' || t === 'dash' || looksLikeHls || looksLikeDash || hasDrm;\n },\n supportsWithCaps: (cfg: PlayerConfig, caps: PlaybackCapabilities) => {\n const t = cfg.source.type as any;\n const url = t === 'url' ? (cfg.source as any).url : (cfg.source as any).url;\n const looksLikeHls = typeof url === 'string' && /\\.m3u8($|\\?)/i.test(url);\n const looksLikeDash = typeof url === 'string' && /\\.mpd($|\\?)/i.test(url);\n const drm = ((cfg as any).drm ?? (cfg.source as any).drm) as any;\n const hasDrm = !!(drm && (drm.widevine || drm.playready || drm.fairplay || Object.keys(drm).length));\n\n // Shaka is an MSE engine.\n if (!caps.mse) return false;\n // DRM requires EME.\n if (hasDrm && !caps.eme) return false;\n\n return t === 'hls' || t === 'dash' || looksLikeHls || looksLikeDash || hasDrm;\n },\n create: () => new ShakaEngine()\n };\n}\n"],"mappings":"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","names":[]}
|
package/index.d.cts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { PlaybackEngine, EngineEvent, PlayerSource, LoadOptions, MediaTrack, EngineFactory } from '@ngxsp/core';
|
|
2
|
+
|
|
3
|
+
declare class ShakaEngine implements PlaybackEngine {
|
|
4
|
+
readonly id = "shaka";
|
|
5
|
+
private shaka;
|
|
6
|
+
private player;
|
|
7
|
+
private video;
|
|
8
|
+
private off;
|
|
9
|
+
private emit?;
|
|
10
|
+
private lastAbrRestrictions;
|
|
11
|
+
attach(videoEl: HTMLVideoElement): Promise<void>;
|
|
12
|
+
onEvent(cb: (ev: EngineEvent) => void): () => void;
|
|
13
|
+
private fire;
|
|
14
|
+
load(source: PlayerSource, opts?: LoadOptions): Promise<void>;
|
|
15
|
+
private configureAbr;
|
|
16
|
+
private autoTuneAbrWithMediaCapabilities;
|
|
17
|
+
destroy(): Promise<void>;
|
|
18
|
+
play(): Promise<void>;
|
|
19
|
+
pause(): Promise<void>;
|
|
20
|
+
seekTo(timeSec: number): Promise<void>;
|
|
21
|
+
setPlaybackRate(rate: number): Promise<void>;
|
|
22
|
+
setVolume(volume: number): Promise<void>;
|
|
23
|
+
setTextTrack(trackId: string | null): Promise<void>;
|
|
24
|
+
setAudioTrack(trackId: string | null): Promise<void>;
|
|
25
|
+
setVideoTrack(trackId: string | null): Promise<void>;
|
|
26
|
+
getTracks(): Promise<MediaTrack[]>;
|
|
27
|
+
}
|
|
28
|
+
declare function createShakaEngineFactory(): EngineFactory;
|
|
29
|
+
|
|
30
|
+
export { ShakaEngine, createShakaEngineFactory };
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { PlaybackEngine, EngineEvent, PlayerSource, LoadOptions, MediaTrack, EngineFactory } from '@ngxsp/core';
|
|
2
|
+
|
|
3
|
+
declare class ShakaEngine implements PlaybackEngine {
|
|
4
|
+
readonly id = "shaka";
|
|
5
|
+
private shaka;
|
|
6
|
+
private player;
|
|
7
|
+
private video;
|
|
8
|
+
private off;
|
|
9
|
+
private emit?;
|
|
10
|
+
private lastAbrRestrictions;
|
|
11
|
+
attach(videoEl: HTMLVideoElement): Promise<void>;
|
|
12
|
+
onEvent(cb: (ev: EngineEvent) => void): () => void;
|
|
13
|
+
private fire;
|
|
14
|
+
load(source: PlayerSource, opts?: LoadOptions): Promise<void>;
|
|
15
|
+
private configureAbr;
|
|
16
|
+
private autoTuneAbrWithMediaCapabilities;
|
|
17
|
+
destroy(): Promise<void>;
|
|
18
|
+
play(): Promise<void>;
|
|
19
|
+
pause(): Promise<void>;
|
|
20
|
+
seekTo(timeSec: number): Promise<void>;
|
|
21
|
+
setPlaybackRate(rate: number): Promise<void>;
|
|
22
|
+
setVolume(volume: number): Promise<void>;
|
|
23
|
+
setTextTrack(trackId: string | null): Promise<void>;
|
|
24
|
+
setAudioTrack(trackId: string | null): Promise<void>;
|
|
25
|
+
setVideoTrack(trackId: string | null): Promise<void>;
|
|
26
|
+
getTracks(): Promise<MediaTrack[]>;
|
|
27
|
+
}
|
|
28
|
+
declare function createShakaEngineFactory(): EngineFactory;
|
|
29
|
+
|
|
30
|
+
export { ShakaEngine, createShakaEngineFactory };
|
package/index.js
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
async function importShaka() {
|
|
3
|
+
const mod = await import("shaka-player");
|
|
4
|
+
return mod?.default ?? mod;
|
|
5
|
+
}
|
|
6
|
+
function sourceToUrl(source) {
|
|
7
|
+
const s = source;
|
|
8
|
+
if (typeof s.url === "string") return s.url;
|
|
9
|
+
throw new Error("Invalid source url");
|
|
10
|
+
}
|
|
11
|
+
function mapTracks(shaka) {
|
|
12
|
+
const out = [];
|
|
13
|
+
try {
|
|
14
|
+
const v = shaka.getVariantTracks?.() ?? [];
|
|
15
|
+
for (const t of v) {
|
|
16
|
+
out.push({
|
|
17
|
+
id: String(t.id),
|
|
18
|
+
kind: "audio",
|
|
19
|
+
language: t.language ?? "und",
|
|
20
|
+
label: t.label ?? t.language ?? "audio",
|
|
21
|
+
active: !!t.active
|
|
22
|
+
});
|
|
23
|
+
out.push({
|
|
24
|
+
id: `video:${t.id}`,
|
|
25
|
+
kind: "video",
|
|
26
|
+
label: formatVideoLabel(t),
|
|
27
|
+
active: !!t.active,
|
|
28
|
+
width: Number.isFinite(t.width) ? t.width : void 0,
|
|
29
|
+
height: Number.isFinite(t.height) ? t.height : void 0,
|
|
30
|
+
bandwidth: Number.isFinite(t.bandwidth) ? t.bandwidth : void 0
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
} catch {
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const tt = shaka.getTextTracks?.() ?? [];
|
|
37
|
+
for (const t of tt) {
|
|
38
|
+
out.push({
|
|
39
|
+
id: String(t.id),
|
|
40
|
+
kind: "text",
|
|
41
|
+
language: t.language ?? "und",
|
|
42
|
+
label: t.label ?? t.language ?? "subtitles",
|
|
43
|
+
active: !!t.active
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
function formatVideoLabel(track) {
|
|
51
|
+
const height = Number.isFinite(track?.height) ? `${track.height}p` : null;
|
|
52
|
+
const bandwidth = Number.isFinite(track?.bandwidth) ? `${(track.bandwidth / 1e6).toFixed(1)} Mbps` : null;
|
|
53
|
+
return [height, bandwidth].filter(Boolean).join(" \u2022 ") || "Quality";
|
|
54
|
+
}
|
|
55
|
+
var ShakaEngine = class {
|
|
56
|
+
id = "shaka";
|
|
57
|
+
shaka = null;
|
|
58
|
+
player = null;
|
|
59
|
+
video;
|
|
60
|
+
off = [];
|
|
61
|
+
emit;
|
|
62
|
+
lastAbrRestrictions = null;
|
|
63
|
+
async attach(videoEl) {
|
|
64
|
+
this.video = videoEl;
|
|
65
|
+
}
|
|
66
|
+
onEvent(cb) {
|
|
67
|
+
this.emit = cb;
|
|
68
|
+
return () => {
|
|
69
|
+
if (this.emit === cb) this.emit = void 0;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
fire(ev) {
|
|
73
|
+
try {
|
|
74
|
+
this.emit?.(ev);
|
|
75
|
+
} catch {
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async load(source, opts) {
|
|
79
|
+
const shaka = await importShaka();
|
|
80
|
+
if (!shaka?.Player) throw new Error("Shaka Player not available");
|
|
81
|
+
this.shaka = shaka;
|
|
82
|
+
try {
|
|
83
|
+
shaka.polyfill?.installAll?.();
|
|
84
|
+
} catch {
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
await this.player?.destroy?.();
|
|
88
|
+
} catch {
|
|
89
|
+
}
|
|
90
|
+
this.player = new shaka.Player(this.video);
|
|
91
|
+
try {
|
|
92
|
+
await this.configureAbr(this.player, source);
|
|
93
|
+
} catch {
|
|
94
|
+
}
|
|
95
|
+
const streamHints = source?._shakaStreaming;
|
|
96
|
+
if (streamHints) {
|
|
97
|
+
try {
|
|
98
|
+
this.player.configure({
|
|
99
|
+
streaming: {
|
|
100
|
+
...streamHints.lowLatencyMode != null ? { lowLatencyMode: streamHints.lowLatencyMode } : {},
|
|
101
|
+
...streamHints.bufferingGoalSec != null ? { bufferingGoal: streamHints.bufferingGoalSec } : {},
|
|
102
|
+
...streamHints.rebufferingGoalSec != null ? { rebufferingGoal: streamHints.rebufferingGoalSec } : {}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const anySrc = source;
|
|
109
|
+
const drm = anySrc?.drm;
|
|
110
|
+
if (drm?.servers || drm?.keySystems) {
|
|
111
|
+
const servers = { ...drm?.servers ?? {} };
|
|
112
|
+
const advanced = {};
|
|
113
|
+
const licenseHeadersByKs = {};
|
|
114
|
+
if (drm?.keySystems && typeof drm.keySystems === "object") {
|
|
115
|
+
for (const [ks, v] of Object.entries(drm.keySystems)) {
|
|
116
|
+
if (v?.licenseServerUrl) servers[ks] = String(v.licenseServerUrl);
|
|
117
|
+
if (v?.videoRobustness || v?.audioRobustness) {
|
|
118
|
+
advanced[ks] = {
|
|
119
|
+
videoRobustness: v.videoRobustness,
|
|
120
|
+
audioRobustness: v.audioRobustness
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (v?.headers) licenseHeadersByKs[ks] = { ...v.headers };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const retry = drm?.licenseRetry ?? {};
|
|
127
|
+
const retryParameters = {
|
|
128
|
+
maxAttempts: retry.maxAttempts ?? 3,
|
|
129
|
+
baseDelay: retry.baseDelayMs ?? 500,
|
|
130
|
+
backoffFactor: retry.backoffFactor ?? 2,
|
|
131
|
+
fuzzFactor: retry.fuzzFactor ?? 0.5,
|
|
132
|
+
timeout: retry.timeoutMs ?? 0
|
|
133
|
+
};
|
|
134
|
+
this.player.configure({
|
|
135
|
+
drm: {
|
|
136
|
+
servers,
|
|
137
|
+
advanced: Object.keys(advanced).length ? advanced : void 0,
|
|
138
|
+
retryParameters,
|
|
139
|
+
persistentStateRequired: !!drm?.persistentLicense
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
try {
|
|
143
|
+
const net = this.player.getNetworkingEngine?.();
|
|
144
|
+
const ReqType = shaka.net?.NetworkingEngine?.RequestType;
|
|
145
|
+
if (net?.registerRequestFilter && ReqType?.LICENSE != null) {
|
|
146
|
+
net.registerRequestFilter((type, request) => {
|
|
147
|
+
if (type !== ReqType.LICENSE) return;
|
|
148
|
+
const headers = {};
|
|
149
|
+
for (const h of Object.values(licenseHeadersByKs)) Object.assign(headers, h);
|
|
150
|
+
request.headers = { ...request.headers ?? {}, ...headers };
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
} catch {
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const onErrorEvent = (evt) => {
|
|
157
|
+
const detail = evt?.detail ?? evt;
|
|
158
|
+
const code = String(detail?.code ?? "SHAKA_ERROR");
|
|
159
|
+
const msg = detail?.message ? String(detail.message) : "Shaka error";
|
|
160
|
+
this.fire({ type: "error", error: { code, message: msg, fatal: true, details: detail } });
|
|
161
|
+
};
|
|
162
|
+
this.player.addEventListener("error", onErrorEvent);
|
|
163
|
+
this.off.push(() => this.player?.removeEventListener?.("error", onErrorEvent));
|
|
164
|
+
const url = sourceToUrl(source);
|
|
165
|
+
this.fire({ type: "state", state: "loading" });
|
|
166
|
+
await this.player.load(url);
|
|
167
|
+
this.fire({ type: "tracks", tracks: mapTracks(this.player) });
|
|
168
|
+
if (opts?.startTimeSec != null && Number.isFinite(opts.startTimeSec)) {
|
|
169
|
+
try {
|
|
170
|
+
await this.seekTo(opts.startTimeSec);
|
|
171
|
+
} catch {
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
this.fire({ type: "state", state: this.video.paused ? "paused" : "playing" });
|
|
175
|
+
}
|
|
176
|
+
async configureAbr(player, source) {
|
|
177
|
+
const hints = source?.abr;
|
|
178
|
+
const restrictions = {};
|
|
179
|
+
let reason = "";
|
|
180
|
+
if (hints?.maxBandwidth != null) restrictions.maxBandwidth = hints.maxBandwidth;
|
|
181
|
+
if (hints?.maxHeight != null) restrictions.maxHeight = hints.maxHeight;
|
|
182
|
+
if (!Object.keys(restrictions).length) {
|
|
183
|
+
const tuned = await this.autoTuneAbrWithMediaCapabilities();
|
|
184
|
+
if (tuned) {
|
|
185
|
+
Object.assign(restrictions, tuned);
|
|
186
|
+
reason = "mediaCapabilities";
|
|
187
|
+
}
|
|
188
|
+
} else {
|
|
189
|
+
reason = "source.abr";
|
|
190
|
+
}
|
|
191
|
+
if (!Object.keys(restrictions).length) return;
|
|
192
|
+
try {
|
|
193
|
+
player.configure({ abr: { restrictions } });
|
|
194
|
+
this.lastAbrRestrictions = { ...restrictions, reason };
|
|
195
|
+
} catch {
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async autoTuneAbrWithMediaCapabilities() {
|
|
199
|
+
const mc = globalThis.navigator?.mediaCapabilities;
|
|
200
|
+
if (!mc?.decodingInfo) return null;
|
|
201
|
+
try {
|
|
202
|
+
const info = await mc.decodingInfo({
|
|
203
|
+
type: "media-source",
|
|
204
|
+
video: {
|
|
205
|
+
contentType: 'video/mp4; codecs="avc1.640028"',
|
|
206
|
+
width: 1920,
|
|
207
|
+
height: 1080,
|
|
208
|
+
bitrate: 5e6,
|
|
209
|
+
framerate: 30
|
|
210
|
+
},
|
|
211
|
+
audio: {
|
|
212
|
+
contentType: 'audio/mp4; codecs="mp4a.40.2"',
|
|
213
|
+
channels: 2,
|
|
214
|
+
bitrate: 128e3,
|
|
215
|
+
samplerate: 48e3
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
if (info?.supported && info.smooth !== false && info.powerEfficient !== false) return null;
|
|
219
|
+
return { maxHeight: 720, maxBandwidth: 3e6 };
|
|
220
|
+
} catch {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
async destroy() {
|
|
225
|
+
try {
|
|
226
|
+
for (const fn of this.off.splice(0)) fn();
|
|
227
|
+
} catch {
|
|
228
|
+
}
|
|
229
|
+
try {
|
|
230
|
+
await this.player?.destroy?.();
|
|
231
|
+
} catch {
|
|
232
|
+
}
|
|
233
|
+
this.player = null;
|
|
234
|
+
this.shaka = null;
|
|
235
|
+
}
|
|
236
|
+
async play() {
|
|
237
|
+
await this.video.play();
|
|
238
|
+
this.fire({ type: "state", state: "playing" });
|
|
239
|
+
}
|
|
240
|
+
async pause() {
|
|
241
|
+
this.video.pause();
|
|
242
|
+
this.fire({ type: "state", state: "paused" });
|
|
243
|
+
}
|
|
244
|
+
async seekTo(timeSec) {
|
|
245
|
+
this.video.currentTime = Math.max(0, timeSec);
|
|
246
|
+
this.fire({ type: "timeupdate", currentTime: this.video.currentTime, duration: this.video.duration || 0 });
|
|
247
|
+
}
|
|
248
|
+
async setPlaybackRate(rate) {
|
|
249
|
+
this.video.playbackRate = rate;
|
|
250
|
+
}
|
|
251
|
+
async setVolume(volume) {
|
|
252
|
+
this.video.volume = Math.min(1, Math.max(0, volume));
|
|
253
|
+
}
|
|
254
|
+
async setTextTrack(trackId) {
|
|
255
|
+
if (!this.player?.selectTextTrack) return;
|
|
256
|
+
if (!trackId) {
|
|
257
|
+
try {
|
|
258
|
+
this.player.setTextTrackVisibility(false);
|
|
259
|
+
} catch {
|
|
260
|
+
}
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
const tracks = this.player.getTextTracks?.() ?? [];
|
|
265
|
+
const t = tracks.find((x) => String(x.id) === String(trackId));
|
|
266
|
+
if (t) {
|
|
267
|
+
this.player.selectTextTrack(t);
|
|
268
|
+
this.player.setTextTrackVisibility(true);
|
|
269
|
+
}
|
|
270
|
+
} catch {
|
|
271
|
+
}
|
|
272
|
+
this.fire({ type: "tracks", tracks: mapTracks(this.player) });
|
|
273
|
+
}
|
|
274
|
+
async setAudioTrack(trackId) {
|
|
275
|
+
if (!this.player?.selectVariantTrack || !trackId) return;
|
|
276
|
+
try {
|
|
277
|
+
const tracks = this.player.getVariantTracks?.() ?? [];
|
|
278
|
+
const t = tracks.find((x) => String(x.id) === String(trackId));
|
|
279
|
+
if (t) this.player.selectVariantTrack(t, true);
|
|
280
|
+
} catch {
|
|
281
|
+
}
|
|
282
|
+
this.fire({ type: "tracks", tracks: mapTracks(this.player) });
|
|
283
|
+
}
|
|
284
|
+
async setVideoTrack(trackId) {
|
|
285
|
+
if (!this.player?.selectVariantTrack) return;
|
|
286
|
+
try {
|
|
287
|
+
if (!trackId) {
|
|
288
|
+
this.player.configure?.({ abr: { enabled: true } });
|
|
289
|
+
} else {
|
|
290
|
+
const normalizedTrackId = String(trackId).replace(/^video:/, "");
|
|
291
|
+
const tracks = this.player.getVariantTracks?.() ?? [];
|
|
292
|
+
const t = tracks.find((x) => String(x.id) === normalizedTrackId);
|
|
293
|
+
if (t) {
|
|
294
|
+
this.player.configure?.({ abr: { enabled: false } });
|
|
295
|
+
this.player.selectVariantTrack(t, true);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
} catch {
|
|
299
|
+
}
|
|
300
|
+
this.fire({ type: "tracks", tracks: mapTracks(this.player) });
|
|
301
|
+
}
|
|
302
|
+
async getTracks() {
|
|
303
|
+
if (!this.player) return [];
|
|
304
|
+
return mapTracks(this.player);
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
function createShakaEngineFactory() {
|
|
308
|
+
return {
|
|
309
|
+
id: "shaka",
|
|
310
|
+
// Higher than native; only selected when it *should* be used.
|
|
311
|
+
priority: 50,
|
|
312
|
+
supports: (cfg) => {
|
|
313
|
+
const t = cfg.source.type;
|
|
314
|
+
const url = t === "url" ? cfg.source.url : cfg.source.url;
|
|
315
|
+
const looksLikeHls = typeof url === "string" && /\.m3u8($|\?)/i.test(url);
|
|
316
|
+
const looksLikeDash = typeof url === "string" && /\.mpd($|\?)/i.test(url);
|
|
317
|
+
const hasDrm = !!(cfg.drm ?? cfg.source.drm);
|
|
318
|
+
return t === "hls" || t === "dash" || looksLikeHls || looksLikeDash || hasDrm;
|
|
319
|
+
},
|
|
320
|
+
supportsWithCaps: (cfg, caps) => {
|
|
321
|
+
const t = cfg.source.type;
|
|
322
|
+
const url = t === "url" ? cfg.source.url : cfg.source.url;
|
|
323
|
+
const looksLikeHls = typeof url === "string" && /\.m3u8($|\?)/i.test(url);
|
|
324
|
+
const looksLikeDash = typeof url === "string" && /\.mpd($|\?)/i.test(url);
|
|
325
|
+
const drm = cfg.drm ?? cfg.source.drm;
|
|
326
|
+
const hasDrm = !!(drm && (drm.widevine || drm.playready || drm.fairplay || Object.keys(drm).length));
|
|
327
|
+
if (!caps.mse) return false;
|
|
328
|
+
if (hasDrm && !caps.eme) return false;
|
|
329
|
+
return t === "hls" || t === "dash" || looksLikeHls || looksLikeDash || hasDrm;
|
|
330
|
+
},
|
|
331
|
+
create: () => new ShakaEngine()
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
export {
|
|
335
|
+
ShakaEngine,
|
|
336
|
+
createShakaEngineFactory
|
|
337
|
+
};
|
|
338
|
+
//# sourceMappingURL=index.js.map
|
package/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type {\n PlaybackEngine,\n EngineEvent,\n LoadOptions,\n PlayerSource,\n MediaTrack,\n EngineFactory,\n PlayerConfig,\n PlaybackCapabilities\n} from '@ngxsp/core';\n\ntype ShakaNS = any;\n\nasync function importShaka(): Promise<ShakaNS> {\n // Use dynamic import to keep Shaka optional and avoid bundler static resolution issues.\n const mod: any = await import('shaka-player');\n return (mod?.default ?? mod) as ShakaNS;\n}\n\nfunction sourceToUrl(source: PlayerSource): string {\n const s: any = source as any;\n if (typeof s.url === 'string') return s.url;\n throw new Error('Invalid source url');\n}\n\nfunction mapTracks(shaka: any): MediaTrack[] {\n const out: MediaTrack[] = [];\n try {\n const v = shaka.getVariantTracks?.() ?? [];\n for (const t of v) {\n out.push({\n id: String(t.id),\n kind: 'audio',\n language: t.language ?? 'und',\n label: t.label ?? t.language ?? 'audio',\n active: !!t.active\n });\n out.push({\n id: `video:${t.id}`,\n kind: 'video',\n label: formatVideoLabel(t),\n active: !!t.active,\n width: Number.isFinite(t.width) ? t.width : undefined,\n height: Number.isFinite(t.height) ? t.height : undefined,\n bandwidth: Number.isFinite(t.bandwidth) ? t.bandwidth : undefined\n });\n }\n } catch {}\n try {\n const tt = shaka.getTextTracks?.() ?? [];\n for (const t of tt) {\n out.push({\n id: String(t.id),\n kind: 'text',\n language: t.language ?? 'und',\n label: t.label ?? t.language ?? 'subtitles',\n active: !!t.active\n });\n }\n } catch {}\n return out;\n}\n\nfunction formatVideoLabel(track: any): string {\n const height = Number.isFinite(track?.height) ? `${track.height}p` : null;\n const bandwidth =\n Number.isFinite(track?.bandwidth) ? `${(track.bandwidth / 1_000_000).toFixed(1)} Mbps` : null;\n return [height, bandwidth].filter(Boolean).join(' • ') || 'Quality';\n}\n\nexport class ShakaEngine implements PlaybackEngine {\n readonly id = 'shaka';\n\n private shaka: ShakaNS | null = null;\n private player: any | null = null;\n private video!: HTMLVideoElement;\n private off: Array<() => void> = [];\n private emit?: (ev: EngineEvent) => void;\n\n private lastAbrRestrictions: { maxHeight?: number; maxBandwidth?: number; reason?: string } | null = null;\n\n async attach(videoEl: HTMLVideoElement): Promise<void> {\n this.video = videoEl;\n }\n\n onEvent(cb: (ev: EngineEvent) => void): () => void {\n this.emit = cb;\n return () => { if (this.emit === cb) this.emit = undefined; };\n }\n\n private fire(ev: EngineEvent): void {\n try { this.emit?.(ev); } catch {}\n }\n\n async load(source: PlayerSource, opts?: LoadOptions): Promise<void> {\n const shaka: ShakaNS = await importShaka();\n if (!shaka?.Player) throw new Error('Shaka Player not available');\n this.shaka = shaka;\n\n try { shaka.polyfill?.installAll?.(); } catch {}\n\n // Clean previous player if any\n try { await this.player?.destroy?.(); } catch {}\n this.player = new shaka.Player(this.video);\n\n // ABR tuning (best-effort):\n // - explicit hints from source.abr\n // - implicit hints via MediaCapabilities probes\n try { await this.configureAbr(this.player, source); } catch {}\n\n // Profile streaming hints (best-effort): filled by core via `source._shakaStreaming`.\n const streamHints = (source as any)?._shakaStreaming as\n | { lowLatencyMode?: boolean; bufferingGoalSec?: number; rebufferingGoalSec?: number }\n | undefined;\n if (streamHints) {\n try {\n this.player.configure({\n streaming: {\n ...(streamHints.lowLatencyMode != null ? { lowLatencyMode: streamHints.lowLatencyMode } : {}),\n ...(streamHints.bufferingGoalSec != null ? { bufferingGoal: streamHints.bufferingGoalSec } : {}),\n ...(streamHints.rebufferingGoalSec != null ? { rebufferingGoal: streamHints.rebufferingGoalSec } : {})\n }\n });\n } catch {}\n }\n\n // DRM config if present\n const anySrc: any = source as any;\n const drm: any = anySrc?.drm;\n if (drm?.servers || drm?.keySystems) {\n const servers: Record<string, string> = { ...(drm?.servers ?? {}) };\n const advanced: Record<string, any> = {};\n const licenseHeadersByKs: Record<string, Record<string, string>> = {};\n\n if (drm?.keySystems && typeof drm.keySystems === \"object\") {\n for (const [ks, v] of Object.entries<any>(drm.keySystems)) {\n if (v?.licenseServerUrl) servers[ks] = String(v.licenseServerUrl);\n if (v?.videoRobustness || v?.audioRobustness) {\n advanced[ks] = {\n videoRobustness: v.videoRobustness,\n audioRobustness: v.audioRobustness\n };\n }\n if (v?.headers) licenseHeadersByKs[ks] = { ...v.headers };\n }\n }\n\n const retry = drm?.licenseRetry ?? {};\n const retryParameters = {\n maxAttempts: retry.maxAttempts ?? 3,\n baseDelay: retry.baseDelayMs ?? 500,\n backoffFactor: retry.backoffFactor ?? 2,\n fuzzFactor: retry.fuzzFactor ?? 0.5,\n timeout: retry.timeoutMs ?? 0\n };\n\n this.player.configure({\n drm: {\n servers,\n advanced: Object.keys(advanced).length ? advanced : undefined,\n retryParameters,\n persistentStateRequired: !!drm?.persistentLicense\n }\n });\n\n // Inject per-keysystem license headers (Widevine/PlayReady etc.)\n try {\n const net = this.player.getNetworkingEngine?.();\n const ReqType = (shaka as any).net?.NetworkingEngine?.RequestType;\n if (net?.registerRequestFilter && ReqType?.LICENSE != null) {\n net.registerRequestFilter((type: any, request: any) => {\n if (type !== ReqType.LICENSE) return;\n const headers: Record<string, string> = {};\n for (const h of Object.values(licenseHeadersByKs)) Object.assign(headers, h);\n request.headers = { ...(request.headers ?? {}), ...headers };\n });\n }\n } catch {}\n }\n\n // forward shaka errors\n const onErrorEvent = (evt: any) => {\n const detail = evt?.detail ?? evt;\n const code = String(detail?.code ?? 'SHAKA_ERROR');\n const msg = detail?.message ? String(detail.message) : 'Shaka error';\n this.fire({ type: 'error', error: { code, message: msg, fatal: true, details: detail } });\n };\n this.player.addEventListener('error', onErrorEvent);\n this.off.push(() => this.player?.removeEventListener?.('error', onErrorEvent));\n\n const url = sourceToUrl(source);\n this.fire({ type: 'state', state: 'loading' });\n await this.player.load(url);\n\n // initial tracks\n this.fire({ type: 'tracks', tracks: mapTracks(this.player) });\n\n // start time\n if (opts?.startTimeSec != null && Number.isFinite(opts.startTimeSec)) {\n try { await this.seekTo(opts.startTimeSec); } catch {}\n }\n\n this.fire({ type: 'state', state: this.video.paused ? 'paused' : 'playing' });\n }\n\n private async configureAbr(player: any, source: PlayerSource): Promise<void> {\n const hints = (source as any)?.abr as { maxHeight?: number; maxBandwidth?: number } | undefined;\n\n const restrictions: any = {};\n let reason = '';\n\n if (hints?.maxBandwidth != null) restrictions.maxBandwidth = hints.maxBandwidth;\n if (hints?.maxHeight != null) restrictions.maxHeight = hints.maxHeight;\n\n if (!Object.keys(restrictions).length) {\n const tuned = await this.autoTuneAbrWithMediaCapabilities();\n if (tuned) {\n Object.assign(restrictions, tuned);\n reason = 'mediaCapabilities';\n }\n } else {\n reason = 'source.abr';\n }\n\n if (!Object.keys(restrictions).length) return;\n\n try {\n player.configure({ abr: { restrictions } });\n this.lastAbrRestrictions = { ...restrictions, reason };\n } catch {\n // ignore\n }\n }\n\n private async autoTuneAbrWithMediaCapabilities(): Promise<{ maxHeight?: number; maxBandwidth?: number } | null> {\n const mc: any = (globalThis as any).navigator?.mediaCapabilities;\n if (!mc?.decodingInfo) return null;\n\n try {\n const info = await mc.decodingInfo({\n type: 'media-source',\n video: {\n contentType: 'video/mp4; codecs=\"avc1.640028\"',\n width: 1920,\n height: 1080,\n bitrate: 5000000,\n framerate: 30\n },\n audio: {\n contentType: 'audio/mp4; codecs=\"mp4a.40.2\"',\n channels: 2,\n bitrate: 128000,\n samplerate: 48000\n }\n });\n // If 1080p H264 is not power-efficient or not smooth, cap to conservative defaults.\n if (info?.supported && info.smooth !== false && info.powerEfficient !== false) return null;\n return { maxHeight: 720, maxBandwidth: 3000000 };\n } catch {\n return null;\n }\n }\n\n async destroy(): Promise<void> {\n try { for (const fn of this.off.splice(0)) fn(); } catch {}\n try { await this.player?.destroy?.(); } catch {}\n this.player = null;\n this.shaka = null;\n }\n\n async play(): Promise<void> {\n await this.video.play();\n this.fire({ type: 'state', state: 'playing' });\n }\n\n async pause(): Promise<void> {\n this.video.pause();\n this.fire({ type: 'state', state: 'paused' });\n }\n\n async seekTo(timeSec: number): Promise<void> {\n this.video.currentTime = Math.max(0, timeSec);\n this.fire({ type: 'timeupdate', currentTime: this.video.currentTime, duration: this.video.duration || 0 });\n }\n\n async setPlaybackRate(rate: number): Promise<void> {\n this.video.playbackRate = rate;\n }\n\n async setVolume(volume: number): Promise<void> {\n this.video.volume = Math.min(1, Math.max(0, volume));\n }\n\n async setTextTrack(trackId: string | null): Promise<void> {\n if (!this.player?.selectTextTrack) return;\n if (!trackId) {\n try { this.player.setTextTrackVisibility(false); } catch {}\n return;\n }\n try {\n const tracks = this.player.getTextTracks?.() ?? [];\n const t = tracks.find((x: any) => String(x.id) === String(trackId));\n if (t) {\n this.player.selectTextTrack(t);\n this.player.setTextTrackVisibility(true);\n }\n } catch {}\n this.fire({ type: 'tracks', tracks: mapTracks(this.player) });\n }\n\n async setAudioTrack(trackId: string | null): Promise<void> {\n if (!this.player?.selectVariantTrack || !trackId) return;\n try {\n const tracks = this.player.getVariantTracks?.() ?? [];\n const t = tracks.find((x: any) => String(x.id) === String(trackId));\n if (t) this.player.selectVariantTrack(t, true);\n } catch {}\n this.fire({ type: 'tracks', tracks: mapTracks(this.player) });\n }\n\n async setVideoTrack(trackId: string | null): Promise<void> {\n if (!this.player?.selectVariantTrack) return;\n try {\n if (!trackId) {\n this.player.configure?.({ abr: { enabled: true } });\n } else {\n const normalizedTrackId = String(trackId).replace(/^video:/, '');\n const tracks = this.player.getVariantTracks?.() ?? [];\n const t = tracks.find((x: any) => String(x.id) === normalizedTrackId);\n if (t) {\n this.player.configure?.({ abr: { enabled: false } });\n this.player.selectVariantTrack(t, true);\n }\n }\n } catch {}\n this.fire({ type: 'tracks', tracks: mapTracks(this.player) });\n }\n\n async getTracks(): Promise<MediaTrack[]> {\n if (!this.player) return [];\n return mapTracks(this.player);\n }\n}\n\nexport function createShakaEngineFactory(): EngineFactory {\n return {\n id: 'shaka',\n // Higher than native; only selected when it *should* be used.\n priority: 50,\n supports: (cfg: PlayerConfig) => {\n const t = cfg.source.type as any;\n const url = t === 'url' ? (cfg.source as any).url : (cfg.source as any).url;\n const looksLikeHls = typeof url === 'string' && /\\.m3u8($|\\?)/i.test(url);\n const looksLikeDash = typeof url === 'string' && /\\.mpd($|\\?)/i.test(url);\n const hasDrm = !!((cfg as any).drm ?? (cfg.source as any).drm);\n return t === 'hls' || t === 'dash' || looksLikeHls || looksLikeDash || hasDrm;\n },\n supportsWithCaps: (cfg: PlayerConfig, caps: PlaybackCapabilities) => {\n const t = cfg.source.type as any;\n const url = t === 'url' ? (cfg.source as any).url : (cfg.source as any).url;\n const looksLikeHls = typeof url === 'string' && /\\.m3u8($|\\?)/i.test(url);\n const looksLikeDash = typeof url === 'string' && /\\.mpd($|\\?)/i.test(url);\n const drm = ((cfg as any).drm ?? (cfg.source as any).drm) as any;\n const hasDrm = !!(drm && (drm.widevine || drm.playready || drm.fairplay || Object.keys(drm).length));\n\n // Shaka is an MSE engine.\n if (!caps.mse) return false;\n // DRM requires EME.\n if (hasDrm && !caps.eme) return false;\n\n return t === 'hls' || t === 'dash' || looksLikeHls || looksLikeDash || hasDrm;\n },\n create: () => new ShakaEngine()\n };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ngxsp/engine-shaka",
|
|
3
|
-
"version": "0.0.1-next.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
3
|
+
"version": "0.0.1-next.1",
|
|
4
|
+
"description": "Shaka-based playback engine for ngxsp audio and video runtimes.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"audio",
|
|
7
|
+
"video",
|
|
8
|
+
"media",
|
|
9
|
+
"player",
|
|
10
|
+
"shaka",
|
|
11
|
+
"dash",
|
|
12
|
+
"hls"
|
|
10
13
|
],
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "index.cjs",
|
|
16
|
+
"module": "index.js",
|
|
17
|
+
"types": "index.d.ts",
|
|
11
18
|
"sideEffects": false,
|
|
12
19
|
"dependencies": {
|
|
13
20
|
"shaka-player": "^5.0.2",
|
|
14
|
-
"@ngxsp/core": "0.0.1-next.
|
|
21
|
+
"@ngxsp/core": "0.0.1-next.1"
|
|
15
22
|
},
|
|
16
23
|
"exports": {
|
|
17
24
|
".": {
|
|
18
|
-
"types": "./
|
|
19
|
-
"import": "./
|
|
20
|
-
"require": "./
|
|
21
|
-
"default": "./
|
|
25
|
+
"types": "./index.d.ts",
|
|
26
|
+
"import": "./index.js",
|
|
27
|
+
"require": "./index.cjs",
|
|
28
|
+
"default": "./index.js"
|
|
22
29
|
}
|
|
23
30
|
}
|
|
24
31
|
}
|