@videojs/spf 10.0.0-beta.3 → 10.0.0-beta.30
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/README.md +19 -38
- package/dist/default/core/actors/create-machine-actor.js +91 -0
- package/dist/default/core/actors/create-machine-actor.js.map +1 -0
- package/dist/default/core/actors/create-transition-actor.js +46 -0
- package/dist/default/core/actors/create-transition-actor.js.map +1 -0
- package/dist/default/core/composition/create-composition.js +85 -0
- package/dist/default/core/composition/create-composition.js.map +1 -0
- package/dist/default/core/composition/share-signals.js +39 -0
- package/dist/default/core/composition/share-signals.js.map +1 -0
- package/dist/default/core/machine.js +26 -0
- package/dist/default/core/machine.js.map +1 -0
- package/dist/default/core/reactors/create-machine-reactor.js +83 -0
- package/dist/default/core/reactors/create-machine-reactor.js.map +1 -0
- package/dist/default/core/signals/effect.js +41 -0
- package/dist/default/core/signals/effect.js.map +1 -0
- package/dist/default/core/signals/primitives.js +54 -0
- package/dist/default/core/signals/primitives.js.map +1 -0
- package/dist/default/core/signals/when.js +38 -0
- package/dist/default/core/signals/when.js.map +1 -0
- package/dist/default/core/tasks/delayed-reschedule.js +31 -0
- package/dist/default/core/tasks/delayed-reschedule.js.map +1 -0
- package/dist/default/core/tasks/task.js +321 -0
- package/dist/default/core/tasks/task.js.map +1 -0
- package/dist/default/dom.js +9 -0
- package/dist/default/hls-audio.js +3 -0
- package/dist/default/hls-background-video.js +3 -0
- package/dist/default/hls-video.js +4 -0
- package/dist/default/hls.js +8 -0
- package/dist/default/index.js +23 -0
- package/dist/default/index.js.map +1 -0
- package/dist/default/media/abr/quality-selection.js +21 -0
- package/dist/default/media/abr/quality-selection.js.map +1 -0
- package/dist/default/media/buffer/back-buffer.js +46 -0
- package/dist/default/media/buffer/back-buffer.js.map +1 -0
- package/dist/default/media/buffer/forward-buffer.js +119 -0
- package/dist/default/media/buffer/forward-buffer.js.map +1 -0
- package/dist/default/media/dom/capabilities.js +72 -0
- package/dist/default/media/dom/capabilities.js.map +1 -0
- package/dist/default/media/dom/mse/append-segment.js +60 -0
- package/dist/default/media/dom/mse/append-segment.js.map +1 -0
- package/dist/default/media/dom/mse/buffer-flusher.js +55 -0
- package/dist/default/media/dom/mse/buffer-flusher.js.map +1 -0
- package/dist/default/media/dom/mse/duration.js +95 -0
- package/dist/default/media/dom/mse/duration.js.map +1 -0
- package/dist/default/media/dom/mse/end-of-stream.js +20 -0
- package/dist/default/media/dom/mse/end-of-stream.js.map +1 -0
- package/dist/default/media/dom/mse/mediasource-setup.js +242 -0
- package/dist/default/media/dom/mse/mediasource-setup.js.map +1 -0
- package/dist/default/media/dom/screen.js +112 -0
- package/dist/default/media/dom/screen.js.map +1 -0
- package/dist/default/media/dom/text/resolve-vtt-segment.js +50 -0
- package/dist/default/media/dom/text/resolve-vtt-segment.js.map +1 -0
- package/dist/default/media/dom/text/text-track-slots.js +69 -0
- package/dist/default/media/dom/text/text-track-slots.js.map +1 -0
- package/dist/default/media/errors.js +69 -0
- package/dist/default/media/errors.js.map +1 -0
- package/dist/default/media/hls/parse-attributes.js +148 -0
- package/dist/default/media/hls/parse-attributes.js.map +1 -0
- package/dist/default/media/hls/parse-media-playlist.js +261 -0
- package/dist/default/media/hls/parse-media-playlist.js.map +1 -0
- package/dist/default/media/hls/parse-multivariant.js +234 -0
- package/dist/default/media/hls/parse-multivariant.js.map +1 -0
- package/dist/default/media/hls/reload-policy.js +71 -0
- package/dist/default/media/hls/reload-policy.js.map +1 -0
- package/dist/default/media/hls/resolve-url.js +11 -0
- package/dist/default/media/hls/resolve-url.js.map +1 -0
- package/dist/default/media/live-window.js +36 -0
- package/dist/default/media/live-window.js.map +1 -0
- package/dist/default/media/media-tracks/media-tracks.js +101 -0
- package/dist/default/media/media-tracks/media-tracks.js.map +1 -0
- package/dist/default/media/mp4/box.js +58 -0
- package/dist/default/media/mp4/box.js.map +1 -0
- package/dist/default/media/mp4/timestamp-origin.js +107 -0
- package/dist/default/media/mp4/timestamp-origin.js.map +1 -0
- package/dist/default/media/primitives/resolution.js +29 -0
- package/dist/default/media/primitives/resolution.js.map +1 -0
- package/dist/default/media/primitives/select-tracks.js +107 -0
- package/dist/default/media/primitives/select-tracks.js.map +1 -0
- package/dist/default/media/text/parse-vtt-timestamp-map.js +42 -0
- package/dist/default/media/text/parse-vtt-timestamp-map.js.map +1 -0
- package/dist/default/media/text/resolve-vtt-metadata.js +23 -0
- package/dist/default/media/text/resolve-vtt-metadata.js.map +1 -0
- package/dist/default/media/types/index.js +50 -0
- package/dist/default/media/types/index.js.map +1 -0
- package/dist/default/media/utils/cdn.js +56 -0
- package/dist/default/media/utils/cdn.js.map +1 -0
- package/dist/default/media/utils/preload.js +22 -0
- package/dist/default/media/utils/preload.js.map +1 -0
- package/dist/default/media/utils/track-selection.js +47 -0
- package/dist/default/media/utils/track-selection.js.map +1 -0
- package/dist/default/media/utils/tracks.js +144 -0
- package/dist/default/media/utils/tracks.js.map +1 -0
- package/dist/default/media-tracks.js +2 -0
- package/dist/default/mux-audio.js +3 -0
- package/dist/default/mux-background-video.js +3 -0
- package/dist/default/mux-video.js +3 -0
- package/dist/default/network/bandwidth-estimator.js +96 -0
- package/dist/default/network/bandwidth-estimator.js.map +1 -0
- package/dist/default/network/chunked-stream-iterable.js +49 -0
- package/dist/default/network/chunked-stream-iterable.js.map +1 -0
- package/dist/default/network/ewma.js +71 -0
- package/dist/default/network/ewma.js.map +1 -0
- package/dist/default/network/fetch.js +115 -0
- package/dist/default/network/fetch.js.map +1 -0
- package/dist/default/playback/actors/dom/segment-loader.js +249 -0
- package/dist/default/playback/actors/dom/segment-loader.js.map +1 -0
- package/dist/default/playback/actors/dom/source-buffer.js +139 -0
- package/dist/default/playback/actors/dom/source-buffer.js.map +1 -0
- package/dist/default/playback/actors/dom/text-tracks.js +46 -0
- package/dist/default/playback/actors/dom/text-tracks.js.map +1 -0
- package/dist/default/playback/actors/text-track-segment-loader.js +149 -0
- package/dist/default/playback/actors/text-track-segment-loader.js.map +1 -0
- package/dist/default/playback/adapters/hls-audio/adapter.js +186 -0
- package/dist/default/playback/adapters/hls-audio/adapter.js.map +1 -0
- package/dist/default/playback/adapters/hls-audio/media.js +9 -0
- package/dist/default/playback/adapters/hls-audio/media.js.map +1 -0
- package/dist/default/playback/adapters/hls-background-video/adapter.js +211 -0
- package/dist/default/playback/adapters/hls-background-video/adapter.js.map +1 -0
- package/dist/default/playback/adapters/hls-background-video/host.js +60 -0
- package/dist/default/playback/adapters/hls-background-video/host.js.map +1 -0
- package/dist/default/playback/adapters/hls-background-video/media.js +21 -0
- package/dist/default/playback/adapters/hls-background-video/media.js.map +1 -0
- package/dist/default/playback/adapters/hls-video/adapter.js +316 -0
- package/dist/default/playback/adapters/hls-video/adapter.js.map +1 -0
- package/dist/default/playback/adapters/hls-video/error-surface.js +51 -0
- package/dist/default/playback/adapters/hls-video/error-surface.js.map +1 -0
- package/dist/default/playback/adapters/hls-video/media-tracks.js +126 -0
- package/dist/default/playback/adapters/hls-video/media-tracks.js.map +1 -0
- package/dist/default/playback/adapters/hls-video/media.js +11 -0
- package/dist/default/playback/adapters/hls-video/media.js.map +1 -0
- package/dist/default/playback/adapters/mux-audio/media.js +26 -0
- package/dist/default/playback/adapters/mux-audio/media.js.map +1 -0
- package/dist/default/playback/adapters/mux-video/adapter.js +105 -0
- package/dist/default/playback/adapters/mux-video/adapter.js.map +1 -0
- package/dist/default/playback/adapters/mux-video/media.js +23 -0
- package/dist/default/playback/adapters/mux-video/media.js.map +1 -0
- package/dist/default/playback/behaviors/calculate-presentation-duration.js +36 -0
- package/dist/default/playback/behaviors/calculate-presentation-duration.js.map +1 -0
- package/dist/default/playback/behaviors/collect-errors.js +111 -0
- package/dist/default/playback/behaviors/collect-errors.js.map +1 -0
- package/dist/default/playback/behaviors/derive-cdn-priority.js +68 -0
- package/dist/default/playback/behaviors/derive-cdn-priority.js.map +1 -0
- package/dist/default/playback/behaviors/dom/airplay.js +211 -0
- package/dist/default/playback/behaviors/dom/airplay.js.map +1 -0
- package/dist/default/playback/behaviors/dom/apply-start-position.js +93 -0
- package/dist/default/playback/behaviors/dom/apply-start-position.js.map +1 -0
- package/dist/default/playback/behaviors/dom/end-of-stream.js +102 -0
- package/dist/default/playback/behaviors/dom/end-of-stream.js.map +1 -0
- package/dist/default/playback/behaviors/dom/load-segments.js +181 -0
- package/dist/default/playback/behaviors/dom/load-segments.js.map +1 -0
- package/dist/default/playback/behaviors/dom/recover-end-stall.js +77 -0
- package/dist/default/playback/behaviors/dom/recover-end-stall.js.map +1 -0
- package/dist/default/playback/behaviors/dom/seek-to-live-edge.js +132 -0
- package/dist/default/playback/behaviors/dom/seek-to-live-edge.js.map +1 -0
- package/dist/default/playback/behaviors/dom/setup-buffer-actors.js +205 -0
- package/dist/default/playback/behaviors/dom/setup-buffer-actors.js.map +1 -0
- package/dist/default/playback/behaviors/dom/setup-mediasource.js +114 -0
- package/dist/default/playback/behaviors/dom/setup-mediasource.js.map +1 -0
- package/dist/default/playback/behaviors/dom/setup-text-track-actors.js +40 -0
- package/dist/default/playback/behaviors/dom/setup-text-track-actors.js.map +1 -0
- package/dist/default/playback/behaviors/dom/sync-live-seekable-range.js +26 -0
- package/dist/default/playback/behaviors/dom/sync-live-seekable-range.js.map +1 -0
- package/dist/default/playback/behaviors/dom/sync-text-tracks.js +124 -0
- package/dist/default/playback/behaviors/dom/sync-text-tracks.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-current-time.js +52 -0
- package/dist/default/playback/behaviors/dom/track-current-time.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-load-triggers.js +94 -0
- package/dist/default/playback/behaviors/dom/track-load-triggers.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-playback-rate.js +37 -0
- package/dist/default/playback/behaviors/dom/track-playback-rate.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-player-resolution.js +57 -0
- package/dist/default/playback/behaviors/dom/track-player-resolution.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-screen-resolution.js +29 -0
- package/dist/default/playback/behaviors/dom/track-screen-resolution.js.map +1 -0
- package/dist/default/playback/behaviors/dom/update-mediasource-duration.js +113 -0
- package/dist/default/playback/behaviors/dom/update-mediasource-duration.js.map +1 -0
- package/dist/default/playback/behaviors/establish-start-media-time.js +197 -0
- package/dist/default/playback/behaviors/establish-start-media-time.js.map +1 -0
- package/dist/default/playback/behaviors/resolve-presentation.js +85 -0
- package/dist/default/playback/behaviors/resolve-presentation.js.map +1 -0
- package/dist/default/playback/behaviors/resolve-track.js +141 -0
- package/dist/default/playback/behaviors/resolve-track.js.map +1 -0
- package/dist/default/playback/behaviors/select-tracks.js +216 -0
- package/dist/default/playback/behaviors/select-tracks.js.map +1 -0
- package/dist/default/playback/behaviors/setup-failover-monitor.js +66 -0
- package/dist/default/playback/behaviors/setup-failover-monitor.js.map +1 -0
- package/dist/default/playback/behaviors/sync-preload.js +59 -0
- package/dist/default/playback/behaviors/sync-preload.js.map +1 -0
- package/dist/default/playback/behaviors/track-switching.js +391 -0
- package/dist/default/playback/behaviors/track-switching.js.map +1 -0
- package/dist/default/playback/engines/hls/engine-audio-only.js +98 -0
- package/dist/default/playback/engines/hls/engine-audio-only.js.map +1 -0
- package/dist/default/playback/engines/hls/engine-background-video.js +92 -0
- package/dist/default/playback/engines/hls/engine-background-video.js.map +1 -0
- package/dist/default/playback/engines/hls/engine.js +147 -0
- package/dist/default/playback/engines/hls/engine.js.map +1 -0
- package/dist/default/playback/primitives/error-messages.js +51 -0
- package/dist/default/playback/primitives/error-messages.js.map +1 -0
- package/dist/default/playback/primitives/failover-fetch.js +42 -0
- package/dist/default/playback/primitives/failover-fetch.js.map +1 -0
- package/dist/default/playback/primitives/head-peek.js +44 -0
- package/dist/default/playback/primitives/head-peek.js.map +1 -0
- package/dist/default/playback/primitives/live-window.js +66 -0
- package/dist/default/playback/primitives/live-window.js.map +1 -0
- package/dist/default/playback/primitives/relocation-pipelines.js +203 -0
- package/dist/default/playback/primitives/relocation-pipelines.js.map +1 -0
- package/dist/default/playback/primitives/report-track-conditions.js +86 -0
- package/dist/default/playback/primitives/report-track-conditions.js.map +1 -0
- package/dist/default/playback/primitives/segment-load-pipeline.js +96 -0
- package/dist/default/playback/primitives/segment-load-pipeline.js.map +1 -0
- package/dist/default/playback/primitives/selection-rules.js +86 -0
- package/dist/default/playback/primitives/selection-rules.js.map +1 -0
- package/dist/default/playback/primitives/text-segment-load-pipeline.js +37 -0
- package/dist/default/playback/primitives/text-segment-load-pipeline.js.map +1 -0
- package/dist/default/playback/primitives/track-types.js +61 -0
- package/dist/default/playback/primitives/track-types.js.map +1 -0
- package/dist/dev/core/actors/actor.d.ts +26 -0
- package/dist/dev/core/actors/actor.d.ts.map +1 -0
- package/dist/dev/core/actors/create-machine-actor.d.ts +128 -0
- package/dist/dev/core/actors/create-machine-actor.d.ts.map +1 -0
- package/dist/dev/core/actors/create-machine-actor.js +91 -0
- package/dist/dev/core/actors/create-machine-actor.js.map +1 -0
- package/dist/dev/core/actors/create-transition-actor.d.ts +41 -0
- package/dist/dev/core/actors/create-transition-actor.d.ts.map +1 -0
- package/dist/dev/core/actors/create-transition-actor.js +46 -0
- package/dist/dev/core/actors/create-transition-actor.js.map +1 -0
- package/dist/dev/core/composition/create-composition.d.ts +273 -0
- package/dist/dev/core/composition/create-composition.d.ts.map +1 -0
- package/dist/dev/core/composition/create-composition.js +85 -0
- package/dist/dev/core/composition/create-composition.js.map +1 -0
- package/dist/dev/core/composition/share-signals.d.ts +46 -0
- package/dist/dev/core/composition/share-signals.d.ts.map +1 -0
- package/dist/dev/core/composition/share-signals.js +39 -0
- package/dist/dev/core/composition/share-signals.js.map +1 -0
- package/dist/dev/core/machine.d.ts +21 -0
- package/dist/dev/core/machine.d.ts.map +1 -0
- package/dist/dev/core/machine.js +26 -0
- package/dist/dev/core/machine.js.map +1 -0
- package/dist/dev/core/reactors/create-machine-reactor.d.ts +93 -0
- package/dist/dev/core/reactors/create-machine-reactor.d.ts.map +1 -0
- package/dist/dev/core/reactors/create-machine-reactor.js +83 -0
- package/dist/dev/core/reactors/create-machine-reactor.js.map +1 -0
- package/dist/dev/core/signals/effect.d.ts +15 -0
- package/dist/dev/core/signals/effect.d.ts.map +1 -0
- package/dist/dev/core/signals/effect.js +41 -0
- package/dist/dev/core/signals/effect.js.map +1 -0
- package/dist/dev/core/signals/primitives.d.ts +46 -0
- package/dist/dev/core/signals/primitives.d.ts.map +1 -0
- package/dist/dev/core/signals/primitives.js +54 -0
- package/dist/dev/core/signals/primitives.js.map +1 -0
- package/dist/dev/core/signals/when.js +38 -0
- package/dist/dev/core/signals/when.js.map +1 -0
- package/dist/dev/core/tasks/delayed-reschedule.js +31 -0
- package/dist/dev/core/tasks/delayed-reschedule.js.map +1 -0
- package/dist/dev/core/tasks/task.d.ts +166 -0
- package/dist/dev/core/tasks/task.d.ts.map +1 -0
- package/dist/dev/core/tasks/task.js +321 -0
- package/dist/dev/core/tasks/task.js.map +1 -0
- package/dist/dev/dom.d.ts +9 -0
- package/dist/dev/dom.js +9 -0
- package/dist/dev/hls-audio.d.ts +3 -0
- package/dist/dev/hls-audio.js +3 -0
- package/dist/dev/hls-background-video.d.ts +4 -0
- package/dist/dev/hls-background-video.js +3 -0
- package/dist/dev/hls-video.d.ts +5 -0
- package/dist/dev/hls-video.js +4 -0
- package/dist/dev/hls.d.ts +9 -0
- package/dist/dev/hls.js +8 -0
- package/dist/dev/index.d.ts +24 -0
- package/dist/dev/index.d.ts.map +1 -0
- package/dist/dev/index.js +23 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/dev/media/abr/quality-selection.d.ts +22 -0
- package/dist/dev/media/abr/quality-selection.d.ts.map +1 -0
- package/dist/dev/media/abr/quality-selection.js +21 -0
- package/dist/dev/media/abr/quality-selection.js.map +1 -0
- package/dist/dev/media/buffer/back-buffer.d.ts +14 -0
- package/dist/dev/media/buffer/back-buffer.d.ts.map +1 -0
- package/dist/dev/media/buffer/back-buffer.js +46 -0
- package/dist/dev/media/buffer/back-buffer.js.map +1 -0
- package/dist/dev/media/buffer/forward-buffer.d.ts +14 -0
- package/dist/dev/media/buffer/forward-buffer.d.ts.map +1 -0
- package/dist/dev/media/buffer/forward-buffer.js +119 -0
- package/dist/dev/media/buffer/forward-buffer.js.map +1 -0
- package/dist/dev/media/dom/capabilities.js +72 -0
- package/dist/dev/media/dom/capabilities.js.map +1 -0
- package/dist/dev/media/dom/mse/append-segment.d.ts +18 -0
- package/dist/dev/media/dom/mse/append-segment.d.ts.map +1 -0
- package/dist/dev/media/dom/mse/append-segment.js +60 -0
- package/dist/dev/media/dom/mse/append-segment.js.map +1 -0
- package/dist/dev/media/dom/mse/buffer-flusher.d.ts +24 -0
- package/dist/dev/media/dom/mse/buffer-flusher.d.ts.map +1 -0
- package/dist/dev/media/dom/mse/buffer-flusher.js +55 -0
- package/dist/dev/media/dom/mse/buffer-flusher.js.map +1 -0
- package/dist/dev/media/dom/mse/duration.js +95 -0
- package/dist/dev/media/dom/mse/duration.js.map +1 -0
- package/dist/dev/media/dom/mse/end-of-stream.js +20 -0
- package/dist/dev/media/dom/mse/end-of-stream.js.map +1 -0
- package/dist/dev/media/dom/mse/mediasource-setup.js +242 -0
- package/dist/dev/media/dom/mse/mediasource-setup.js.map +1 -0
- package/dist/dev/media/dom/screen.d.ts +7 -0
- package/dist/dev/media/dom/screen.d.ts.map +1 -0
- package/dist/dev/media/dom/screen.js +112 -0
- package/dist/dev/media/dom/screen.js.map +1 -0
- package/dist/dev/media/dom/text/resolve-vtt-segment.d.ts +6 -0
- package/dist/dev/media/dom/text/resolve-vtt-segment.d.ts.map +1 -0
- package/dist/dev/media/dom/text/resolve-vtt-segment.js +50 -0
- package/dist/dev/media/dom/text/resolve-vtt-segment.js.map +1 -0
- package/dist/dev/media/dom/text/text-track-slots.d.ts +30 -0
- package/dist/dev/media/dom/text/text-track-slots.d.ts.map +1 -0
- package/dist/dev/media/dom/text/text-track-slots.js +69 -0
- package/dist/dev/media/dom/text/text-track-slots.js.map +1 -0
- package/dist/dev/media/errors.d.ts +82 -0
- package/dist/dev/media/errors.d.ts.map +1 -0
- package/dist/dev/media/errors.js +69 -0
- package/dist/dev/media/errors.js.map +1 -0
- package/dist/dev/media/hls/parse-attributes.js +148 -0
- package/dist/dev/media/hls/parse-attributes.js.map +1 -0
- package/dist/dev/media/hls/parse-media-playlist.js +261 -0
- package/dist/dev/media/hls/parse-media-playlist.js.map +1 -0
- package/dist/dev/media/hls/parse-multivariant.js +234 -0
- package/dist/dev/media/hls/parse-multivariant.js.map +1 -0
- package/dist/dev/media/hls/reload-policy.js +71 -0
- package/dist/dev/media/hls/reload-policy.js.map +1 -0
- package/dist/dev/media/hls/resolve-url.js +11 -0
- package/dist/dev/media/hls/resolve-url.js.map +1 -0
- package/dist/dev/media/live-window.js +36 -0
- package/dist/dev/media/live-window.js.map +1 -0
- package/dist/dev/media/media-tracks/media-tracks.d.ts +51 -0
- package/dist/dev/media/media-tracks/media-tracks.d.ts.map +1 -0
- package/dist/dev/media/media-tracks/media-tracks.js +101 -0
- package/dist/dev/media/media-tracks/media-tracks.js.map +1 -0
- package/dist/dev/media/mp4/box.js +58 -0
- package/dist/dev/media/mp4/box.js.map +1 -0
- package/dist/dev/media/mp4/timestamp-origin.js +107 -0
- package/dist/dev/media/mp4/timestamp-origin.js.map +1 -0
- package/dist/dev/media/primitives/resolution.d.ts +24 -0
- package/dist/dev/media/primitives/resolution.d.ts.map +1 -0
- package/dist/dev/media/primitives/resolution.js +29 -0
- package/dist/dev/media/primitives/resolution.js.map +1 -0
- package/dist/dev/media/primitives/select-tracks.js +107 -0
- package/dist/dev/media/primitives/select-tracks.js.map +1 -0
- package/dist/dev/media/text/parse-vtt-timestamp-map.js +42 -0
- package/dist/dev/media/text/parse-vtt-timestamp-map.js.map +1 -0
- package/dist/dev/media/text/resolve-vtt-metadata.js +23 -0
- package/dist/dev/media/text/resolve-vtt-metadata.js.map +1 -0
- package/dist/dev/media/types/index.d.ts +377 -0
- package/dist/dev/media/types/index.d.ts.map +1 -0
- package/dist/dev/media/types/index.js +50 -0
- package/dist/dev/media/types/index.js.map +1 -0
- package/dist/dev/media/utils/cdn.d.ts +13 -0
- package/dist/dev/media/utils/cdn.d.ts.map +1 -0
- package/dist/dev/media/utils/cdn.js +56 -0
- package/dist/dev/media/utils/cdn.js.map +1 -0
- package/dist/dev/media/utils/preload.js +22 -0
- package/dist/dev/media/utils/preload.js.map +1 -0
- package/dist/dev/media/utils/track-selection.js +47 -0
- package/dist/dev/media/utils/track-selection.js.map +1 -0
- package/dist/dev/media/utils/tracks.js +144 -0
- package/dist/dev/media/utils/tracks.js.map +1 -0
- package/dist/dev/media-tracks.d.ts +3 -0
- package/dist/dev/media-tracks.js +2 -0
- package/dist/dev/mux-audio.d.ts +4 -0
- package/dist/dev/mux-audio.js +3 -0
- package/dist/dev/mux-background-video.d.ts +4 -0
- package/dist/dev/mux-background-video.js +3 -0
- package/dist/dev/mux-video.d.ts +4 -0
- package/dist/dev/mux-video.js +3 -0
- package/dist/dev/network/bandwidth-estimator.d.ts +50 -0
- package/dist/dev/network/bandwidth-estimator.d.ts.map +1 -0
- package/dist/dev/network/bandwidth-estimator.js +96 -0
- package/dist/dev/network/bandwidth-estimator.js.map +1 -0
- package/dist/dev/network/chunked-stream-iterable.js +49 -0
- package/dist/dev/network/chunked-stream-iterable.js.map +1 -0
- package/dist/dev/network/ewma.js +71 -0
- package/dist/dev/network/ewma.js.map +1 -0
- package/dist/dev/network/fetch.js +115 -0
- package/dist/dev/network/fetch.js.map +1 -0
- package/dist/dev/playback/actors/dom/segment-loader.d.ts +48 -0
- package/dist/dev/playback/actors/dom/segment-loader.d.ts.map +1 -0
- package/dist/dev/playback/actors/dom/segment-loader.js +249 -0
- package/dist/dev/playback/actors/dom/segment-loader.js.map +1 -0
- package/dist/dev/playback/actors/dom/source-buffer.d.ts +47 -0
- package/dist/dev/playback/actors/dom/source-buffer.d.ts.map +1 -0
- package/dist/dev/playback/actors/dom/source-buffer.js +139 -0
- package/dist/dev/playback/actors/dom/source-buffer.js.map +1 -0
- package/dist/dev/playback/actors/dom/text-tracks.d.ts +3 -0
- package/dist/dev/playback/actors/dom/text-tracks.js +46 -0
- package/dist/dev/playback/actors/dom/text-tracks.js.map +1 -0
- package/dist/dev/playback/actors/text-track-segment-loader.d.ts +54 -0
- package/dist/dev/playback/actors/text-track-segment-loader.d.ts.map +1 -0
- package/dist/dev/playback/actors/text-track-segment-loader.js +149 -0
- package/dist/dev/playback/actors/text-track-segment-loader.js.map +1 -0
- package/dist/dev/playback/actors/text-tracks.d.ts +33 -0
- package/dist/dev/playback/actors/text-tracks.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-audio/adapter.d.ts +54 -0
- package/dist/dev/playback/adapters/hls-audio/adapter.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-audio/adapter.js +186 -0
- package/dist/dev/playback/adapters/hls-audio/adapter.js.map +1 -0
- package/dist/dev/playback/adapters/hls-audio/media.d.ts +10 -0
- package/dist/dev/playback/adapters/hls-audio/media.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-audio/media.js +9 -0
- package/dist/dev/playback/adapters/hls-audio/media.js.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/adapter.d.ts +77 -0
- package/dist/dev/playback/adapters/hls-background-video/adapter.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/adapter.js +211 -0
- package/dist/dev/playback/adapters/hls-background-video/adapter.js.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/host.d.ts +38 -0
- package/dist/dev/playback/adapters/hls-background-video/host.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/host.js +60 -0
- package/dist/dev/playback/adapters/hls-background-video/host.js.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/media.d.ts +20 -0
- package/dist/dev/playback/adapters/hls-background-video/media.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/media.js +21 -0
- package/dist/dev/playback/adapters/hls-background-video/media.js.map +1 -0
- package/dist/dev/playback/adapters/hls-video/adapter.d.ts +63 -0
- package/dist/dev/playback/adapters/hls-video/adapter.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-video/adapter.js +316 -0
- package/dist/dev/playback/adapters/hls-video/adapter.js.map +1 -0
- package/dist/dev/playback/adapters/hls-video/error-surface.d.ts +18 -0
- package/dist/dev/playback/adapters/hls-video/error-surface.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-video/error-surface.js +51 -0
- package/dist/dev/playback/adapters/hls-video/error-surface.js.map +1 -0
- package/dist/dev/playback/adapters/hls-video/media-tracks.d.ts +22 -0
- package/dist/dev/playback/adapters/hls-video/media-tracks.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-video/media-tracks.js +126 -0
- package/dist/dev/playback/adapters/hls-video/media-tracks.js.map +1 -0
- package/dist/dev/playback/adapters/hls-video/media.d.ts +10 -0
- package/dist/dev/playback/adapters/hls-video/media.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-video/media.js +11 -0
- package/dist/dev/playback/adapters/hls-video/media.js.map +1 -0
- package/dist/dev/playback/adapters/mux-audio/media.d.ts +28 -0
- package/dist/dev/playback/adapters/mux-audio/media.d.ts.map +1 -0
- package/dist/dev/playback/adapters/mux-audio/media.js +26 -0
- package/dist/dev/playback/adapters/mux-audio/media.js.map +1 -0
- package/dist/dev/playback/adapters/mux-video/adapter.d.ts +34 -0
- package/dist/dev/playback/adapters/mux-video/adapter.d.ts.map +1 -0
- package/dist/dev/playback/adapters/mux-video/adapter.js +105 -0
- package/dist/dev/playback/adapters/mux-video/adapter.js.map +1 -0
- package/dist/dev/playback/adapters/mux-video/media.d.ts +24 -0
- package/dist/dev/playback/adapters/mux-video/media.d.ts.map +1 -0
- package/dist/dev/playback/adapters/mux-video/media.js +23 -0
- package/dist/dev/playback/adapters/mux-video/media.js.map +1 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.d.ts +26 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.js +36 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.js.map +1 -0
- package/dist/dev/playback/behaviors/collect-errors.js +111 -0
- package/dist/dev/playback/behaviors/collect-errors.js.map +1 -0
- package/dist/dev/playback/behaviors/derive-cdn-priority.js +68 -0
- package/dist/dev/playback/behaviors/derive-cdn-priority.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/airplay.js +211 -0
- package/dist/dev/playback/behaviors/dom/airplay.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/apply-start-position.js +93 -0
- package/dist/dev/playback/behaviors/dom/apply-start-position.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/end-of-stream.js +102 -0
- package/dist/dev/playback/behaviors/dom/end-of-stream.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/load-segments.d.ts +72 -0
- package/dist/dev/playback/behaviors/dom/load-segments.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/load-segments.js +181 -0
- package/dist/dev/playback/behaviors/dom/load-segments.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/recover-end-stall.js +77 -0
- package/dist/dev/playback/behaviors/dom/recover-end-stall.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/seek-to-live-edge.js +132 -0
- package/dist/dev/playback/behaviors/dom/seek-to-live-edge.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/setup-buffer-actors.js +205 -0
- package/dist/dev/playback/behaviors/dom/setup-buffer-actors.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/setup-mediasource.js +114 -0
- package/dist/dev/playback/behaviors/dom/setup-mediasource.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/setup-text-track-actors.d.ts +28 -0
- package/dist/dev/playback/behaviors/dom/setup-text-track-actors.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/setup-text-track-actors.js +40 -0
- package/dist/dev/playback/behaviors/dom/setup-text-track-actors.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/sync-live-seekable-range.js +26 -0
- package/dist/dev/playback/behaviors/dom/sync-live-seekable-range.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/sync-text-tracks.js +124 -0
- package/dist/dev/playback/behaviors/dom/sync-text-tracks.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-current-time.d.ts +33 -0
- package/dist/dev/playback/behaviors/dom/track-current-time.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-current-time.js +52 -0
- package/dist/dev/playback/behaviors/dom/track-current-time.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-load-triggers.d.ts +47 -0
- package/dist/dev/playback/behaviors/dom/track-load-triggers.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-load-triggers.js +94 -0
- package/dist/dev/playback/behaviors/dom/track-load-triggers.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-playback-rate.d.ts +33 -0
- package/dist/dev/playback/behaviors/dom/track-playback-rate.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-playback-rate.js +37 -0
- package/dist/dev/playback/behaviors/dom/track-playback-rate.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-player-resolution.d.ts +8 -0
- package/dist/dev/playback/behaviors/dom/track-player-resolution.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-player-resolution.js +57 -0
- package/dist/dev/playback/behaviors/dom/track-player-resolution.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-screen-resolution.js +29 -0
- package/dist/dev/playback/behaviors/dom/track-screen-resolution.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/update-mediasource-duration.js +113 -0
- package/dist/dev/playback/behaviors/dom/update-mediasource-duration.js.map +1 -0
- package/dist/dev/playback/behaviors/establish-start-media-time.d.ts +36 -0
- package/dist/dev/playback/behaviors/establish-start-media-time.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/establish-start-media-time.js +197 -0
- package/dist/dev/playback/behaviors/establish-start-media-time.js.map +1 -0
- package/dist/dev/playback/behaviors/resolve-presentation.d.ts +8 -0
- package/dist/dev/playback/behaviors/resolve-presentation.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/resolve-presentation.js +85 -0
- package/dist/dev/playback/behaviors/resolve-presentation.js.map +1 -0
- package/dist/dev/playback/behaviors/resolve-track.js +141 -0
- package/dist/dev/playback/behaviors/resolve-track.js.map +1 -0
- package/dist/dev/playback/behaviors/select-tracks.d.ts +72 -0
- package/dist/dev/playback/behaviors/select-tracks.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/select-tracks.js +216 -0
- package/dist/dev/playback/behaviors/select-tracks.js.map +1 -0
- package/dist/dev/playback/behaviors/setup-failover-monitor.d.ts +14 -0
- package/dist/dev/playback/behaviors/setup-failover-monitor.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/setup-failover-monitor.js +66 -0
- package/dist/dev/playback/behaviors/setup-failover-monitor.js.map +1 -0
- package/dist/dev/playback/behaviors/sync-preload.js +59 -0
- package/dist/dev/playback/behaviors/sync-preload.js.map +1 -0
- package/dist/dev/playback/behaviors/track-switching.js +391 -0
- package/dist/dev/playback/behaviors/track-switching.js.map +1 -0
- package/dist/dev/playback/engines/hls/engine-audio-only.d.ts +173 -0
- package/dist/dev/playback/engines/hls/engine-audio-only.d.ts.map +1 -0
- package/dist/dev/playback/engines/hls/engine-audio-only.js +98 -0
- package/dist/dev/playback/engines/hls/engine-audio-only.js.map +1 -0
- package/dist/dev/playback/engines/hls/engine-background-video.d.ts +158 -0
- package/dist/dev/playback/engines/hls/engine-background-video.d.ts.map +1 -0
- package/dist/dev/playback/engines/hls/engine-background-video.js +92 -0
- package/dist/dev/playback/engines/hls/engine-background-video.js.map +1 -0
- package/dist/dev/playback/engines/hls/engine.d.ts +329 -0
- package/dist/dev/playback/engines/hls/engine.d.ts.map +1 -0
- package/dist/dev/playback/engines/hls/engine.js +147 -0
- package/dist/dev/playback/engines/hls/engine.js.map +1 -0
- package/dist/dev/playback/primitives/derive-start-media-time.d.ts +16 -0
- package/dist/dev/playback/primitives/derive-start-media-time.d.ts.map +1 -0
- package/dist/dev/playback/primitives/error-messages.js +51 -0
- package/dist/dev/playback/primitives/error-messages.js.map +1 -0
- package/dist/dev/playback/primitives/failover-fetch.js +42 -0
- package/dist/dev/playback/primitives/failover-fetch.js.map +1 -0
- package/dist/dev/playback/primitives/head-peek.js +44 -0
- package/dist/dev/playback/primitives/head-peek.js.map +1 -0
- package/dist/dev/playback/primitives/live-window.js +66 -0
- package/dist/dev/playback/primitives/live-window.js.map +1 -0
- package/dist/dev/playback/primitives/relocation-pipelines.js +203 -0
- package/dist/dev/playback/primitives/relocation-pipelines.js.map +1 -0
- package/dist/dev/playback/primitives/report-track-conditions.d.ts +11 -0
- package/dist/dev/playback/primitives/report-track-conditions.d.ts.map +1 -0
- package/dist/dev/playback/primitives/report-track-conditions.js +86 -0
- package/dist/dev/playback/primitives/report-track-conditions.js.map +1 -0
- package/dist/dev/playback/primitives/segment-load-pipeline.d.ts +2 -0
- package/dist/dev/playback/primitives/segment-load-pipeline.js +96 -0
- package/dist/dev/playback/primitives/segment-load-pipeline.js.map +1 -0
- package/dist/dev/playback/primitives/selection-rules.d.ts +38 -0
- package/dist/dev/playback/primitives/selection-rules.d.ts.map +1 -0
- package/dist/dev/playback/primitives/selection-rules.js +86 -0
- package/dist/dev/playback/primitives/selection-rules.js.map +1 -0
- package/dist/dev/playback/primitives/source-buffer-messages.d.ts +43 -0
- package/dist/dev/playback/primitives/source-buffer-messages.d.ts.map +1 -0
- package/dist/dev/playback/primitives/text-segment-load-pipeline.d.ts +65 -0
- package/dist/dev/playback/primitives/text-segment-load-pipeline.d.ts.map +1 -0
- package/dist/dev/playback/primitives/text-segment-load-pipeline.js +37 -0
- package/dist/dev/playback/primitives/text-segment-load-pipeline.js.map +1 -0
- package/dist/dev/playback/primitives/text-track-messages.d.ts +14 -0
- package/dist/dev/playback/primitives/text-track-messages.d.ts.map +1 -0
- package/dist/dev/playback/primitives/track-types.js +61 -0
- package/dist/dev/playback/primitives/track-types.js.map +1 -0
- package/package.json +63 -26
- package/dist/adapter-CMw-rvbk.js +0 -3512
- package/dist/adapter-CMw-rvbk.js.map +0 -1
- package/dist/adapter-l8iJN_GI.d.ts +0 -689
- package/dist/adapter-l8iJN_GI.d.ts.map +0 -1
- package/dist/dom/index.d.ts +0 -243
- package/dist/dom/index.d.ts.map +0 -1
- package/dist/dom/index.js +0 -38
- package/dist/dom/index.js.map +0 -1
- package/dist/dom/playback-engine/index.d.ts +0 -2
- package/dist/dom/playback-engine/index.js +0 -4
- package/dist/index.d.ts +0 -13
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -3
- package/dist/src-DRsS_H80.js +0 -14
- package/dist/src-DRsS_H80.js.map +0 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { peek } from "../../core/signals/primitives.js";
|
|
2
|
+
import { SerialRunner, Task } from "../../core/tasks/task.js";
|
|
3
|
+
import { createMachineActor } from "../../core/actors/create-machine-actor.js";
|
|
4
|
+
import { DEFAULT_FORWARD_BUFFER_CONFIG, getSegmentsToLoad } from "../../media/buffer/forward-buffer.js";
|
|
5
|
+
import { DEFAULT_TEXT_MESSAGE_PIPELINES } from "../primitives/text-segment-load-pipeline.js";
|
|
6
|
+
//#region src/playback/actors/text-track-segment-loader.ts
|
|
7
|
+
/**
|
|
8
|
+
* Loads text-track segments for a track and delegates cue management
|
|
9
|
+
* to a TextTracksActor. Mirrors the v/a `SegmentLoaderActor` shape (FSM
|
|
10
|
+
* with `idle` / `loading` and `inFlight*` context for continue-vs-preempt),
|
|
11
|
+
* adapted to text:
|
|
12
|
+
*
|
|
13
|
+
* - No init segment, no flush ops (text cues don't need eviction — they're
|
|
14
|
+
* small and the playhead-relative window is enforced by the runtime).
|
|
15
|
+
* - Single in-flight identity (`inFlightSegmentId`) — text has only the
|
|
16
|
+
* media-segment path, no init-segment path.
|
|
17
|
+
*
|
|
18
|
+
* Planning is done in the load handler on every incoming message:
|
|
19
|
+
* `getSegmentsToLoad` filters to the forward window, then the segments
|
|
20
|
+
* not already in `TextTracksActor`'s context are scheduled. When a new
|
|
21
|
+
* `load` arrives mid-run, the handler replans and either:
|
|
22
|
+
*
|
|
23
|
+
* - **Continues**: the in-flight segment is still in the new plan →
|
|
24
|
+
* `abortPending` only, schedule the rest of the plan (minus the
|
|
25
|
+
* in-flight item, which covers its slot).
|
|
26
|
+
* - **Preempts**: in-flight segment is no longer wanted (track switch,
|
|
27
|
+
* large seek out of window) → `abortAll`, schedule the new plan
|
|
28
|
+
* from scratch.
|
|
29
|
+
*
|
|
30
|
+
* The cue parser is injected so this factory is host-agnostic. A DOM
|
|
31
|
+
* host supplies a VTT parser backed by `<track>`/`TextTrack` APIs; a
|
|
32
|
+
* non-DOM host (worker, test fake, alternate runtime) supplies its own.
|
|
33
|
+
*/
|
|
34
|
+
function createTextTrackSegmentLoaderActor(textTracksActor, resolveSegment, config = {}, compositionDeps = {
|
|
35
|
+
state: {},
|
|
36
|
+
context: {},
|
|
37
|
+
config: {}
|
|
38
|
+
}) {
|
|
39
|
+
const forwardBufferConfig = {
|
|
40
|
+
...DEFAULT_FORWARD_BUFFER_CONFIG,
|
|
41
|
+
...config.forwardBuffer
|
|
42
|
+
};
|
|
43
|
+
const deps = {
|
|
44
|
+
state: compositionDeps.state,
|
|
45
|
+
context: compositionDeps.context,
|
|
46
|
+
config: {
|
|
47
|
+
...compositionDeps.config,
|
|
48
|
+
textTracksActor,
|
|
49
|
+
resolveSegment
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const pipeline = (config.messagePipelines ?? DEFAULT_TEXT_MESSAGE_PIPELINES)();
|
|
53
|
+
/**
|
|
54
|
+
* Translate a load message into an ordered TextLoadTask list based on
|
|
55
|
+
* committed actor state. In-flight awareness is handled separately in
|
|
56
|
+
* the `loading` state's load handler.
|
|
57
|
+
*
|
|
58
|
+
* Metadata mode (no `range`) is a no-op for text — text tracks have
|
|
59
|
+
* no init-segment concept, so there's nothing to load until a range
|
|
60
|
+
* arrives via `'full-range'` dispatch.
|
|
61
|
+
*/
|
|
62
|
+
const planTasks = (message) => {
|
|
63
|
+
const { track, range } = message;
|
|
64
|
+
if (!range) return [];
|
|
65
|
+
const trackId = track.id;
|
|
66
|
+
const bufferedSegments = peek(textTracksActor.snapshot).context.segments[trackId] ?? [];
|
|
67
|
+
return getSegmentsToLoad(track.segments, bufferedSegments, range.start, forwardBufferConfig).map((segment) => ({
|
|
68
|
+
segment,
|
|
69
|
+
trackId
|
|
70
|
+
}));
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Wraps a TextLoadTask into a Task that runs the op's step pipeline
|
|
74
|
+
* (resolve/relocate/dispatch, per the composition's `messagePipelines`).
|
|
75
|
+
* Updates `inFlightSegmentId` around the async region so the load handler can
|
|
76
|
+
* make accurate continue/preempt decisions, and checks the abort signal before
|
|
77
|
+
* each step.
|
|
78
|
+
*
|
|
79
|
+
* Text degrades gracefully: a step throwing (e.g. a failed segment fetch) is
|
|
80
|
+
* logged and swallowed so the runner continues to the next segment — unlike the
|
|
81
|
+
* v/a loader, where a failed init must abort the remaining tasks.
|
|
82
|
+
*/
|
|
83
|
+
const makeLoadTask = (op, { getContext, setContext }) => {
|
|
84
|
+
return new Task(async (signal) => {
|
|
85
|
+
if (signal.aborted) return;
|
|
86
|
+
const frame = { op };
|
|
87
|
+
setContext({
|
|
88
|
+
...getContext(),
|
|
89
|
+
inFlightTrackId: op.trackId,
|
|
90
|
+
inFlightSegmentId: op.segment.id
|
|
91
|
+
});
|
|
92
|
+
try {
|
|
93
|
+
for (const step of pipeline) {
|
|
94
|
+
if (signal.aborted) return;
|
|
95
|
+
await step(frame, signal, deps);
|
|
96
|
+
}
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.error("Failed to load text-track segment:", error);
|
|
99
|
+
} finally {
|
|
100
|
+
setContext({
|
|
101
|
+
...getContext(),
|
|
102
|
+
inFlightTrackId: null,
|
|
103
|
+
inFlightSegmentId: null
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
const scheduleAll = (tasks, ctx) => {
|
|
109
|
+
for (const op of tasks) ctx.runner.schedule(makeLoadTask(op, ctx)).then(void 0, (e) => {
|
|
110
|
+
if (e instanceof Error && e.name === "AbortError") return;
|
|
111
|
+
console.error("Unexpected error in text-track segment loader:", e);
|
|
112
|
+
ctx.runner.abortPending();
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
return createMachineActor({
|
|
116
|
+
runner: () => new SerialRunner(),
|
|
117
|
+
initial: "idle",
|
|
118
|
+
context: {
|
|
119
|
+
inFlightTrackId: null,
|
|
120
|
+
inFlightSegmentId: null
|
|
121
|
+
},
|
|
122
|
+
states: {
|
|
123
|
+
idle: { on: { load: (msg, ctx) => {
|
|
124
|
+
const tasks = planTasks(msg);
|
|
125
|
+
if (tasks.length === 0) return;
|
|
126
|
+
ctx.transition("loading");
|
|
127
|
+
scheduleAll(tasks, ctx);
|
|
128
|
+
} } },
|
|
129
|
+
loading: {
|
|
130
|
+
onSettled: "idle",
|
|
131
|
+
on: { load: (msg, ctx) => {
|
|
132
|
+
const { context, runner } = ctx;
|
|
133
|
+
const tasks = planTasks(msg);
|
|
134
|
+
if (context.inFlightTrackId !== null && context.inFlightSegmentId !== null && tasks.some((t) => t.trackId === context.inFlightTrackId && t.segment.id === context.inFlightSegmentId)) {
|
|
135
|
+
runner.abortPending();
|
|
136
|
+
scheduleAll(tasks.filter((t) => !(t.trackId === context.inFlightTrackId && t.segment.id === context.inFlightSegmentId)), ctx);
|
|
137
|
+
} else {
|
|
138
|
+
runner.abortAll();
|
|
139
|
+
scheduleAll(tasks, ctx);
|
|
140
|
+
}
|
|
141
|
+
} }
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
export { createTextTrackSegmentLoaderActor };
|
|
148
|
+
|
|
149
|
+
//# sourceMappingURL=text-track-segment-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-track-segment-loader.js","names":[],"sources":["../../../../src/playback/actors/text-track-segment-loader.ts"],"sourcesContent":["import { createMachineActor, type HandlerContext, type MessageActor } from '../../core/actors/create-machine-actor';\nimport { peek } from '../../core/signals/primitives';\nimport { SerialRunner, Task } from '../../core/tasks/task';\nimport {\n DEFAULT_FORWARD_BUFFER_CONFIG,\n type ForwardBufferConfig,\n getSegmentsToLoad,\n} from '../../media/buffer/forward-buffer';\nimport type { Cue, TextTrack } from '../../media/types';\nimport {\n DEFAULT_TEXT_MESSAGE_PIPELINES,\n type TextFrame,\n type TextLoadTask,\n type TextMessagePipelines,\n type TextStepDeps,\n type TextTrackSegmentResolver,\n} from '../primitives/text-segment-load-pipeline';\nimport type { TextTracksActor } from './text-tracks';\n\n// =============================================================================\n// Message / actor types\n// =============================================================================\n\n/**\n * Mirrors the v/a `SegmentLoaderMessage` shape. `range` carries the\n * forward-window anchor (`range.start` is treated as the load anchor;\n * the actor computes its own forward window internally via\n * `getSegmentsToLoad`). When `range` is omitted (metadata mode), this\n * actor is a no-op — text tracks have no init-segment concept.\n */\nexport type TextTrackSegmentLoaderMessage = {\n type: 'load';\n track: TextTrack;\n range?: { start: number; end: number };\n};\n\n/** Finite states of the actor. */\nexport type TextTrackSegmentLoaderActorState = 'idle' | 'loading' | 'destroyed';\n\n/** Non-finite (extended) data managed by the actor. */\nexport interface TextTrackSegmentLoaderActorContext {\n /**\n * Track ID of the segment currently being fetched, or null. Paired\n * with `inFlightSegmentId` so the continue-vs-preempt check survives\n * cross-track segment-id collisions (e.g. each track starts at\n * `seg-0`).\n */\n inFlightTrackId: string | null;\n /**\n * Segment ID currently being fetched, or null. Used together with\n * `inFlightTrackId` by the `loading` state's `load` handler.\n */\n inFlightSegmentId: string | null;\n}\n\nexport type TextTrackSegmentLoaderActor = MessageActor<\n TextTrackSegmentLoaderActorState,\n TextTrackSegmentLoaderActorContext,\n TextTrackSegmentLoaderMessage\n>;\n\n/**\n * Configuration for `createTextTrackSegmentLoaderActor`. Spread over\n * `DEFAULT_FORWARD_BUFFER_CONFIG` to override individual forward-window\n * fields (e.g. `bufferDuration`). Text tracks don't have a back-buffer\n * concern — cues evict by their playhead-relative window at runtime —\n * so no `backBuffer` config field.\n */\nexport interface TextTrackSegmentLoaderActorConfig<C extends Cue = Cue> {\n forwardBuffer?: Partial<ForwardBufferConfig>;\n /** Ordered step pipeline. Defaults to {@link DEFAULT_TEXT_MESSAGE_PIPELINES} (`resolveCues → dispatchCues`). */\n messagePipelines?: TextMessagePipelines<C>;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\n/**\n * Loads text-track segments for a track and delegates cue management\n * to a TextTracksActor. Mirrors the v/a `SegmentLoaderActor` shape (FSM\n * with `idle` / `loading` and `inFlight*` context for continue-vs-preempt),\n * adapted to text:\n *\n * - No init segment, no flush ops (text cues don't need eviction — they're\n * small and the playhead-relative window is enforced by the runtime).\n * - Single in-flight identity (`inFlightSegmentId`) — text has only the\n * media-segment path, no init-segment path.\n *\n * Planning is done in the load handler on every incoming message:\n * `getSegmentsToLoad` filters to the forward window, then the segments\n * not already in `TextTracksActor`'s context are scheduled. When a new\n * `load` arrives mid-run, the handler replans and either:\n *\n * - **Continues**: the in-flight segment is still in the new plan →\n * `abortPending` only, schedule the rest of the plan (minus the\n * in-flight item, which covers its slot).\n * - **Preempts**: in-flight segment is no longer wanted (track switch,\n * large seek out of window) → `abortAll`, schedule the new plan\n * from scratch.\n *\n * The cue parser is injected so this factory is host-agnostic. A DOM\n * host supplies a VTT parser backed by `<track>`/`TextTrack` APIs; a\n * non-DOM host (worker, test fake, alternate runtime) supplies its own.\n */\nexport function createTextTrackSegmentLoaderActor<C extends Cue>(\n textTracksActor: TextTracksActor<C>,\n resolveSegment: TextTrackSegmentResolver<C>,\n config: TextTrackSegmentLoaderActorConfig<C> = {},\n // Composition deps threaded opaquely into each step's `TextStepDeps` (relocation\n // reads composition state). The loader never reads them. Defaults empty for\n // standalone / base-pipeline use.\n compositionDeps: TextStepDeps = { state: {}, context: {}, config: {} }\n): TextTrackSegmentLoaderActor {\n type UserState = Exclude<TextTrackSegmentLoaderActorState, 'destroyed'>;\n type Ctx = HandlerContext<UserState, TextTrackSegmentLoaderActorContext, () => SerialRunner>;\n\n const forwardBufferConfig: ForwardBufferConfig = { ...DEFAULT_FORWARD_BUFFER_CONFIG, ...config.forwardBuffer };\n // Fold the loader's wiring into the passthrough `config` (see `textStepWiring`) so\n // base steps read it from the uniform `{state,context,config}` — present in both\n // composition and standalone use.\n const deps: TextStepDeps = {\n state: compositionDeps.state,\n context: compositionDeps.context,\n config: { ...compositionDeps.config, textTracksActor, resolveSegment },\n };\n // Built once per actor; default is `resolveCues → dispatchCues`.\n const pipeline = (config.messagePipelines ?? DEFAULT_TEXT_MESSAGE_PIPELINES)();\n\n /**\n * Translate a load message into an ordered TextLoadTask list based on\n * committed actor state. In-flight awareness is handled separately in\n * the `loading` state's load handler.\n *\n * Metadata mode (no `range`) is a no-op for text — text tracks have\n * no init-segment concept, so there's nothing to load until a range\n * arrives via `'full-range'` dispatch.\n */\n const planTasks = (message: TextTrackSegmentLoaderMessage): TextLoadTask[] => {\n const { track, range } = message;\n if (!range) return [];\n const trackId = track.id;\n // Peek (don't track) the snapshot: the loader's `send` is typically\n // invoked from inside the dispatcher's effect body, so a tracked\n // `.get()` here would leak the textTracksActor snapshot into the\n // dispatcher's dep set — every `add-cues` would re-fire the dispatcher\n // and schedule duplicate loads.\n const bufferedSegments = peek(textTracksActor.snapshot).context.segments[trackId] ?? [];\n // `getSegmentsToLoad` uses the actor's threaded `forwardBufferConfig`\n // to compute its forward-window; only `range.start` is consulted\n // here as the playhead anchor. `range.end` is informational — it\n // carries the dispatcher's intended window upper bound but doesn't\n // override the actor's planning.\n const segmentsToLoad = getSegmentsToLoad(track.segments, bufferedSegments, range.start, forwardBufferConfig);\n return segmentsToLoad.map((segment) => ({ segment, trackId }));\n };\n\n /**\n * Wraps a TextLoadTask into a Task that runs the op's step pipeline\n * (resolve/relocate/dispatch, per the composition's `messagePipelines`).\n * Updates `inFlightSegmentId` around the async region so the load handler can\n * make accurate continue/preempt decisions, and checks the abort signal before\n * each step.\n *\n * Text degrades gracefully: a step throwing (e.g. a failed segment fetch) is\n * logged and swallowed so the runner continues to the next segment — unlike the\n * v/a loader, where a failed init must abort the remaining tasks.\n */\n const makeLoadTask = (op: TextLoadTask, { getContext, setContext }: Ctx): Task<void> => {\n return new Task(async (signal) => {\n if (signal.aborted) return;\n const frame: TextFrame<C> = { op };\n setContext({ ...getContext(), inFlightTrackId: op.trackId, inFlightSegmentId: op.segment.id });\n try {\n for (const step of pipeline) {\n if (signal.aborted) return;\n await step(frame, signal, deps);\n }\n } catch (error) {\n // Graceful degradation: log and continue to the next segment.\n console.error('Failed to load text-track segment:', error);\n } finally {\n setContext({ ...getContext(), inFlightTrackId: null, inFlightSegmentId: null });\n }\n });\n };\n\n const scheduleAll = (tasks: TextLoadTask[], ctx: Ctx): void => {\n for (const op of tasks) {\n ctx.runner.schedule(makeLoadTask(op, ctx)).then(undefined, (e: unknown) => {\n if (e instanceof Error && e.name === 'AbortError') return;\n console.error('Unexpected error in text-track segment loader:', e);\n ctx.runner.abortPending();\n });\n }\n };\n\n return createMachineActor<\n UserState,\n TextTrackSegmentLoaderActorContext,\n TextTrackSegmentLoaderMessage,\n () => SerialRunner\n >({\n runner: () => new SerialRunner(),\n initial: 'idle',\n context: { inFlightTrackId: null, inFlightSegmentId: null },\n states: {\n idle: {\n on: {\n load: (msg, ctx) => {\n const tasks = planTasks(msg);\n if (tasks.length === 0) return;\n ctx.transition('loading');\n scheduleAll(tasks, ctx);\n },\n },\n },\n loading: {\n onSettled: 'idle',\n on: {\n load: (msg, ctx) => {\n const { context, runner } = ctx;\n const tasks = planTasks(msg);\n\n const inFlightStillNeeded =\n context.inFlightTrackId !== null &&\n context.inFlightSegmentId !== null &&\n tasks.some((t) => t.trackId === context.inFlightTrackId && t.segment.id === context.inFlightSegmentId);\n\n if (inFlightStillNeeded) {\n // Continue: keep the in-flight fetch, schedule the rest.\n runner.abortPending();\n scheduleAll(\n tasks.filter(\n (t) => !(t.trackId === context.inFlightTrackId && t.segment.id === context.inFlightSegmentId)\n ),\n ctx\n );\n } else {\n // Preempt: abort everything (including in-flight) and replan.\n runner.abortAll();\n scheduleAll(tasks, ctx);\n }\n },\n },\n },\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyGA,SAAgB,kCACd,iBACA,gBACA,SAA+C,CAAC,GAIhD,kBAAgC;CAAE,OAAO,CAAC;CAAG,SAAS,CAAC;CAAG,QAAQ,CAAC;AAAE,GACxC;CAI7B,MAAM,sBAA2C;EAAE,GAAG;EAA+B,GAAG,OAAO;CAAc;CAI7G,MAAM,OAAqB;EACzB,OAAO,gBAAgB;EACvB,SAAS,gBAAgB;EACzB,QAAQ;GAAE,GAAG,gBAAgB;GAAQ;GAAiB;EAAe;CACvE;CAEA,MAAM,YAAY,OAAO,oBAAoB,+BAAA,CAAgC;;;;;;;;;;CAW7E,MAAM,aAAa,YAA2D;EAC5E,MAAM,EAAE,OAAO,UAAU;EACzB,IAAI,CAAC,OAAO,OAAO,CAAC;EACpB,MAAM,UAAU,MAAM;EAMtB,MAAM,mBAAmB,KAAK,gBAAgB,QAAQ,CAAC,CAAC,QAAQ,SAAS,YAAY,CAAC;EAOtF,OADuB,kBAAkB,MAAM,UAAU,kBAAkB,MAAM,OAAO,mBACpE,CAAC,CAAC,KAAK,aAAa;GAAE;GAAS;EAAQ,EAAE;CAC/D;;;;;;;;;;;;CAaA,MAAM,gBAAgB,IAAkB,EAAE,YAAY,iBAAkC;EACtF,OAAO,IAAI,KAAK,OAAO,WAAW;GAChC,IAAI,OAAO,SAAS;GACpB,MAAM,QAAsB,EAAE,GAAG;GACjC,WAAW;IAAE,GAAG,WAAW;IAAG,iBAAiB,GAAG;IAAS,mBAAmB,GAAG,QAAQ;GAAG,CAAC;GAC7F,IAAI;IACF,KAAK,MAAM,QAAQ,UAAU;KAC3B,IAAI,OAAO,SAAS;KACpB,MAAM,KAAK,OAAO,QAAQ,IAAI;IAChC;GACF,SAAS,OAAO;IAEd,QAAQ,MAAM,sCAAsC,KAAK;GAC3D,UAAU;IACR,WAAW;KAAE,GAAG,WAAW;KAAG,iBAAiB;KAAM,mBAAmB;IAAK,CAAC;GAChF;EACF,CAAC;CACH;CAEA,MAAM,eAAe,OAAuB,QAAmB;EAC7D,KAAK,MAAM,MAAM,OACf,IAAI,OAAO,SAAS,aAAa,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,KAAA,IAAY,MAAe;GACzE,IAAI,aAAa,SAAS,EAAE,SAAS,cAAc;GACnD,QAAQ,MAAM,kDAAkD,CAAC;GACjE,IAAI,OAAO,aAAa;EAC1B,CAAC;CAEL;CAEA,OAAO,mBAKL;EACA,cAAc,IAAI,aAAa;EAC/B,SAAS;EACT,SAAS;GAAE,iBAAiB;GAAM,mBAAmB;EAAK;EAC1D,QAAQ;GACN,MAAM,EACJ,IAAI,EACF,OAAO,KAAK,QAAQ;IAClB,MAAM,QAAQ,UAAU,GAAG;IAC3B,IAAI,MAAM,WAAW,GAAG;IACxB,IAAI,WAAW,SAAS;IACxB,YAAY,OAAO,GAAG;GACxB,EACF,EACF;GACA,SAAS;IACP,WAAW;IACX,IAAI,EACF,OAAO,KAAK,QAAQ;KAClB,MAAM,EAAE,SAAS,WAAW;KAC5B,MAAM,QAAQ,UAAU,GAAG;KAO3B,IAJE,QAAQ,oBAAoB,QAC5B,QAAQ,sBAAsB,QAC9B,MAAM,MAAM,MAAM,EAAE,YAAY,QAAQ,mBAAmB,EAAE,QAAQ,OAAO,QAAQ,iBAAiB,GAE9E;MAEvB,OAAO,aAAa;MACpB,YACE,MAAM,QACH,MAAM,EAAE,EAAE,YAAY,QAAQ,mBAAmB,EAAE,QAAQ,OAAO,QAAQ,kBAC7E,GACA,GACF;KACF,OAAO;MAEL,OAAO,SAAS;MAChB,YAAY,OAAO,GAAG;KACxB;IACF,EACF;GACF;EACF;CACF,CAAC;AACH"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { effect } from "../../../core/signals/effect.js";
|
|
2
|
+
import { SVTA_NO_SUPPORTED_AUDIO_TRACK, SVTA_UNSUPPORTED_PLAYBACK_FEATURE } from "../../../media/errors.js";
|
|
3
|
+
import { createHlsAudioEngine } from "../../engines/hls/engine-audio-only.js";
|
|
4
|
+
import { UNSUPPORTED_PLAYBACK_FEATURE_MESSAGE } from "../../primitives/error-messages.js";
|
|
5
|
+
import { firstFatal, hasUnsupportedFeatureCause, withAlternativeMediaSuggestion } from "../hls-video/error-surface.js";
|
|
6
|
+
//#region src/playback/adapters/hls-audio/adapter.ts
|
|
7
|
+
const hlsAudioMediaDefaultProps = {
|
|
8
|
+
src: "",
|
|
9
|
+
preload: "",
|
|
10
|
+
disableRemotePlayback: false
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Which reported conditions this composition treats as fatal. Only the audio
|
|
14
|
+
* verdict: an audio-only engine composes no video selection, so
|
|
15
|
+
* `SVTA_NO_SUPPORTED_VIDEO_TRACK` is never reported and surfacing it would
|
|
16
|
+
* describe a track type this media doesn't have.
|
|
17
|
+
*/
|
|
18
|
+
const FATAL_SVTA_CODES = /* @__PURE__ */ new Set([SVTA_NO_SUPPORTED_AUDIO_TRACK]);
|
|
19
|
+
/**
|
|
20
|
+
* Mixin that adds SPF audio-only HLS playback to any base class.
|
|
21
|
+
*
|
|
22
|
+
* @fires error - Fired when a fatal condition is reported. Read `error` for it.
|
|
23
|
+
*
|
|
24
|
+
* Parallel to `HlsVideoMediaMixin` with one substantive difference: the
|
|
25
|
+
* underlying engine is the audio-only variant (`createHlsAudioEngine`),
|
|
26
|
+
* which omits video and text-track behaviors. The src / preload /
|
|
27
|
+
* disableRemotePlayback / play() contract per the WHATWG HTML spec is identical
|
|
28
|
+
* to the default adapter.
|
|
29
|
+
*
|
|
30
|
+
* Selecting this adapter is the variant decision: instantiating
|
|
31
|
+
* `HlsAudioMediaElement` opts the consumer into audio-only
|
|
32
|
+
* delivery even when the source is a mixed-AV HLS manifest.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* class HlsAudioMedia extends HlsAudioMediaMixin(HTMLVideoElementHost) {}
|
|
36
|
+
*
|
|
37
|
+
* const media = new HlsAudioMedia();
|
|
38
|
+
* media.attach(document.querySelector('video'));
|
|
39
|
+
* media.src = 'https://stream.mux.com/abc123.m3u8';
|
|
40
|
+
*/
|
|
41
|
+
function HlsAudioMediaMixin(BaseClass) {
|
|
42
|
+
class HlsAudioMediaImpl extends BaseClass {
|
|
43
|
+
/**
|
|
44
|
+
* A complete sentence naming the Media to reach for when this one can't play
|
|
45
|
+
* a source. Appended to the copy this adapter logs.
|
|
46
|
+
*
|
|
47
|
+
* Empty here, and overridden the same way as on the video adapter — see its
|
|
48
|
+
* note. `hls-audio` has no better-equipped sibling of its own; the
|
|
49
|
+
* Mux audio Media built on this engine does, and points at the hls.js-backed
|
|
50
|
+
* one.
|
|
51
|
+
*/
|
|
52
|
+
static get alternativeMediaSuggestion() {}
|
|
53
|
+
#engine;
|
|
54
|
+
#config;
|
|
55
|
+
#signals;
|
|
56
|
+
#preload = hlsAudioMediaDefaultProps.preload;
|
|
57
|
+
#disableRemotePlayback = hlsAudioMediaDefaultProps.disableRemotePlayback;
|
|
58
|
+
#error = null;
|
|
59
|
+
/** Reported condition currently surfaced — see the video adapter's note. */
|
|
60
|
+
#reportedCode = null;
|
|
61
|
+
#stopErrorSync;
|
|
62
|
+
/** Pending loadstart listener from a deferred play() retry, if any. */
|
|
63
|
+
#loadstartListener = null;
|
|
64
|
+
constructor(...args) {
|
|
65
|
+
super(...args);
|
|
66
|
+
const { config } = args?.[0] ?? {};
|
|
67
|
+
this.#config = config;
|
|
68
|
+
this.#engine = this.#createEngine();
|
|
69
|
+
this.#stopErrorSync = effect(() => {
|
|
70
|
+
const errors = this.#signals.state.errors.get();
|
|
71
|
+
this.#setError(firstFatal(errors, FATAL_SVTA_CODES), errors);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The current fatal error, or `null`. Only *fatal* conditions appear here —
|
|
76
|
+
* the engine reports non-fatal ones too, which stay in `engine.state.errors`.
|
|
77
|
+
* Resets per source. Fires `'error'` when set.
|
|
78
|
+
*/
|
|
79
|
+
get error() {
|
|
80
|
+
return this.#error;
|
|
81
|
+
}
|
|
82
|
+
#setError(reported, errors) {
|
|
83
|
+
if (!reported) {
|
|
84
|
+
this.#error = null;
|
|
85
|
+
this.#reportedCode = null;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (this.#reportedCode === reported.code) return;
|
|
89
|
+
this.#reportedCode = reported.code;
|
|
90
|
+
const unsupported = hasUnsupportedFeatureCause(errors);
|
|
91
|
+
if (unsupported) console.error(this.#withSuggestion(UNSUPPORTED_PLAYBACK_FEATURE_MESSAGE), { conditions: errors });
|
|
92
|
+
this.#error = {
|
|
93
|
+
code: unsupported ? SVTA_UNSUPPORTED_PLAYBACK_FEATURE : reported.code,
|
|
94
|
+
message: reported.message ?? "",
|
|
95
|
+
...reported.data === void 0 ? {} : { data: reported.data }
|
|
96
|
+
};
|
|
97
|
+
this.dispatchEvent?.(new Event("error"));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Underlying playback engine — the low-level SPF reactive composition that
|
|
101
|
+
* drives playback. An advanced escape hatch for direct engine access;
|
|
102
|
+
* normal playback is driven through this element's own properties and
|
|
103
|
+
* methods.
|
|
104
|
+
*/
|
|
105
|
+
get engine() {
|
|
106
|
+
return this.#engine;
|
|
107
|
+
}
|
|
108
|
+
attach(mediaElement) {
|
|
109
|
+
super.attach?.(mediaElement);
|
|
110
|
+
this.#signals.context.mediaElement.set(mediaElement);
|
|
111
|
+
}
|
|
112
|
+
detach() {
|
|
113
|
+
this.#cancelPendingPlay();
|
|
114
|
+
this.#signals.context.mediaElement.set(void 0);
|
|
115
|
+
super.detach?.();
|
|
116
|
+
}
|
|
117
|
+
destroy() {
|
|
118
|
+
this.#cancelPendingPlay();
|
|
119
|
+
this.#stopErrorSync();
|
|
120
|
+
this.#engine.destroy();
|
|
121
|
+
}
|
|
122
|
+
/** Preload type (`'none'` / `'metadata'` / `'auto'`). */
|
|
123
|
+
get preload() {
|
|
124
|
+
return this.#preload;
|
|
125
|
+
}
|
|
126
|
+
set preload(value) {
|
|
127
|
+
this.#preload = value;
|
|
128
|
+
if (value) this.#signals.state.preload.set(value);
|
|
129
|
+
}
|
|
130
|
+
get disableRemotePlayback() {
|
|
131
|
+
return this.#disableRemotePlayback;
|
|
132
|
+
}
|
|
133
|
+
set disableRemotePlayback(value) {
|
|
134
|
+
this.#disableRemotePlayback = value;
|
|
135
|
+
this.#signals.state.disableRemotePlayback.set(value);
|
|
136
|
+
}
|
|
137
|
+
get src() {
|
|
138
|
+
return this.#signals.state.presentation.get()?.url ?? "";
|
|
139
|
+
}
|
|
140
|
+
set src(value) {
|
|
141
|
+
if (value === this.src) return;
|
|
142
|
+
this.#cancelPendingPlay();
|
|
143
|
+
this.#signals.state.presentation.set(value ? { url: value } : void 0);
|
|
144
|
+
}
|
|
145
|
+
play() {
|
|
146
|
+
const mediaElement = this.#signals.context.mediaElement.get();
|
|
147
|
+
if (!mediaElement) return Promise.reject(/* @__PURE__ */ new Error("HlsAudioMediaElement: no media element attached"));
|
|
148
|
+
this.#signals.state.loadActivated.set(true);
|
|
149
|
+
return mediaElement.play().catch((err) => {
|
|
150
|
+
if (this.src) return new Promise((resolve, reject) => {
|
|
151
|
+
const listener = () => {
|
|
152
|
+
this.#loadstartListener = null;
|
|
153
|
+
mediaElement.play().then(resolve, reject);
|
|
154
|
+
};
|
|
155
|
+
this.#loadstartListener = listener;
|
|
156
|
+
mediaElement.addEventListener("loadstart", listener, { once: true });
|
|
157
|
+
});
|
|
158
|
+
throw err;
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/** `message`, plus the alternative-Media sentence when this class names one. */
|
|
162
|
+
#withSuggestion(message) {
|
|
163
|
+
return withAlternativeMediaSuggestion(message, this);
|
|
164
|
+
}
|
|
165
|
+
#createEngine() {
|
|
166
|
+
return createHlsAudioEngine({
|
|
167
|
+
...this.#config,
|
|
168
|
+
onSignalsReady: (signals) => {
|
|
169
|
+
this.#signals = signals;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
#cancelPendingPlay() {
|
|
174
|
+
if (!this.#loadstartListener) return;
|
|
175
|
+
this.#signals.context.mediaElement.get()?.removeEventListener("loadstart", this.#loadstartListener);
|
|
176
|
+
this.#loadstartListener = null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return HlsAudioMediaImpl;
|
|
180
|
+
}
|
|
181
|
+
/** Standalone SPF audio-only media adapter with no base class. */
|
|
182
|
+
var HlsAudioMediaElement = class extends HlsAudioMediaMixin(class {}) {};
|
|
183
|
+
//#endregion
|
|
184
|
+
export { HlsAudioMediaElement, HlsAudioMediaMixin, hlsAudioMediaDefaultProps };
|
|
185
|
+
|
|
186
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","names":["#engine","#config","#createEngine","#stopErrorSync","#signals","#setError","#error","#reportedCode","#withSuggestion","#cancelPendingPlay","#preload","#disableRemotePlayback","#loadstartListener"],"sources":["../../../../../src/playback/adapters/hls-audio/adapter.ts"],"sourcesContent":["import type { Constructor, MixinReturn } from '@videojs/utils/types';\nimport type { Composition } from '../../../core/composition/create-composition';\nimport { effect } from '../../../core/signals/effect';\nimport {\n SVTA_NO_SUPPORTED_AUDIO_TRACK,\n SVTA_UNSUPPORTED_PLAYBACK_FEATURE,\n type SvtaError,\n} from '../../../media/errors';\nimport {\n createHlsAudioEngine,\n type HlsAudioEngineConfig,\n type HlsAudioEngineContext,\n type HlsAudioEngineSignals,\n type HlsAudioEngineState,\n} from '../../engines/hls/engine-audio-only';\nimport { UNSUPPORTED_PLAYBACK_FEATURE_MESSAGE } from '../../primitives/error-messages';\nimport {\n firstFatal,\n type HlsVideoMediaError,\n hasUnsupportedFeatureCause,\n withAlternativeMediaSuggestion,\n} from '../hls-video/error-surface';\n\nexport interface HlsAudioMediaProps {\n src: string;\n preload: '' | 'none' | 'metadata' | 'auto';\n disableRemotePlayback: boolean;\n}\n\nexport const hlsAudioMediaDefaultProps: HlsAudioMediaProps = {\n src: '',\n preload: '',\n disableRemotePlayback: false,\n};\n\nexport interface HlsAudioMediaAPI extends HlsAudioMediaProps {\n readonly engine: Composition<HlsAudioEngineState, HlsAudioEngineContext>;\n readonly error: HlsVideoMediaError | null;\n attach(mediaElement: HTMLMediaElement): void;\n detach(): void;\n destroy(): void;\n play(): Promise<void>;\n}\n\n/**\n * Which reported conditions this composition treats as fatal. Only the audio\n * verdict: an audio-only engine composes no video selection, so\n * `SVTA_NO_SUPPORTED_VIDEO_TRACK` is never reported and surfacing it would\n * describe a track type this media doesn't have.\n */\nconst FATAL_SVTA_CODES: ReadonlySet<number> = new Set<number>([SVTA_NO_SUPPORTED_AUDIO_TRACK]);\n\n/**\n * Mixin that adds SPF audio-only HLS playback to any base class.\n *\n * @fires error - Fired when a fatal condition is reported. Read `error` for it.\n *\n * Parallel to `HlsVideoMediaMixin` with one substantive difference: the\n * underlying engine is the audio-only variant (`createHlsAudioEngine`),\n * which omits video and text-track behaviors. The src / preload /\n * disableRemotePlayback / play() contract per the WHATWG HTML spec is identical\n * to the default adapter.\n *\n * Selecting this adapter is the variant decision: instantiating\n * `HlsAudioMediaElement` opts the consumer into audio-only\n * delivery even when the source is a mixed-AV HLS manifest.\n *\n * @example\n * class HlsAudioMedia extends HlsAudioMediaMixin(HTMLVideoElementHost) {}\n *\n * const media = new HlsAudioMedia();\n * media.attach(document.querySelector('video'));\n * media.src = 'https://stream.mux.com/abc123.m3u8';\n */\nexport function HlsAudioMediaMixin<Base extends Constructor<any>>(BaseClass: Base) {\n class HlsAudioMediaImpl extends BaseClass {\n /**\n * A complete sentence naming the Media to reach for when this one can't play\n * a source. Appended to the copy this adapter logs.\n *\n * Empty here, and overridden the same way as on the video adapter — see its\n * note. `hls-audio` has no better-equipped sibling of its own; the\n * Mux audio Media built on this engine does, and points at the hls.js-backed\n * one.\n */\n static get alternativeMediaSuggestion(): string | undefined {\n return undefined;\n }\n\n readonly #engine: Composition<HlsAudioEngineState, HlsAudioEngineContext>;\n #config: HlsAudioEngineConfig;\n #signals!: HlsAudioEngineSignals;\n #preload: '' | 'none' | 'metadata' | 'auto' = hlsAudioMediaDefaultProps.preload;\n #disableRemotePlayback: boolean = hlsAudioMediaDefaultProps.disableRemotePlayback;\n #error: HlsVideoMediaError | null = null;\n /** Reported condition currently surfaced — see the video adapter's note. */\n #reportedCode: number | null = null;\n #stopErrorSync: () => void;\n\n /** Pending loadstart listener from a deferred play() retry, if any. */\n #loadstartListener: (() => void) | null = null;\n\n constructor(...args: any[]) {\n super(...args);\n\n const { config } = args?.[0] ?? {};\n this.#config = config;\n this.#engine = this.#createEngine();\n\n // Promote the first fatal condition out of the engine's reported sequence\n // onto the media surface. Clearing rides the same signal: `collectErrors`\n // resets the slot per source, so a new source starts with no error without\n // this needing its own source-change hook.\n this.#stopErrorSync = effect(() => {\n const errors = this.#signals.state.errors.get();\n this.#setError(firstFatal(errors, FATAL_SVTA_CODES), errors);\n });\n }\n\n /**\n * The current fatal error, or `null`. Only *fatal* conditions appear here —\n * the engine reports non-fatal ones too, which stay in `engine.state.errors`.\n * Resets per source. Fires `'error'` when set.\n */\n get error(): HlsVideoMediaError | null {\n return this.#error;\n }\n\n #setError(reported: SvtaError | undefined, errors: readonly SvtaError[] | undefined): void {\n if (!reported) {\n // Cleared (new source). No event: `'error'` announces a failure, and\n // consumers reset their own copy on source change.\n this.#error = null;\n this.#reportedCode = null;\n return;\n }\n // Keyed on the code, not the object: a later append re-runs this effect\n // with an equal-but-new array, and re-firing `'error'` for a condition\n // already surfaced would look like a second failure.\n if (this.#reportedCode === reported.code) return;\n this.#reportedCode = reported.code;\n\n // See the video adapter: a cause this engine can't implement is what the\n // consumer needs, so it replaces the verdict's code on the surface.\n const unsupported = hasUnsupportedFeatureCause(errors);\n if (unsupported) {\n console.error(this.#withSuggestion(UNSUPPORTED_PLAYBACK_FEATURE_MESSAGE), { conditions: errors });\n }\n\n this.#error = {\n code: unsupported ? SVTA_UNSUPPORTED_PLAYBACK_FEATURE : reported.code,\n message: reported.message ?? '',\n ...(reported.data === undefined ? {} : { data: reported.data }),\n };\n this.dispatchEvent?.(new Event('error'));\n }\n\n /**\n * Underlying playback engine — the low-level SPF reactive composition that\n * drives playback. An advanced escape hatch for direct engine access;\n * normal playback is driven through this element's own properties and\n * methods.\n */\n get engine(): Composition<HlsAudioEngineState, HlsAudioEngineContext> {\n return this.#engine;\n }\n\n // -------------------------------------------------------------------------\n // Media element lifecycle\n // -------------------------------------------------------------------------\n\n attach(mediaElement: HTMLMediaElement): void {\n super.attach?.(mediaElement);\n this.#signals.context.mediaElement.set(mediaElement);\n }\n\n detach(): void {\n this.#cancelPendingPlay();\n this.#signals.context.mediaElement.set(undefined);\n super.detach?.();\n }\n\n destroy(): void {\n this.#cancelPendingPlay();\n this.#stopErrorSync();\n this.#engine.destroy();\n }\n\n // -------------------------------------------------------------------------\n // preload — synchronous IDL attribute (WHATWG §4.8.11.2)\n // -------------------------------------------------------------------------\n\n /** Preload type (`'none'` / `'metadata'` / `'auto'`). */\n get preload(): '' | 'none' | 'metadata' | 'auto' {\n return this.#preload;\n }\n\n set preload(value: '' | 'none' | 'metadata' | 'auto') {\n this.#preload = value;\n if (value) {\n this.#signals.state.preload.set(value);\n }\n }\n\n // -------------------------------------------------------------------------\n // disableRemotePlayback — synchronous IDL attribute (WHATWG Remote Playback)\n // Author intent for whether the AirPlay/remote picker is offered. Mirrors\n // the DOM attribute name; the value flows to `state.disableRemotePlayback`,\n // which `setupAirPlay` reads to honor an explicit opt-out. The underlying\n // media element's own `disableRemotePlayback` stays programmatically managed\n // (ManagedMediaSource needs it `true` to open; AirPlay flips it `false` once\n // the source is open), so author intent and the effective flag stay distinct.\n // -------------------------------------------------------------------------\n\n get disableRemotePlayback(): boolean {\n return this.#disableRemotePlayback;\n }\n\n set disableRemotePlayback(value: boolean) {\n this.#disableRemotePlayback = value;\n this.#signals.state.disableRemotePlayback.set(value);\n }\n\n // -------------------------------------------------------------------------\n // src — synchronous IDL attribute (WHATWG §4.8.11.2)\n // Each assignment overwrites the engine's presentation state in place. The\n // resolver FSM routes back through teardown → rebuild on the same engine,\n // mirroring how the browser's load algorithm resets media state on src change\n // — without recreating the engine or re-capturing its signals. Setting an\n // empty src un-resolves the presentation, tearing the current source down to\n // the engine's fresh-but-attached \"no source\" state.\n // -------------------------------------------------------------------------\n\n get src(): string {\n return this.#signals.state.presentation.get()?.url ?? '';\n }\n\n set src(value: string) {\n // Unchanged URL, no reload — see the video adapter's note.\n if (value === this.src) return;\n\n this.#cancelPendingPlay();\n this.#signals.state.presentation.set(value ? { url: value } : undefined);\n }\n\n // -------------------------------------------------------------------------\n // play() — WHATWG §4.8.11.8\n // -------------------------------------------------------------------------\n\n play(): Promise<void> {\n const mediaElement = this.#signals.context.mediaElement.get();\n if (!mediaElement) {\n return Promise.reject(new Error('HlsAudioMediaElement: no media element attached'));\n }\n\n this.#signals.state.loadActivated.set(true);\n\n return mediaElement.play().catch((err: unknown) => {\n if (this.src) {\n return new Promise<void>((resolve, reject) => {\n const listener = () => {\n this.#loadstartListener = null;\n mediaElement.play().then(resolve, reject);\n };\n this.#loadstartListener = listener;\n mediaElement.addEventListener('loadstart', listener, { once: true });\n });\n }\n throw err;\n });\n }\n\n // -------------------------------------------------------------------------\n // Private\n // -------------------------------------------------------------------------\n\n /** `message`, plus the alternative-Media sentence when this class names one. */\n #withSuggestion(message: string): string {\n return withAlternativeMediaSuggestion(message, this);\n }\n\n #createEngine(): Composition<HlsAudioEngineState, HlsAudioEngineContext> {\n return createHlsAudioEngine({\n ...this.#config,\n onSignalsReady: (signals) => {\n this.#signals = signals;\n },\n });\n }\n\n #cancelPendingPlay(): void {\n if (!this.#loadstartListener) return;\n const mediaElement = this.#signals.context.mediaElement.get();\n mediaElement?.removeEventListener('loadstart', this.#loadstartListener);\n this.#loadstartListener = null;\n }\n }\n\n // `MixinReturn` sources statics from `Base`, so the adapter's own static needs\n // adding back to the type or callers can't read it.\n return HlsAudioMediaImpl as unknown as MixinReturn<Base, HlsAudioMediaAPI> & {\n readonly alternativeMediaSuggestion: string | undefined;\n };\n}\n\n/** Standalone SPF audio-only media adapter with no base class. */\nexport class HlsAudioMediaElement extends HlsAudioMediaMixin(class {}) {}\n"],"mappings":";;;;;;AA6BA,MAAa,4BAAgD;CAC3D,KAAK;CACL,SAAS;CACT,uBAAuB;AACzB;;;;;;;AAiBA,MAAM,mCAAwC,IAAI,IAAY,CAAC,6BAA6B,CAAC;;;;;;;;;;;;;;;;;;;;;;;AAwB7F,SAAgB,mBAAkD,WAAiB;CACjF,MAAM,0BAA0B,UAAU;;;;;;;;;;EAUxC,WAAW,6BAAiD,CAE5D;EAEA;EACA;EACA;EACA,WAA8C,0BAA0B;EACxE,yBAAkC,0BAA0B;EAC5D,SAAoC;;EAEpC,gBAA+B;EAC/B;;EAGA,qBAA0C;EAE1C,YAAY,GAAG,MAAa;GAC1B,MAAM,GAAG,IAAI;GAEb,MAAM,EAAE,WAAW,OAAO,MAAM,CAAC;GACjC,KAAKC,UAAU;GACf,KAAKD,UAAU,KAAKE,cAAc;GAMlC,KAAKC,iBAAiB,aAAa;IACjC,MAAM,SAAS,KAAKC,SAAS,MAAM,OAAO,IAAI;IAC9C,KAAKC,UAAU,WAAW,QAAQ,gBAAgB,GAAG,MAAM;GAC7D,CAAC;EACH;;;;;;EAOA,IAAI,QAAmC;GACrC,OAAO,KAAKC;EACd;EAEA,UAAU,UAAiC,QAAgD;GACzF,IAAI,CAAC,UAAU;IAGb,KAAKA,SAAS;IACd,KAAKC,gBAAgB;IACrB;GACF;GAIA,IAAI,KAAKA,kBAAkB,SAAS,MAAM;GAC1C,KAAKA,gBAAgB,SAAS;GAI9B,MAAM,cAAc,2BAA2B,MAAM;GACrD,IAAI,aACF,QAAQ,MAAM,KAAKC,gBAAgB,oCAAoC,GAAG,EAAE,YAAY,OAAO,CAAC;GAGlG,KAAKF,SAAS;IACZ,MAAM,cAAc,oCAAoC,SAAS;IACjE,SAAS,SAAS,WAAW;IAC7B,GAAI,SAAS,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,SAAS,KAAK;GAC/D;GACA,KAAK,gBAAgB,IAAI,MAAM,OAAO,CAAC;EACzC;;;;;;;EAQA,IAAI,SAAkE;GACpE,OAAO,KAAKN;EACd;EAMA,OAAO,cAAsC;GAC3C,MAAM,SAAS,YAAY;GAC3B,KAAKI,SAAS,QAAQ,aAAa,IAAI,YAAY;EACrD;EAEA,SAAe;GACb,KAAKK,mBAAmB;GACxB,KAAKL,SAAS,QAAQ,aAAa,IAAI,KAAA,CAAS;GAChD,MAAM,SAAS;EACjB;EAEA,UAAgB;GACd,KAAKK,mBAAmB;GACxB,KAAKN,eAAe;GACpB,KAAKH,QAAQ,QAAQ;EACvB;;EAOA,IAAI,UAA6C;GAC/C,OAAO,KAAKU;EACd;EAEA,IAAI,QAAQ,OAA0C;GACpD,KAAKA,WAAW;GAChB,IAAI,OACF,KAAKN,SAAS,MAAM,QAAQ,IAAI,KAAK;EAEzC;EAYA,IAAI,wBAAiC;GACnC,OAAO,KAAKO;EACd;EAEA,IAAI,sBAAsB,OAAgB;GACxC,KAAKA,yBAAyB;GAC9B,KAAKP,SAAS,MAAM,sBAAsB,IAAI,KAAK;EACrD;EAYA,IAAI,MAAc;GAChB,OAAO,KAAKA,SAAS,MAAM,aAAa,IAAI,CAAC,EAAE,OAAO;EACxD;EAEA,IAAI,IAAI,OAAe;GAErB,IAAI,UAAU,KAAK,KAAK;GAExB,KAAKK,mBAAmB;GACxB,KAAKL,SAAS,MAAM,aAAa,IAAI,QAAQ,EAAE,KAAK,MAAM,IAAI,KAAA,CAAS;EACzE;EAMA,OAAsB;GACpB,MAAM,eAAe,KAAKA,SAAS,QAAQ,aAAa,IAAI;GAC5D,IAAI,CAAC,cACH,OAAO,QAAQ,uBAAO,IAAI,MAAM,iDAAiD,CAAC;GAGpF,KAAKA,SAAS,MAAM,cAAc,IAAI,IAAI;GAE1C,OAAO,aAAa,KAAK,CAAC,CAAC,OAAO,QAAiB;IACjD,IAAI,KAAK,KACP,OAAO,IAAI,SAAe,SAAS,WAAW;KAC5C,MAAM,iBAAiB;MACrB,KAAKQ,qBAAqB;MAC1B,aAAa,KAAK,CAAC,CAAC,KAAK,SAAS,MAAM;KAC1C;KACA,KAAKA,qBAAqB;KAC1B,aAAa,iBAAiB,aAAa,UAAU,EAAE,MAAM,KAAK,CAAC;IACrE,CAAC;IAEH,MAAM;GACR,CAAC;EACH;;EAOA,gBAAgB,SAAyB;GACvC,OAAO,+BAA+B,SAAS,IAAI;EACrD;EAEA,gBAAyE;GACvE,OAAO,qBAAqB;IAC1B,GAAG,KAAKX;IACR,iBAAiB,YAAY;KAC3B,KAAKG,WAAW;IAClB;GACF,CAAC;EACH;EAEA,qBAA2B;GACzB,IAAI,CAAC,KAAKQ,oBAAoB;GAE9B,KAD0BR,SAAS,QAAQ,aAAa,IAC7C,CAAC,EAAE,oBAAoB,aAAa,KAAKQ,kBAAkB;GACtE,KAAKA,qBAAqB;EAC5B;CACF;CAIA,OAAO;AAGT;;AAGA,IAAa,uBAAb,cAA0C,mBAAmB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { HlsAudioMediaMixin } from "./adapter.js";
|
|
2
|
+
import { HTMLAudioElementHost } from "@videojs/media/dom/audio-host";
|
|
3
|
+
//#region src/playback/adapters/hls-audio/media.ts
|
|
4
|
+
const HlsAudioMediaBase = HlsAudioMediaMixin(HTMLAudioElementHost);
|
|
5
|
+
var HlsAudioMedia = class extends HlsAudioMediaBase {};
|
|
6
|
+
//#endregion
|
|
7
|
+
export { HlsAudioMedia };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=media.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media.js","names":[],"sources":["../../../../../src/playback/adapters/hls-audio/media.ts"],"sourcesContent":["import { HTMLAudioElementHost } from '@videojs/media/dom/audio-host';\nimport { HlsAudioMediaMixin } from './adapter';\n\nconst HlsAudioMediaBase = HlsAudioMediaMixin(HTMLAudioElementHost);\n\nexport class HlsAudioMedia extends HlsAudioMediaBase {}\n"],"mappings":";;;AAGA,MAAM,oBAAoB,mBAAmB,oBAAoB;AAEjE,IAAa,gBAAb,cAAmC,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { effect } from "../../../core/signals/effect.js";
|
|
2
|
+
import { SVTA_NO_SUPPORTED_VIDEO_TRACK, SVTA_UNSUPPORTED_DRM_SYSTEM, SVTA_UNSUPPORTED_PLAYBACK_FEATURE, SVTA_UNSUPPORTED_VIDEO_FORMAT } from "../../../media/errors.js";
|
|
3
|
+
import { createBackgroundVideoEngine } from "../../engines/hls/engine-background-video.js";
|
|
4
|
+
import { UNPLAYABLE_SOURCE_MESSAGE } from "../../primitives/error-messages.js";
|
|
5
|
+
import { firstFatal, hasUnsupportedFeatureCause } from "../hls-video/error-surface.js";
|
|
6
|
+
//#region src/playback/adapters/hls-background-video/adapter.ts
|
|
7
|
+
const hlsBackgroundVideoMediaDefaultProps = { src: "" };
|
|
8
|
+
/**
|
|
9
|
+
* Which reported conditions this composition treats as **fatal** — the ones that
|
|
10
|
+
* reach `error` and fire `'error'`. Severity isn't part of an SVTA code
|
|
11
|
+
* (§Approach: "impact varies with player implementation"), so it's decided at
|
|
12
|
+
* this boundary rather than by the reporter.
|
|
13
|
+
*
|
|
14
|
+
* **Causes are fatal here, unlike on the other two adapters.** There, a cause is
|
|
15
|
+
* context — one unplayable rendition doesn't fail a source whose others still
|
|
16
|
+
* play, and a verdict follows if the type empties. In the pinned variant a cause
|
|
17
|
+
* *is* the verdict: only the pinned rendition's playlist is ever resolved, so a
|
|
18
|
+
* cause can only be about the pick itself, and dropping that pick is final —
|
|
19
|
+
* nothing here re-picks (that is what `switchVideoTrack` exists for, and this
|
|
20
|
+
* engine doesn't compose it). Measured on Chromium: an MPEG-TS source reports
|
|
21
|
+
* 1004 and an encrypted one 4008, each with no verdict behind it, and the element
|
|
22
|
+
* then sits at `readyState 0` with `error` null forever.
|
|
23
|
+
*
|
|
24
|
+
* The verdict is still listed, for the shapes that report nothing else: no video
|
|
25
|
+
* renditions at all, or a ladder pruned before anything resolves — both of which
|
|
26
|
+
* `reportAbsentTrackType` covers from the tail of the constraint chain.
|
|
27
|
+
*
|
|
28
|
+
* First-fatal-wins then surfaces the cause rather than the verdict when both are
|
|
29
|
+
* present, which is the more specific of the two.
|
|
30
|
+
*/
|
|
31
|
+
const FATAL_SVTA_CODES = /* @__PURE__ */ new Set([
|
|
32
|
+
SVTA_NO_SUPPORTED_VIDEO_TRACK,
|
|
33
|
+
SVTA_UNSUPPORTED_VIDEO_FORMAT,
|
|
34
|
+
SVTA_UNSUPPORTED_DRM_SYSTEM
|
|
35
|
+
]);
|
|
36
|
+
/**
|
|
37
|
+
* Mixin that adds the background-video SPF playback engine to any base class,
|
|
38
|
+
* for an HLS URL.
|
|
39
|
+
*
|
|
40
|
+
* `src` is the whole input surface, and `error` is the one output: nothing about
|
|
41
|
+
* an unplayable source reaches the media element on its own here — an unsupported
|
|
42
|
+
* container, encryption with no EME, and an undecodable codec all leave
|
|
43
|
+
* `HTMLMediaElement.error` null with the element stalled at `readyState 0`
|
|
44
|
+
* (measured on Chromium and WebKit) — so a consumer that watched only the
|
|
45
|
+
* `<video>` would see a source that never appears and never says why. The engine
|
|
46
|
+
* reports each condition onto `engine.state.errors` and logs it; this adapter
|
|
47
|
+
* promotes the first fatal one, mapping it the same way the video and audio Medias
|
|
48
|
+
* map theirs. See `internal/design/spf/features/errors.md`.
|
|
49
|
+
*
|
|
50
|
+
* Selection pins the largest rendition that *fits the screen*, and holds it for
|
|
51
|
+
* the session. The manifest is still the better place to narrow further: a
|
|
52
|
+
* delivery param — `?max_resolution=720p` on a Mux stream URL, for one — keeps
|
|
53
|
+
* the renditions it excludes out of the manifest entirely, rather than
|
|
54
|
+
* fetched-then-unpicked.
|
|
55
|
+
*
|
|
56
|
+
* The pin is given up, never moved, if the pick turns out to be unplayable: the
|
|
57
|
+
* container is only known once a media playlist resolves, which is after the pick
|
|
58
|
+
* is made, so the selection clears rather than quietly appending bytes nothing can
|
|
59
|
+
* decode.
|
|
60
|
+
*
|
|
61
|
+
* `@videojs/spf/mux-background-video` is this same Media under a Mux-flavored
|
|
62
|
+
* name — an alias, not a variant. Nothing about the surface changes with the
|
|
63
|
+
* import path.
|
|
64
|
+
*
|
|
65
|
+
* Everything else the use case fixes rather than exposes: video-only, looping,
|
|
66
|
+
* muted, autoplaying, loading as soon as there is a source. `attach` writes that
|
|
67
|
+
* onto the element and nothing here declares `loop` / `muted` / `autoplay` /
|
|
68
|
+
* `preload` of its own — a host-bound Media inherits all four from the host
|
|
69
|
+
* already, and shadowing them with fixed values would only make reads describe
|
|
70
|
+
* an intention rather than what the element is doing.
|
|
71
|
+
*
|
|
72
|
+
* A new src re-resolves the presentation, tearing down the state, SourceBuffers,
|
|
73
|
+
* and in-flight requests the previous one built before the next begins. The
|
|
74
|
+
* engine instance and the attached media element are both kept, so neither has to
|
|
75
|
+
* be rewired.
|
|
76
|
+
*
|
|
77
|
+
* @fires error - Fired when a fatal condition is reported. Read `error` for it.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* class HlsBackgroundVideoMedia extends HlsBackgroundVideoMediaMixin(BackgroundVideoHost) {}
|
|
81
|
+
*
|
|
82
|
+
* const media = new HlsBackgroundVideoMedia();
|
|
83
|
+
* media.attach(document.querySelector('video'));
|
|
84
|
+
* media.src = 'https://stream.mux.com/PLAYBACK_ID.m3u8?max_resolution=720p';
|
|
85
|
+
* media.play();
|
|
86
|
+
*/
|
|
87
|
+
function HlsBackgroundVideoMediaMixin(BaseClass) {
|
|
88
|
+
class HlsBackgroundVideoMediaImpl extends BaseClass {
|
|
89
|
+
#engine;
|
|
90
|
+
#config;
|
|
91
|
+
#signals;
|
|
92
|
+
#error = null;
|
|
93
|
+
/**
|
|
94
|
+
* The *reported* condition currently surfaced, which is what the re-fire latch
|
|
95
|
+
* keys on. Not `#error.code`: that's the code this adapter chose to surface,
|
|
96
|
+
* and the substitution below can make the two differ.
|
|
97
|
+
*/
|
|
98
|
+
#reportedCode = null;
|
|
99
|
+
#stopErrorSync;
|
|
100
|
+
/** Pending loadstart listener from a deferred play() retry, if any. */
|
|
101
|
+
#loadstartListener = null;
|
|
102
|
+
constructor(...args) {
|
|
103
|
+
super(...args);
|
|
104
|
+
const { config } = args?.[0] ?? {};
|
|
105
|
+
this.#config = config;
|
|
106
|
+
this.#engine = this.#createEngine();
|
|
107
|
+
this.#stopErrorSync = effect(() => {
|
|
108
|
+
const errors = this.#signals.state.errors.get();
|
|
109
|
+
this.#setError(firstFatal(errors, FATAL_SVTA_CODES), errors);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
get engine() {
|
|
113
|
+
return this.#engine;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The current fatal condition, or `null`. Only *fatal* ones appear here — the
|
|
117
|
+
* engine reports non-fatal ones too (they stay in `engine.state.errors`), and
|
|
118
|
+
* promoting them would say playback had failed when it hadn't. Which ones are
|
|
119
|
+
* fatal is wider here than on the video and audio Medias; see
|
|
120
|
+
* {@link FATAL_SVTA_CODES}. Resets per source. Fires `'error'` when set.
|
|
121
|
+
*
|
|
122
|
+
* Mapped the same way theirs are: a sequence holding an
|
|
123
|
+
* unimplemented-capability cause surfaces as
|
|
124
|
+
* {@link SVTA_UNSUPPORTED_PLAYBACK_FEATURE} (99001) with the specifics logged,
|
|
125
|
+
* because "this player can't play this source" is what a consumer can act on,
|
|
126
|
+
* where a raw container or DRM code only says what to go and look up.
|
|
127
|
+
*/
|
|
128
|
+
get error() {
|
|
129
|
+
return this.#error;
|
|
130
|
+
}
|
|
131
|
+
#setError(reported, errors) {
|
|
132
|
+
if (!reported) {
|
|
133
|
+
this.#error = null;
|
|
134
|
+
this.#reportedCode = null;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (this.#reportedCode === reported.code) return;
|
|
138
|
+
this.#reportedCode = reported.code;
|
|
139
|
+
console.error(UNPLAYABLE_SOURCE_MESSAGE, { conditions: errors });
|
|
140
|
+
this.#error = {
|
|
141
|
+
code: hasUnsupportedFeatureCause(errors) ? SVTA_UNSUPPORTED_PLAYBACK_FEATURE : reported.code,
|
|
142
|
+
message: reported.message ?? "",
|
|
143
|
+
...reported.data === void 0 ? {} : { data: reported.data }
|
|
144
|
+
};
|
|
145
|
+
this.dispatchEvent?.(new Event("error"));
|
|
146
|
+
}
|
|
147
|
+
attach(mediaElement) {
|
|
148
|
+
super.attach?.(mediaElement);
|
|
149
|
+
mediaElement.loop = true;
|
|
150
|
+
mediaElement.muted = true;
|
|
151
|
+
mediaElement.autoplay = true;
|
|
152
|
+
mediaElement.preload = "auto";
|
|
153
|
+
this.#signals.context.mediaElement.set(mediaElement);
|
|
154
|
+
}
|
|
155
|
+
detach() {
|
|
156
|
+
this.#cancelPendingPlay();
|
|
157
|
+
this.#signals.context.mediaElement.set(void 0);
|
|
158
|
+
super.detach?.();
|
|
159
|
+
}
|
|
160
|
+
destroy() {
|
|
161
|
+
this.#cancelPendingPlay();
|
|
162
|
+
this.#stopErrorSync();
|
|
163
|
+
this.#engine.destroy();
|
|
164
|
+
}
|
|
165
|
+
get src() {
|
|
166
|
+
return this.#signals.state.presentation.get()?.url ?? "";
|
|
167
|
+
}
|
|
168
|
+
set src(value) {
|
|
169
|
+
if (value === this.src) return;
|
|
170
|
+
this.#cancelPendingPlay();
|
|
171
|
+
this.#signals.state.presentation.set(value ? { url: value } : void 0);
|
|
172
|
+
}
|
|
173
|
+
async play() {
|
|
174
|
+
const mediaElement = this.#signals.context.mediaElement.get();
|
|
175
|
+
if (!mediaElement) return Promise.reject(/* @__PURE__ */ new Error("HlsBackgroundVideoMediaElement: no media element attached"));
|
|
176
|
+
try {
|
|
177
|
+
return await mediaElement.play();
|
|
178
|
+
} catch (err) {
|
|
179
|
+
if (this.src) return new Promise((resolve, reject) => {
|
|
180
|
+
const listener = () => {
|
|
181
|
+
this.#loadstartListener = null;
|
|
182
|
+
mediaElement.play().then(resolve, reject);
|
|
183
|
+
};
|
|
184
|
+
this.#loadstartListener = listener;
|
|
185
|
+
mediaElement.addEventListener("loadstart", listener, { once: true });
|
|
186
|
+
});
|
|
187
|
+
throw err;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
#createEngine() {
|
|
191
|
+
return createBackgroundVideoEngine({
|
|
192
|
+
...this.#config,
|
|
193
|
+
onSignalsReady: (signals) => {
|
|
194
|
+
this.#signals = signals;
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
#cancelPendingPlay() {
|
|
199
|
+
if (!this.#loadstartListener) return;
|
|
200
|
+
this.#signals.context.mediaElement.get()?.removeEventListener("loadstart", this.#loadstartListener);
|
|
201
|
+
this.#loadstartListener = null;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return HlsBackgroundVideoMediaImpl;
|
|
205
|
+
}
|
|
206
|
+
/** Standalone SPF background-video adapter with no base class. */
|
|
207
|
+
var HlsBackgroundVideoMediaElement = class extends HlsBackgroundVideoMediaMixin(class {}) {};
|
|
208
|
+
//#endregion
|
|
209
|
+
export { HlsBackgroundVideoMediaElement, HlsBackgroundVideoMediaMixin, hlsBackgroundVideoMediaDefaultProps };
|
|
210
|
+
|
|
211
|
+
//# sourceMappingURL=adapter.js.map
|