@ngxsp/engine-shaka 0.0.1-next.1 → 0.1.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/LICENSE +21 -0
- package/README.md +76 -0
- package/index.cjs +13 -1
- package/index.cjs.map +1 -1
- package/index.js +13 -1
- package/index.js.map +1 -1
- package/package.json +3 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Cedvict
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# @ngxsp/engine-shaka
|
|
2
|
+
|
|
3
|
+
Shaka-based playback engine for the `@ngxsp/*` runtime stack.
|
|
4
|
+
|
|
5
|
+
## What It Provides
|
|
6
|
+
|
|
7
|
+
- Shaka-backed DASH and HLS playback
|
|
8
|
+
- media track mapping into `@ngxsp/core`
|
|
9
|
+
- quality and audio/text track selection
|
|
10
|
+
|
|
11
|
+
## Quick Start: HLS + DRM (Widevine)
|
|
12
|
+
|
|
13
|
+
Install the runtime, the engine, and Shaka:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm i @ngxsp/core @ngxsp/engine-shaka shaka-player
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Use `createDefaultConfig` from `@ngxsp/core` to build a complete `PlayerConfig`
|
|
20
|
+
without restating every mandatory sub-config, then register the Shaka engine via
|
|
21
|
+
`createShakaEngineFactory` and drive playback with `PlayerFacade`:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import {
|
|
25
|
+
PlayerFacade,
|
|
26
|
+
createDefaultConfig,
|
|
27
|
+
type PlayerConfig,
|
|
28
|
+
} from '@ngxsp/core';
|
|
29
|
+
import { createShakaEngineFactory } from '@ngxsp/engine-shaka';
|
|
30
|
+
|
|
31
|
+
// videoEl: HTMLVideoElement (e.g. an Angular @ViewChild('video') ElementRef)
|
|
32
|
+
const config: PlayerConfig = createDefaultConfig({
|
|
33
|
+
source: {
|
|
34
|
+
type: 'hls',
|
|
35
|
+
url: 'https://cdn.example.com/movie/master.m3u8',
|
|
36
|
+
},
|
|
37
|
+
drm: {
|
|
38
|
+
keySystems: {
|
|
39
|
+
'com.widevine.alpha': {
|
|
40
|
+
licenseServerUrl: 'https://drm.example.com/widevine',
|
|
41
|
+
headers: { Authorization: 'Bearer <token>' },
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
// Optional: override a single sub-config; the rest keeps sane defaults.
|
|
46
|
+
subtitles: { enabled: true, providers: ['local'], preferredLang: 'fr' },
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const facade = new PlayerFacade();
|
|
50
|
+
|
|
51
|
+
// Register the Shaka engine (it is selected automatically for HLS/DASH/DRM).
|
|
52
|
+
facade.attach(videoEl, [], config, undefined, [createShakaEngineFactory()]);
|
|
53
|
+
|
|
54
|
+
await facade.load(config);
|
|
55
|
+
await facade.play();
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`createDefaultConfig` fills `progress`, `ui`, `resilience`, `subtitles`,
|
|
59
|
+
`metadata`, and `ads` with defaults and shallow-merges any override you pass, so
|
|
60
|
+
only `source` is strictly required.
|
|
61
|
+
|
|
62
|
+
## Local Commands
|
|
63
|
+
|
|
64
|
+
From this directory:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
make help
|
|
68
|
+
make build
|
|
69
|
+
make clean
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Direct `pnpm` equivalent:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pnpm run build
|
|
76
|
+
```
|
package/index.cjs
CHANGED
|
@@ -97,6 +97,16 @@ var ShakaEngine = class {
|
|
|
97
97
|
lastAbrRestrictions = null;
|
|
98
98
|
async attach(videoEl) {
|
|
99
99
|
this.video = videoEl;
|
|
100
|
+
const listen = (type, event) => {
|
|
101
|
+
const listener = () => this.fire(event());
|
|
102
|
+
videoEl.addEventListener(type, listener);
|
|
103
|
+
this.off.push(() => videoEl.removeEventListener(type, listener));
|
|
104
|
+
};
|
|
105
|
+
listen("timeupdate", () => ({ type: "timeupdate", currentTime: videoEl.currentTime, duration: videoEl.duration || 0 }));
|
|
106
|
+
listen("playing", () => ({ type: "state", state: "playing" }));
|
|
107
|
+
listen("pause", () => ({ type: "state", state: "paused" }));
|
|
108
|
+
listen("waiting", () => ({ type: "state", state: "buffering" }));
|
|
109
|
+
listen("ended", () => ({ type: "state", state: "ended" }));
|
|
100
110
|
}
|
|
101
111
|
onEvent(cb) {
|
|
102
112
|
this.emit = cb;
|
|
@@ -284,7 +294,9 @@ var ShakaEngine = class {
|
|
|
284
294
|
this.video.playbackRate = rate;
|
|
285
295
|
}
|
|
286
296
|
async setVolume(volume) {
|
|
287
|
-
|
|
297
|
+
const level = Math.min(1, Math.max(0, volume));
|
|
298
|
+
this.video.volume = level;
|
|
299
|
+
this.video.muted = level <= 0;
|
|
288
300
|
}
|
|
289
301
|
async setTextTrack(trackId) {
|
|
290
302
|
if (!this.player?.selectTextTrack) return;
|
package/index.cjs.map
CHANGED
|
@@ -1 +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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,eAAe,cAAgC;AAE7C,QAAM,MAAW,MAAM,OAAO,cAAc;AAC5C,SAAQ,KAAK,WAAW;AAC1B;AAEA,SAAS,YAAY,QAA8B;AACjD,QAAM,IAAS;AACf,MAAI,OAAO,EAAE,QAAQ,SAAU,QAAO,EAAE;AACxC,QAAM,IAAI,MAAM,oBAAoB;AACtC;AAEA,SAAS,UAAU,OAA0B;AAC3C,QAAM,MAAoB,CAAC;AAC3B,MAAI;AACF,UAAM,IAAI,MAAM,mBAAmB,KAAK,CAAC;AACzC,eAAW,KAAK,GAAG;AACjB,UAAI,KAAK;AAAA,QACP,IAAI,OAAO,EAAE,EAAE;AAAA,QACf,MAAM;AAAA,QACN,UAAU,EAAE,YAAY;AAAA,QACxB,OAAO,EAAE,SAAS,EAAE,YAAY;AAAA,QAChC,QAAQ,CAAC,CAAC,EAAE;AAAA,MACd,CAAC;AACD,UAAI,KAAK;AAAA,QACP,IAAI,SAAS,EAAE,EAAE;AAAA,QACjB,MAAM;AAAA,QACN,OAAO,iBAAiB,CAAC;AAAA,QACzB,QAAQ,CAAC,CAAC,EAAE;AAAA,QACZ,OAAO,OAAO,SAAS,EAAE,KAAK,IAAI,EAAE,QAAQ;AAAA,QAC5C,QAAQ,OAAO,SAAS,EAAE,MAAM,IAAI,EAAE,SAAS;AAAA,QAC/C,WAAW,OAAO,SAAS,EAAE,SAAS,IAAI,EAAE,YAAY;AAAA,MAC1D,CAAC;AAAA,IACH;AAAA,EACF,QAAQ;AAAA,EAAC;AACT,MAAI;AACF,UAAM,KAAK,MAAM,gBAAgB,KAAK,CAAC;AACvC,eAAW,KAAK,IAAI;AAClB,UAAI,KAAK;AAAA,QACP,IAAI,OAAO,EAAE,EAAE;AAAA,QACf,MAAM;AAAA,QACN,UAAU,EAAE,YAAY;AAAA,QACxB,OAAO,EAAE,SAAS,EAAE,YAAY;AAAA,QAChC,QAAQ,CAAC,CAAC,EAAE;AAAA,MACd,CAAC;AAAA,IACH;AAAA,EACF,QAAQ;AAAA,EAAC;AACT,SAAO;AACT;AAEA,SAAS,iBAAiB,OAAoB;AAC5C,QAAM,SAAS,OAAO,SAAS,OAAO,MAAM,IAAI,GAAG,MAAM,MAAM,MAAM;AACrE,QAAM,YACJ,OAAO,SAAS,OAAO,SAAS,IAAI,IAAI,MAAM,YAAY,KAAW,QAAQ,CAAC,CAAC,UAAU;AAC3F,SAAO,CAAC,QAAQ,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,UAAK,KAAK;AAC5D;AAEO,IAAM,cAAN,MAA4C;AAAA,EACxC,KAAK;AAAA,EAEN,QAAwB;AAAA,EACxB,SAAqB;AAAA,EACrB;AAAA,EACA,MAAyB,CAAC;AAAA,EAC1B;AAAA,EAEA,sBAA6F;AAAA,EAErG,MAAM,OAAO,SAA0C;AACrD,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,QAAQ,IAA2C;AACjD,SAAK,OAAO;AACZ,WAAO,MAAM;AAAE,UAAI,KAAK,SAAS,GAAI,MAAK,OAAO;AAAA,IAAW;AAAA,EAC9D;AAAA,EAEQ,KAAK,IAAuB;AAClC,QAAI;AAAE,WAAK,OAAO,EAAE;AAAA,IAAG,QAAQ;AAAA,IAAC;AAAA,EAClC;AAAA,EAEA,MAAM,KAAK,QAAsB,MAAmC;AAClE,UAAM,QAAiB,MAAM,YAAY;AACzC,QAAI,CAAC,OAAO,OAAQ,OAAM,IAAI,MAAM,4BAA4B;AAChE,SAAK,QAAQ;AAEb,QAAI;AAAE,YAAM,UAAU,aAAa;AAAA,IAAG,QAAQ;AAAA,IAAC;AAG/C,QAAI;AAAE,YAAM,KAAK,QAAQ,UAAU;AAAA,IAAG,QAAQ;AAAA,IAAC;AAC/C,SAAK,SAAS,IAAI,MAAM,OAAO,KAAK,KAAK;AAKzC,QAAI;AAAE,YAAM,KAAK,aAAa,KAAK,QAAQ,MAAM;AAAA,IAAG,QAAQ;AAAA,IAAC;AAG7D,UAAM,cAAe,QAAgB;AAGrC,QAAI,aAAa;AACf,UAAI;AACF,aAAK,OAAO,UAAU;AAAA,UACpB,WAAW;AAAA,YACT,GAAI,YAAY,kBAAkB,OAAO,EAAE,gBAAgB,YAAY,eAAe,IAAI,CAAC;AAAA,YAC3F,GAAI,YAAY,oBAAoB,OAAO,EAAE,eAAe,YAAY,iBAAiB,IAAI,CAAC;AAAA,YAC9F,GAAI,YAAY,sBAAsB,OAAO,EAAE,iBAAiB,YAAY,mBAAmB,IAAI,CAAC;AAAA,UACtG;AAAA,QACF,CAAC;AAAA,MACH,QAAQ;AAAA,MAAC;AAAA,IACX;AAGA,UAAM,SAAc;AACpB,UAAM,MAAW,QAAQ;AACzB,QAAI,KAAK,WAAW,KAAK,YAAY;AACnC,YAAM,UAAkC,EAAE,GAAI,KAAK,WAAW,CAAC,EAAG;AAClE,YAAM,WAAgC,CAAC;AACvC,YAAM,qBAA6D,CAAC;AAEpE,UAAI,KAAK,cAAc,OAAO,IAAI,eAAe,UAAU;AACzD,mBAAW,CAAC,IAAI,CAAC,KAAK,OAAO,QAAa,IAAI,UAAU,GAAG;AACzD,cAAI,GAAG,iBAAkB,SAAQ,EAAE,IAAI,OAAO,EAAE,gBAAgB;AAChE,cAAI,GAAG,mBAAmB,GAAG,iBAAiB;AAC5C,qBAAS,EAAE,IAAI;AAAA,cACb,iBAAiB,EAAE;AAAA,cACnB,iBAAiB,EAAE;AAAA,YACrB;AAAA,UACF;AACA,cAAI,GAAG,QAAS,oBAAmB,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ;AAAA,QAC1D;AAAA,MACF;AAEA,YAAM,QAAQ,KAAK,gBAAgB,CAAC;AACpC,YAAM,kBAAkB;AAAA,QACtB,aAAa,MAAM,eAAe;AAAA,QAClC,WAAW,MAAM,eAAe;AAAA,QAChC,eAAe,MAAM,iBAAiB;AAAA,QACtC,YAAY,MAAM,cAAc;AAAA,QAChC,SAAS,MAAM,aAAa;AAAA,MAC9B;AAEA,WAAK,OAAO,UAAU;AAAA,QACpB,KAAK;AAAA,UACH;AAAA,UACA,UAAU,OAAO,KAAK,QAAQ,EAAE,SAAS,WAAW;AAAA,UACpD;AAAA,UACA,yBAAyB,CAAC,CAAC,KAAK;AAAA,QAClC;AAAA,MACF,CAAC;AAGD,UAAI;AACF,cAAM,MAAM,KAAK,OAAO,sBAAsB;AAC9C,cAAM,UAAW,MAAc,KAAK,kBAAkB;AACtD,YAAI,KAAK,yBAAyB,SAAS,WAAW,MAAM;AAC1D,cAAI,sBAAsB,CAAC,MAAW,YAAiB;AACrD,gBAAI,SAAS,QAAQ,QAAS;AAC9B,kBAAM,UAAkC,CAAC;AACzC,uBAAW,KAAK,OAAO,OAAO,kBAAkB,EAAG,QAAO,OAAO,SAAS,CAAC;AAC3E,oBAAQ,UAAU,EAAE,GAAI,QAAQ,WAAW,CAAC,GAAI,GAAG,QAAQ;AAAA,UAC7D,CAAC;AAAA,QACH;AAAA,MACF,QAAQ;AAAA,MAAC;AAAA,IACX;AAGA,UAAM,eAAe,CAAC,QAAa;AACjC,YAAM,SAAS,KAAK,UAAU;AAC9B,YAAM,OAAO,OAAO,QAAQ,QAAQ,aAAa;AACjD,YAAM,MAAM,QAAQ,UAAU,OAAO,OAAO,OAAO,IAAI;AACvD,WAAK,KAAK,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,KAAK,OAAO,MAAM,SAAS,OAAO,EAAE,CAAC;AAAA,IAC1F;AACA,SAAK,OAAO,iBAAiB,SAAS,YAAY;AAClD,SAAK,IAAI,KAAK,MAAM,KAAK,QAAQ,sBAAsB,SAAS,YAAY,CAAC;AAE7E,UAAM,MAAM,YAAY,MAAM;AAC9B,SAAK,KAAK,EAAE,MAAM,SAAS,OAAO,UAAU,CAAC;AAC7C,UAAM,KAAK,OAAO,KAAK,GAAG;AAG1B,SAAK,KAAK,EAAE,MAAM,UAAU,QAAQ,UAAU,KAAK,MAAM,EAAE,CAAC;AAG5D,QAAI,MAAM,gBAAgB,QAAQ,OAAO,SAAS,KAAK,YAAY,GAAG;AACpE,UAAI;AAAE,cAAM,KAAK,OAAO,KAAK,YAAY;AAAA,MAAG,QAAQ;AAAA,MAAC;AAAA,IACvD;AAEA,SAAK,KAAK,EAAE,MAAM,SAAS,OAAO,KAAK,MAAM,SAAS,WAAW,UAAU,CAAC;AAAA,EAC9E;AAAA,EAEA,MAAc,aAAa,QAAa,QAAqC;AAC3E,UAAM,QAAS,QAAgB;AAE/B,UAAM,eAAoB,CAAC;AAC3B,QAAI,SAAS;AAEb,QAAI,OAAO,gBAAgB,KAAM,cAAa,eAAe,MAAM;AACnE,QAAI,OAAO,aAAa,KAAM,cAAa,YAAY,MAAM;AAE7D,QAAI,CAAC,OAAO,KAAK,YAAY,EAAE,QAAQ;AACrC,YAAM,QAAQ,MAAM,KAAK,iCAAiC;AAC1D,UAAI,OAAO;AACT,eAAO,OAAO,cAAc,KAAK;AACjC,iBAAS;AAAA,MACX;AAAA,IACF,OAAO;AACL,eAAS;AAAA,IACX;AAEA,QAAI,CAAC,OAAO,KAAK,YAAY,EAAE,OAAQ;AAEvC,QAAI;AACF,aAAO,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;AAC1C,WAAK,sBAAsB,EAAE,GAAG,cAAc,OAAO;AAAA,IACvD,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,MAAc,mCAAkG;AAC9G,UAAM,KAAW,WAAmB,WAAW;AAC/C,QAAI,CAAC,IAAI,aAAc,QAAO;AAE9B,QAAI;AACF,YAAM,OAAO,MAAM,GAAG,aAAa;AAAA,QACjC,MAAM;AAAA,QACN,OAAO;AAAA,UACL,aAAa;AAAA,UACb,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,WAAW;AAAA,QACb;AAAA,QACA,OAAO;AAAA,UACL,aAAa;AAAA,UACb,UAAU;AAAA,UACV,SAAS;AAAA,UACT,YAAY;AAAA,QACd;AAAA,MACF,CAAC;AAED,UAAI,MAAM,aAAa,KAAK,WAAW,SAAS,KAAK,mBAAmB,MAAO,QAAO;AACtF,aAAO,EAAE,WAAW,KAAK,cAAc,IAAQ;AAAA,IACjD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,UAAyB;AAC7B,QAAI;AAAE,iBAAW,MAAM,KAAK,IAAI,OAAO,CAAC,EAAG,IAAG;AAAA,IAAG,QAAQ;AAAA,IAAC;AAC1D,QAAI;AAAE,YAAM,KAAK,QAAQ,UAAU;AAAA,IAAG,QAAQ;AAAA,IAAC;AAC/C,SAAK,SAAS;AACd,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,MAAM,OAAsB;AAC1B,UAAM,KAAK,MAAM,KAAK;AACtB,SAAK,KAAK,EAAE,MAAM,SAAS,OAAO,UAAU,CAAC;AAAA,EAC/C;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,MAAM,MAAM;AACjB,SAAK,KAAK,EAAE,MAAM,SAAS,OAAO,SAAS,CAAC;AAAA,EAC9C;AAAA,EAEA,MAAM,OAAO,SAAgC;AAC3C,SAAK,MAAM,cAAc,KAAK,IAAI,GAAG,OAAO;AAC5C,SAAK,KAAK,EAAE,MAAM,cAAc,aAAa,KAAK,MAAM,aAAa,UAAU,KAAK,MAAM,YAAY,EAAE,CAAC;AAAA,EAC3G;AAAA,EAEA,MAAM,gBAAgB,MAA6B;AACjD,SAAK,MAAM,eAAe;AAAA,EAC5B;AAAA,EAEA,MAAM,UAAU,QAA+B;AAC7C,SAAK,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC;AAAA,EACrD;AAAA,EAEA,MAAM,aAAa,SAAuC;AACxD,QAAI,CAAC,KAAK,QAAQ,gBAAiB;AACnC,QAAI,CAAC,SAAS;AACZ,UAAI;AAAE,aAAK,OAAO,uBAAuB,KAAK;AAAA,MAAG,QAAQ;AAAA,MAAC;AAC1D;AAAA,IACF;AACA,QAAI;AACF,YAAM,SAAS,KAAK,OAAO,gBAAgB,KAAK,CAAC;AACjD,YAAM,IAAI,OAAO,KAAK,CAAC,MAAW,OAAO,EAAE,EAAE,MAAM,OAAO,OAAO,CAAC;AAClE,UAAI,GAAG;AACL,aAAK,OAAO,gBAAgB,CAAC;AAC7B,aAAK,OAAO,uBAAuB,IAAI;AAAA,MACzC;AAAA,IACF,QAAQ;AAAA,IAAC;AACT,SAAK,KAAK,EAAE,MAAM,UAAU,QAAQ,UAAU,KAAK,MAAM,EAAE,CAAC;AAAA,EAC9D;AAAA,EAEA,MAAM,cAAc,SAAuC;AACzD,QAAI,CAAC,KAAK,QAAQ,sBAAsB,CAAC,QAAS;AAClD,QAAI;AACF,YAAM,SAAS,KAAK,OAAO,mBAAmB,KAAK,CAAC;AACpD,YAAM,IAAI,OAAO,KAAK,CAAC,MAAW,OAAO,EAAE,EAAE,MAAM,OAAO,OAAO,CAAC;AAClE,UAAI,EAAG,MAAK,OAAO,mBAAmB,GAAG,IAAI;AAAA,IAC/C,QAAQ;AAAA,IAAC;AACT,SAAK,KAAK,EAAE,MAAM,UAAU,QAAQ,UAAU,KAAK,MAAM,EAAE,CAAC;AAAA,EAC9D;AAAA,EAEA,MAAM,cAAc,SAAuC;AACzD,QAAI,CAAC,KAAK,QAAQ,mBAAoB;AACtC,QAAI;AACF,UAAI,CAAC,SAAS;AACZ,aAAK,OAAO,YAAY,EAAE,KAAK,EAAE,SAAS,KAAK,EAAE,CAAC;AAAA,MACpD,OAAO;AACL,cAAM,oBAAoB,OAAO,OAAO,EAAE,QAAQ,WAAW,EAAE;AAC/D,cAAM,SAAS,KAAK,OAAO,mBAAmB,KAAK,CAAC;AACpD,cAAM,IAAI,OAAO,KAAK,CAAC,MAAW,OAAO,EAAE,EAAE,MAAM,iBAAiB;AACpE,YAAI,GAAG;AACL,eAAK,OAAO,YAAY,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;AACnD,eAAK,OAAO,mBAAmB,GAAG,IAAI;AAAA,QACxC;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAAC;AACT,SAAK,KAAK,EAAE,MAAM,UAAU,QAAQ,UAAU,KAAK,MAAM,EAAE,CAAC;AAAA,EAC9D;AAAA,EAEA,MAAM,YAAmC;AACvC,QAAI,CAAC,KAAK,OAAQ,QAAO,CAAC;AAC1B,WAAO,UAAU,KAAK,MAAM;AAAA,EAC9B;AACF;AAEO,SAAS,2BAA0C;AACxD,SAAO;AAAA,IACL,IAAI;AAAA;AAAA,IAEJ,UAAU;AAAA,IACV,UAAU,CAAC,QAAsB;AAC/B,YAAM,IAAI,IAAI,OAAO;AACrB,YAAM,MAAM,MAAM,QAAS,IAAI,OAAe,MAAO,IAAI,OAAe;AACxE,YAAM,eAAe,OAAO,QAAQ,YAAY,gBAAgB,KAAK,GAAG;AACxE,YAAM,gBAAgB,OAAO,QAAQ,YAAY,eAAe,KAAK,GAAG;AACxE,YAAM,SAAS,CAAC,EAAG,IAAY,OAAQ,IAAI,OAAe;AAC1D,aAAO,MAAM,SAAS,MAAM,UAAU,gBAAgB,iBAAiB;AAAA,IACzE;AAAA,IACA,kBAAkB,CAAC,KAAmB,SAA+B;AACnE,YAAM,IAAI,IAAI,OAAO;AACrB,YAAM,MAAM,MAAM,QAAS,IAAI,OAAe,MAAO,IAAI,OAAe;AACxE,YAAM,eAAe,OAAO,QAAQ,YAAY,gBAAgB,KAAK,GAAG;AACxE,YAAM,gBAAgB,OAAO,QAAQ,YAAY,eAAe,KAAK,GAAG;AACxE,YAAM,MAAQ,IAAY,OAAQ,IAAI,OAAe;AACrD,YAAM,SAAS,CAAC,EAAE,QAAQ,IAAI,YAAY,IAAI,aAAa,IAAI,YAAY,OAAO,KAAK,GAAG,EAAE;AAG5F,UAAI,CAAC,KAAK,IAAK,QAAO;AAEtB,UAAI,UAAU,CAAC,KAAK,IAAK,QAAO;AAEhC,aAAO,MAAM,SAAS,MAAM,UAAU,gBAAgB,iBAAiB;AAAA,IACzE;AAAA,IACA,QAAQ,MAAM,IAAI,YAAY;AAAA,EAChC;AACF;","names":[]}
|
|
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 // Shaka plays through the element itself: its time and state are the element's, as with the native engine.\n // Without them the controls keep showing 0:00 and the host never hears the position to resume from.\n const listen = (type: string, event: () => EngineEvent) => {\n const listener = () => this.fire(event());\n videoEl.addEventListener(type, listener);\n this.off.push(() => videoEl.removeEventListener(type, listener));\n };\n listen('timeupdate', () => ({ type: 'timeupdate', currentTime: videoEl.currentTime, duration: videoEl.duration || 0 }));\n listen('playing', () => ({ type: 'state', state: 'playing' }));\n listen('pause', () => ({ type: 'state', state: 'paused' }));\n listen('waiting', () => ({ type: 'state', state: 'buffering' }));\n listen('ended', () => ({ type: 'state', state: 'ended' }));\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 const level = Math.min(1, Math.max(0, volume));\n this.video.volume = level;\n // iOS ignores volume writes on media elements: muting is the only way to silence playback there.\n this.video.muted = level <= 0;\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.js
CHANGED
|
@@ -62,6 +62,16 @@ var ShakaEngine = class {
|
|
|
62
62
|
lastAbrRestrictions = null;
|
|
63
63
|
async attach(videoEl) {
|
|
64
64
|
this.video = videoEl;
|
|
65
|
+
const listen = (type, event) => {
|
|
66
|
+
const listener = () => this.fire(event());
|
|
67
|
+
videoEl.addEventListener(type, listener);
|
|
68
|
+
this.off.push(() => videoEl.removeEventListener(type, listener));
|
|
69
|
+
};
|
|
70
|
+
listen("timeupdate", () => ({ type: "timeupdate", currentTime: videoEl.currentTime, duration: videoEl.duration || 0 }));
|
|
71
|
+
listen("playing", () => ({ type: "state", state: "playing" }));
|
|
72
|
+
listen("pause", () => ({ type: "state", state: "paused" }));
|
|
73
|
+
listen("waiting", () => ({ type: "state", state: "buffering" }));
|
|
74
|
+
listen("ended", () => ({ type: "state", state: "ended" }));
|
|
65
75
|
}
|
|
66
76
|
onEvent(cb) {
|
|
67
77
|
this.emit = cb;
|
|
@@ -249,7 +259,9 @@ var ShakaEngine = class {
|
|
|
249
259
|
this.video.playbackRate = rate;
|
|
250
260
|
}
|
|
251
261
|
async setVolume(volume) {
|
|
252
|
-
|
|
262
|
+
const level = Math.min(1, Math.max(0, volume));
|
|
263
|
+
this.video.volume = level;
|
|
264
|
+
this.video.muted = level <= 0;
|
|
253
265
|
}
|
|
254
266
|
async setTextTrack(trackId) {
|
|
255
267
|
if (!this.player?.selectTextTrack) return;
|
package/index.js.map
CHANGED
|
@@ -1 +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":[]}
|
|
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 // Shaka plays through the element itself: its time and state are the element's, as with the native engine.\n // Without them the controls keep showing 0:00 and the host never hears the position to resume from.\n const listen = (type: string, event: () => EngineEvent) => {\n const listener = () => this.fire(event());\n videoEl.addEventListener(type, listener);\n this.off.push(() => videoEl.removeEventListener(type, listener));\n };\n listen('timeupdate', () => ({ type: 'timeupdate', currentTime: videoEl.currentTime, duration: videoEl.duration || 0 }));\n listen('playing', () => ({ type: 'state', state: 'playing' }));\n listen('pause', () => ({ type: 'state', state: 'paused' }));\n listen('waiting', () => ({ type: 'state', state: 'buffering' }));\n listen('ended', () => ({ type: 'state', state: 'ended' }));\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 const level = Math.min(1, Math.max(0, volume));\n this.video.volume = level;\n // iOS ignores volume writes on media elements: muting is the only way to silence playback there.\n this.video.muted = level <= 0;\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,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ngxsp/engine-shaka",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
4
5
|
"description": "Shaka-based playback engine for ngxsp audio and video runtimes.",
|
|
5
6
|
"keywords": [
|
|
6
7
|
"audio",
|
|
@@ -18,7 +19,7 @@
|
|
|
18
19
|
"sideEffects": false,
|
|
19
20
|
"dependencies": {
|
|
20
21
|
"shaka-player": "^5.0.2",
|
|
21
|
-
"@ngxsp/core": "0.
|
|
22
|
+
"@ngxsp/core": "^0.1.0"
|
|
22
23
|
},
|
|
23
24
|
"exports": {
|
|
24
25
|
".": {
|