11 KiB
DASH Control implementation
The factory remains artplayerPluginDashControl(option = {})(art). Its result has
name and synchronous update(): void. Installation does not require art.dash
yet; ready, restart, or explicit update() reads and validates that instance.
The caller creates, attaches, replaces, and destroys the SDK. This plugin never
destroys it, changes its source, or adds a runtime dependency on dash.js.
Module map
| File | Responsibility |
|---|---|
src/index.ts |
Deferred installation, media identity, update revisions, event subscription and cleanup |
src/sdk.ts |
4.x qualityIndex vs 5.x representation ID access and manual/Auto selection |
src/sdk-events.ts |
Owned SDK subscriptions, coalesced refresh, teardown and asynchronous errors |
src/types.ts |
Narrow internal SDK, host, model and cleanup types |
src/mapping.ts |
Names, current item matching, duplicate labels and selector ordering |
src/menu.ts |
Existing control/setting registries, menu ownership and guarded selection callbacks |
src/audio.svg, src/quality.svg |
Existing setting icons |
types/artplayer-plugin-dash-control.d.ts |
Public options, generic SDK inputs and callable result |
Dependencies flow from the entry into mapping/menu, and from mapping into the SDK adapter. Mapping has no DOM dependency. Menu receives a model and validity callback; it does not choose SDK versions. The event observer receives active/refresh/reset callbacks and owns no DOM or ArtPlayer object. All six owned modules are checked with strict TypeScript, noUncheckedIndexedAccess, and skipLibCheck=false; there are no remaining owned JavaScript modules in this package.
Selection and lifetime
An update validates the captured media element and starts a new revision. A callback from an older update, replaced SDK, or destroyed player returns its previous label without mutating the SDK or UI. This includes references retained by consumers. Every caller formatter and SDK operation is followed by a validity check before subsequent effects. A nested update wins over its older caller.
Manual quality first disables video ABR, then uses the stored SDK selection key. Auto only enables video ABR. Audio passes the original track object to the SDK. Successful selection retains the existing notice, controls.check, setting.check order and synchronous label return. SDK/getName exceptions remain synchronous with their original identity. Other ABR settings are not overwritten.
Duplicate labels still occupy one row. When a duplicate is current, that row keeps
the selected item's key/object so its highlight and subsequent click agree. Numeric
zero is a valid representation ID; a representation named auto is still manual
because the synthetic Auto row is distinguished by its value. Audio prefers object
identity, then a unique match on the current track's available id/index/lang fields.
Ambiguous matches remain unselected instead of selecting an arbitrary track.
Only menus actually installed by this instance are removed on empty topology, disabled surfaces, failed rendering, or destruction. Where registry lookup exists, the saved callback identity protects an entry replaced by the caller. Cleanup takes a snapshot so a synchronous restart cannot cause old cleanup to remove new menus. Cleanup attempts all owned surfaces/subscriptions even if one removal fails. Installation failure rolls back subscriptions, including one installed by a throwing host. The primary error is preserved; secondary cleanup errors are reported.
Keep dash-quality/dash-audio, selector shape, right control placement/padding,
setting width/icons, defaults and unbound getName calls compatible. Do not use a
filtered representation array index or absoluteIndex as the SDK 5 selection key.
SDK-driven refresh
After media identity validation, bind seven listeners only when both SDK on and
off exist. Quality requested/rendered, track rendered and stream updated/initialized
events coalesce into one Promise microtask. This keeps notice/check ordering within
a synchronous menu selection intact. Events emitted by a formatter during refresh
do not schedule recursive refreshes. Unchanged playback-time events only read the
Auto boolean; they do not call formatters or redraw menus. Pure configuration writes
with no subsequent SDK event still need explicit update(), especially while paused.
No polling timer or SDK method interception is installed.
Stream teardown invalidates queued work and clears menus without reading detached
media. Stream initialized/updated can restore menus on the same caller-owned SDK.
Replacing art.dash requires ready/restart or explicit update to bind the new SDK.
Release invalidates the record before calling the captured off method and attempts
every owned removal. Reentrant replacement wins; caller listeners remain installed.
An asynchronous SDK getter/formatter failure stops observation, clears owned menus,
and warns with the original error. Restore the offending formatter/SDK state and
call explicit update() to recover. Explicit update and synchronous menu errors keep
their original throwing behavior. Never convert the public update API to a Promise
or destroy an SDK to handle a plugin rendering failure.
Types and compatibility
src/types.ts describes the narrow SDK and registry surfaces, menu models, event
names, labels, and cleanup callbacks. SDK keys may be absent in malformed external
data; the internal types retain that possibility instead of asserting every value
exists. SDK methods are optional by generation. Non-null assertions in sdk.ts
preserve the selected method family's historical synchronous failure when a caller
provides an incomplete SDK. They do not validate the whole SDK at runtime.
The entry casts only the externally augmented ArtPlayer boundary to the narrow host.
The non-empty track check protects the fallback item. Quality sorting casts apply
before the synthetic Auto row is appended, and the manual selection key cast follows
the Auto branch check. These assertions do not generate runtime conversions or mask
the controlled error/identity tests. Changes to SDK capability detection belong in
sdk.ts, not in a global any or ambient module escape.
Public Config, Option, QualityLevel, AudioTrack, and Result are named types.
AudioTrack id/index/lang include null as declared by both actual SDK generations;
internal AudioFields aliases that public shape. Nullable default labels preserve
runtime behavior, while caller formatters must still return strings.
Default callbacks infer known SDK fields; explicit generic parameters or callback
annotations accept a caller's more detailed SDK interfaces. Original object-based
formatters remain valid. The optional overload supports omitted/undefined options;
the last required overload preserves historical Parameters<typeof factory>[0].
Formatters still receive exactly one argument and return a string; update returns
void synchronously. No global augmentation claims every ArtPlayer has a DASH SDK.
The historical .d.ts path stays available. .d.cts exports a callable CommonJS
value with a type namespace; .d.mts bridges ESM default/named types. Runtime root
and legacy paths are unchanged. typesVersions supports old Node10 type resolution
for the legacy subpath. The online editor declaration is generated by yarn build:ts
and checked standalone against both TS 4.3.5 and 5.9.3, then consumed by real Monaco.
Validation and next work
Run at the workspace root with pinned Node and Yarn:
yarn test:dash-control
yarn build artplayer-plugin-dash-control
yarn test:browser test/browser/dash-control.spec.js --trace on
yarn test:browser test/browser/dash-editor-types.spec.js --trace on
yarn build:ts
yarn test:dash-types-package
yarn ci:check
ARTPLAYER_TEST_DASH adds main/legacy/module files to both SDK generations of Node
contracts and lifecycle tests; use the operating system's path delimiter.
ARTPLAYER_DASH_ARTIFACT selects the browser plugin artifact. Archive browser report
and result/trace directory before running another suite because the output is shared.
Tests use frozen npm 1.1.0, a frozen pre-refactor 5.x implementation, and candidates.
test/types/dash-source.ts checks source/public factory compatibility;
test/types/dash-control.ts covers module modes and rejects invalid calls. The
legacy fixture is checked against the actual published declaration and candidate.
test:dash-types-package packs the current core and DASH with Yarn, installs the
tarballs offline outside the workspace, repeats a frozen install and checks all
public type modes without resolving any workspace source. It also verifies that
implementation files/config do not leak into the archive. This is type acceptance;
the full installed runtime and SDK release matrix still belongs to PKG-DASH-06/05.
dash-control.spec.js tests exercise real old/new core DOM, menu clicks, native MP4 and cleanup,
with controlled SDK methods. They do not load dash.js or test MPD/ABR decoding.
PKG-DASH-05 must verify pinned dash.js 4.5.2 and 5.2.1 with real adaptive media and
review SDK-driven refresh/source events and the existing demo lifecycle. Physical
devices and installed package acceptance remain separate release gates.
dash-sdk.spec.js now separately loads hash-pinned npm dash.js 4.5.2/5.2.1 and local
multi-quality/multi-audio DASH segments. It covers decoding, explicit update after
external selection, source topology replacement, retained callbacks and SDK ownership.
It also includes a native SDK control without an ArtPlayer instance. SDK 4.5.2
paused-seek stalls reproduce independently: its empty buffer-clear path preserves
stale buffer metrics and can prevent further scheduling. A diagnostic backport of
the SDK 5 buffer-level refresh confirms the cause; no production workaround ships.
See the diagnosis.
The compatibility risk remains open. Unsupported MSE is
recorded as a playback capability gap, not acceptance. SDK event tests also cover
external selections without explicit update, same-SDK source replacement, asynchronous
formatter error/recovery, and actual setting clicks during SDK refresh.
refactor/scripts/dash-sdk-types.test.mjs compares actual SDK-only and plugin
consumers across ten compiler/module configurations, retaining upstream-only
Node10/old DOM diagnostics. The exact peer dependency closure is hash-pinned in
refactor/baselines/dash-type-dependencies.json; no type shim or paths mapping is used.
See refactor validation for baseline failures
and task plan for remaining type and release work.