mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 18:36:15 -08:00
docs: document DASH + ClearKey playback architecture
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b838e2c2dd
commit
4e16729bf6
2 files changed
+78
No files matched your search
@@ -615,6 +615,19 @@ This project uses modern Angular signal-based APIs and patterns. **ALWAYS** use
|
||||
**Video Players**:
|
||||
|
||||
- Built-in web players: HTML5+hls.js, Video.js, and ArtPlayer
|
||||
- DASH + ClearKey (M3U module): `.mpd` channels play through a lazily loaded
|
||||
Shaka Player source engine inside the HTML5 and ArtPlayer components (no new
|
||||
player in settings). ClearKey keys come from `#KODIPROP:inputstream.adaptive.*`
|
||||
lines, post-processed into `Channel.drm` by `extractDrmFromRaw()` in
|
||||
`libs/shared/m3u-utils` (hooked in `createPlaylistObject()`, covering all
|
||||
import paths). DASH channels always play inline: `isDashChannel()` bypasses
|
||||
the external-player setting (radio precedent) and routes Video.js/MPV/VLC/
|
||||
embedded-MPV users to the HTML5 player via `playerOverride` (ArtPlayer keeps
|
||||
ArtPlayer). Unsupported license types (Widevine/PlayReady — out of scope,
|
||||
need the castLabs Electron fork) surface a DRM playback diagnostic instead
|
||||
of crashing. ClearKey EME works in stock Electron. Engine:
|
||||
`libs/ui/playback/src/lib/shaka-engine/`; details in
|
||||
`docs/architecture/m3u-playlist-module.md` ("DASH + ClearKey Playback").
|
||||
- External players: MPV, VLC (via IPC to Electron backend)
|
||||
- Embedded MPV (experimental, macOS/Windows/Linux): renders mpv video inside the Electron window through a native addon. macOS uses the libmpv render API in an `NSOpenGLView`; Windows uses in-process libmpv with `--wid` against an app-owned child `HWND`; Linux spawns an out-of-process `mpv --wid=<x11-window>` controlled over a JSON IPC socket (X11/XWayland only, requires system `mpv` on PATH; subtitles/speed/aspect/recording are not exported there). mpv's own screensaver inhibition does not apply to any of these paths, so `EmbeddedMpvNativeService` holds an Electron `powerSaveBlocker` (`prevent-display-sleep`) whenever any session's status is `playing`, and releases it on pause, dispose, or shutdown. Service: `apps/electron-backend/src/app/services/embedded-mpv-native.service.ts`; full architecture: `docs/architecture/embedded-mpv-native.md`.
|
||||
- Embedded MPV frame-copy engine (experimental, macOS Apple Silicon + Linux + Windows; enabled via `Settings > Playback > Embedded MPV: frame-copy engine` (restart required) or `IPTVNATOR_ENABLE_EMBEDDED_MPV_FRAME_COPY=1` on top of the embedded MPV experiment flag): a per-session helper renders mpv offscreen at viewport size (headless CGL on macOS, headless EGL on Linux, WGL against a hidden window on Windows) and publishes BGRA frames into a shm ring (POSIX shm; a `Local\` named file mapping on Windows); the preload frame pump uploads them onto a renderer `<canvas data-embedded-mpv-frame>`, so controls/dialogs are ordinary DOM above the video. Frame-copy is the first runtime consumer of shared `app-player-controls`: `PlayerControlsComponent` and its surface/shortcut/fullscreen collaborators own the DOM UI interactions, while the component-scoped `EmbeddedMpvControlsAdapter` maps session state and commands and coordinates correlated recording state; native-view retains the legacy fixed dock. Stored and explicit opt-ins relax the sandbox only while the base embedded-MPV feature is enabled and a platform-supported packaged runtime contains both the regular-file helper (`iptvnator_mpv_helper` / `.exe`) and readable regular frame-reader addon; packaged discovery is restricted to packaged resources. A disabled base experiment keeps embedded MPV unavailable with the sandbox intact, while a missing, mode-stripped, or incomplete frame-copy runtime falls back to the native engine without relaxing the sandbox. On Linux the engine is dev-build-only for now: the helper links system libmpv (build deps: `libmpv-dev`, `libegl-dev`, `libgl-dev`, `libopengl-dev`, `libgbm-dev`) and is stripped from packages until bundled-runtime staging lands. On Windows the helper links vendored libmpv and package validation requires the exact MPV DLL named in the helper's PE import table beside the executable. Backend process adapter: `apps/electron-backend/src/app/services/embedded-mpv-frame-copy.adapter.ts`; shared-controls adapter: `libs/ui/playback/src/lib/embedded-mpv-player/embedded-mpv-controls.adapter.ts`; helper: `apps/electron-backend/native/helper/`; details in `docs/architecture/embedded-mpv-native.md` ("Frame-Copy Engine").
|
||||
|
||||
@@ -663,6 +663,69 @@ class EpgService {
|
||||
for a programme the user clicked, both hosts surface a
|
||||
`EPG.TIMELINE.CATCHUP_FAILED` snackbar instead of doing nothing.
|
||||
|
||||
### DASH + ClearKey Playback
|
||||
|
||||
MPEG-DASH (`.mpd`) channels play through a Shaka Player *source engine* inside
|
||||
the existing built-in players — exactly like hls.js/mpegts.js. There is no new
|
||||
player in settings.
|
||||
|
||||
**DRM data flow** (M3U module only; Xtream/Stalker have no DRM concept):
|
||||
|
||||
1. The playlist parser fork does not understand `#KODIPROP:` lines, but keeps
|
||||
every unknown line between `#EXTINF` and the stream URL in `item.raw` (the
|
||||
dominant Kodi/TiviMate layout; `#KODIPROP` lines *before* `#EXTINF` are
|
||||
dropped by the parser — fixing that requires a parser-fork patch and is
|
||||
deferred).
|
||||
2. `extractDrmFromRaw()` (`libs/shared/m3u-utils/src/lib/kodiprop.utils.ts`)
|
||||
post-processes `raw` inside `createPlaylistObject()` — the single funnel
|
||||
for all four import paths (Electron URL/file import, refresh worker,
|
||||
web-backend `/parse`, client-side upload). It reads
|
||||
`inputstream.adaptive.license_type`, `license_key`, and the combined
|
||||
`drm_legacy` property. ClearKey key formats: `kid:key` hex (single or
|
||||
comma-separated), the W3C ClearKey license JSON, and a plain `{kid: key}`
|
||||
JSON map. Unsupported license types (Widevine, PlayReady, license-server
|
||||
URLs, malformed values) are preserved as `supported: false` — never a
|
||||
throw.
|
||||
3. The typed result lands on `Channel.drm` (`ChannelDrm` in
|
||||
`@iptvnator/shared/interfaces`), travels through
|
||||
`ResolvedPortalPlayback.drm` into `WebPlayerViewComponent`'s synthetic
|
||||
channel, and reaches the engine. Persistence is free (playlist JSON blob /
|
||||
IndexedDB object).
|
||||
|
||||
**Engine selection and routing:**
|
||||
|
||||
- `ShakaVideoSession` (`libs/ui/playback/src/lib/shaka-engine/`) owns the
|
||||
engine: lazy `import('shaka-player')` on first use (the module is a separate
|
||||
lazy chunk, ~217 KB transfer), `drm.clearKeys` configuration, an operation
|
||||
queue + generation guard against channel-switch races, and Shaka-error →
|
||||
`PlaybackDiagnostic` classification (`PlaybackDiagnosticSource.Shaka`).
|
||||
Channels with `drm.supported === false` emit a `DrmOrEncryption` diagnostic
|
||||
without starting an engine.
|
||||
- HTML5 player: `extension === 'mpd'` branch in `playChannel()`. ArtPlayer:
|
||||
`customType.mpd` in `ArtPlayerSourceSession`. Shared-controls bridge:
|
||||
`WebVideoControlsSource` kind `'shaka'` + `WebVideoShakaControls`
|
||||
(audio/text tracks via the Shaka 5 API — selecting a text track shows it,
|
||||
`selectTextTrack(null)` hides).
|
||||
- DASH channels always play inline (radio precedent): `isDashChannel()` gates
|
||||
`shouldShowInlinePlayer()`, the MPV/VLC auto-launch in `m3u-state` effects
|
||||
(`shouldAutoLaunchExternalPlayer()`), and the `playerOverride` passed to
|
||||
`app-web-player-view` — ArtPlayer stays ArtPlayer, every other configured
|
||||
player (Video.js without a DASH bridge, embedded/external MPV, VLC) falls
|
||||
back to the HTML5 player. External players cannot receive KODIPROP ClearKey
|
||||
configuration (VLC upstream feature request #29465).
|
||||
- ClearKey EME works in stock Electron (`org.w3.clearkey`; no Widevine CDM
|
||||
required) — EME needs a secure context, which `file://` (packaged) and
|
||||
`http://localhost` (dev/PWA) both satisfy. Widevine/FairPlay are out of
|
||||
scope (castLabs fork + VMP signing).
|
||||
|
||||
**Testing:** offline VP9+Opus CENC fixtures in
|
||||
`apps/web-e2e/src/fixtures/dash/` (generated with ffmpeg + Shaka Packager —
|
||||
see the README there for why), e2e suites `web-e2e:src/dash-clearkey.e2e.ts`
|
||||
(Chromium; the Angular service worker is blocked because SW-routed requests
|
||||
bypass Playwright interception) and
|
||||
`electron-backend-e2e:src/dash-clearkey.e2e.ts` (real ClearKey EME in
|
||||
Electron).
|
||||
|
||||
## Interfaces
|
||||
|
||||
### Channel Interface
|
||||
@@ -689,6 +752,8 @@ interface Channel {
|
||||
'user-agent': string;
|
||||
origin: string;
|
||||
};
|
||||
/** ClearKey DRM extracted from #KODIPROP lines (DASH channels). */
|
||||
drm?: ChannelDrm;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Reference in new issue
Block a user