@videojs/spf 10.0.0-beta.9 → 10.0.0-rc.2
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 +89 -0
- package/dist/default/core/actors/create-machine-actor.js.map +1 -0
- package/dist/default/core/actors/create-transition-actor.js +44 -0
- package/dist/default/core/actors/create-transition-actor.js.map +1 -0
- package/dist/default/core/composition/create-composition.js +82 -0
- package/dist/default/core/composition/create-composition.js.map +1 -0
- package/dist/default/core/composition/share-signals.js +34 -0
- package/dist/default/core/composition/share-signals.js.map +1 -0
- package/dist/default/core/machine.js +25 -0
- package/dist/default/core/machine.js.map +1 -0
- package/dist/default/core/reactors/create-machine-reactor.js +84 -0
- package/dist/default/core/reactors/create-machine-reactor.js.map +1 -0
- package/dist/default/core/signals/effect.js +61 -0
- package/dist/default/core/signals/effect.js.map +1 -0
- package/dist/default/core/signals/primitives.js +50 -0
- package/dist/default/core/signals/primitives.js.map +1 -0
- package/dist/default/core/signals/when.js +36 -0
- package/dist/default/core/signals/when.js.map +1 -0
- package/dist/default/core/tasks/delayed-reschedule.js +27 -0
- package/dist/default/core/tasks/delayed-reschedule.js.map +1 -0
- package/dist/default/core/tasks/task.js +298 -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 +10 -0
- package/dist/default/index.js +22 -0
- package/dist/default/index.js.map +1 -0
- package/dist/default/media/abr/quality-selection.js +17 -0
- package/dist/default/media/abr/quality-selection.js.map +1 -0
- package/dist/default/media/buffer/back-buffer.js +42 -0
- package/dist/default/media/buffer/back-buffer.js.map +1 -0
- package/dist/default/media/buffer/forward-buffer.js +110 -0
- package/dist/default/media/buffer/forward-buffer.js.map +1 -0
- package/dist/default/media/dom/capabilities.js +61 -0
- package/dist/default/media/dom/capabilities.js.map +1 -0
- package/dist/default/media/dom/mse/append-segment.js +58 -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 +87 -0
- package/dist/default/media/dom/mse/duration.js.map +1 -0
- package/dist/default/media/dom/mse/end-of-stream.js +17 -0
- package/dist/default/media/dom/mse/end-of-stream.js.map +1 -0
- package/dist/default/media/dom/mse/mediasource-setup.js +227 -0
- package/dist/default/media/dom/mse/mediasource-setup.js.map +1 -0
- package/dist/default/media/dom/screen.js +95 -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 +61 -0
- package/dist/default/media/dom/text/text-track-slots.js.map +1 -0
- package/dist/default/media/errors.js +60 -0
- package/dist/default/media/errors.js.map +1 -0
- package/dist/default/media/hls/parse-attributes.js +131 -0
- package/dist/default/media/hls/parse-attributes.js.map +1 -0
- package/dist/default/media/hls/parse-media-playlist.js +253 -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 +63 -0
- package/dist/default/media/hls/reload-policy.js.map +1 -0
- package/dist/default/media/hls/resolve-url.js +9 -0
- package/dist/default/media/hls/resolve-url.js.map +1 -0
- package/dist/default/media/live-window.js +32 -0
- package/dist/default/media/live-window.js.map +1 -0
- package/dist/default/media/media-tracks/media-tracks.js +96 -0
- package/dist/default/media/media-tracks/media-tracks.js.map +1 -0
- package/dist/default/media/mp4/box.js +57 -0
- package/dist/default/media/mp4/box.js.map +1 -0
- package/dist/default/media/mp4/timestamp-origin.js +95 -0
- package/dist/default/media/mp4/timestamp-origin.js.map +1 -0
- package/dist/default/media/primitives/resolution.js +26 -0
- package/dist/default/media/primitives/resolution.js.map +1 -0
- package/dist/default/media/primitives/select-tracks.js +97 -0
- package/dist/default/media/primitives/select-tracks.js.map +1 -0
- package/dist/default/media/text/parse-vtt-timestamp-map.js +40 -0
- package/dist/default/media/text/parse-vtt-timestamp-map.js.map +1 -0
- package/dist/default/media/text/resolve-vtt-metadata.js +22 -0
- package/dist/default/media/text/resolve-vtt-metadata.js.map +1 -0
- package/dist/default/media/types/index.js +42 -0
- package/dist/default/media/types/index.js.map +1 -0
- package/dist/default/media/utils/cdn.js +50 -0
- package/dist/default/media/utils/cdn.js.map +1 -0
- package/dist/default/media/utils/preload.js +21 -0
- package/dist/default/media/utils/preload.js.map +1 -0
- package/dist/default/media/utils/track-selection.js +43 -0
- package/dist/default/media/utils/track-selection.js.map +1 -0
- package/dist/default/media/utils/tracks.js +146 -0
- package/dist/default/media/utils/tracks.js.map +1 -0
- package/dist/default/media-tracks.js +2 -0
- package/dist/default/network/bandwidth-estimator.js +95 -0
- package/dist/default/network/bandwidth-estimator.js.map +1 -0
- package/dist/default/network/chunked-stream-iterable.js +47 -0
- package/dist/default/network/chunked-stream-iterable.js.map +1 -0
- package/dist/default/network/ewma.js +68 -0
- package/dist/default/network/ewma.js.map +1 -0
- package/dist/default/network/fetch.js +108 -0
- package/dist/default/network/fetch.js.map +1 -0
- package/dist/default/playback/actors/dom/segment-loader.js +233 -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 +138 -0
- package/dist/default/playback/actors/text-track-segment-loader.js.map +1 -0
- package/dist/default/playback/adapters/hls-audio/adapter.js +8 -0
- package/dist/default/playback/adapters/hls-audio/adapter.js.map +1 -0
- package/dist/default/playback/adapters/hls-audio/mixin.js +178 -0
- package/dist/default/playback/adapters/hls-audio/mixin.js.map +1 -0
- package/dist/default/playback/adapters/hls-background-video/adapter.js +17 -0
- package/dist/default/playback/adapters/hls-background-video/adapter.js.map +1 -0
- package/dist/default/playback/adapters/hls-background-video/host.js +56 -0
- package/dist/default/playback/adapters/hls-background-video/host.js.map +1 -0
- package/dist/default/playback/adapters/hls-background-video/mixin.js +191 -0
- package/dist/default/playback/adapters/hls-background-video/mixin.js.map +1 -0
- package/dist/default/playback/adapters/hls-video/adapter.js +11 -0
- package/dist/default/playback/adapters/hls-video/adapter.js.map +1 -0
- package/dist/default/playback/adapters/hls-video/error-surface.js +46 -0
- package/dist/default/playback/adapters/hls-video/error-surface.js.map +1 -0
- package/dist/default/playback/adapters/hls-video/media-tracks.js +125 -0
- package/dist/default/playback/adapters/hls-video/media-tracks.js.map +1 -0
- package/dist/default/playback/adapters/hls-video/mixin.js +299 -0
- package/dist/default/playback/adapters/hls-video/mixin.js.map +1 -0
- package/dist/default/playback/behaviors/calculate-presentation-duration.js +33 -0
- package/dist/default/playback/behaviors/calculate-presentation-duration.js.map +1 -0
- package/dist/default/playback/behaviors/collect-errors.js +98 -0
- package/dist/default/playback/behaviors/collect-errors.js.map +1 -0
- package/dist/default/playback/behaviors/derive-cdn-priority.js +61 -0
- package/dist/default/playback/behaviors/derive-cdn-priority.js.map +1 -0
- package/dist/default/playback/behaviors/dom/airplay.js +188 -0
- package/dist/default/playback/behaviors/dom/airplay.js.map +1 -0
- package/dist/default/playback/behaviors/dom/apply-start-position.js +81 -0
- package/dist/default/playback/behaviors/dom/apply-start-position.js.map +1 -0
- package/dist/default/playback/behaviors/dom/end-of-stream.js +97 -0
- package/dist/default/playback/behaviors/dom/end-of-stream.js.map +1 -0
- package/dist/default/playback/behaviors/dom/load-segments.js +169 -0
- package/dist/default/playback/behaviors/dom/load-segments.js.map +1 -0
- package/dist/default/playback/behaviors/dom/recover-end-stall.js +72 -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 +113 -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 +181 -0
- package/dist/default/playback/behaviors/dom/setup-buffer-actors.js.map +1 -0
- package/dist/default/playback/behaviors/dom/setup-mediasource.js +100 -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 +25 -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 +109 -0
- package/dist/default/playback/behaviors/dom/sync-text-tracks.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-current-time.js +50 -0
- package/dist/default/playback/behaviors/dom/track-current-time.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-load-triggers.js +86 -0
- package/dist/default/playback/behaviors/dom/track-load-triggers.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-playback-rate.js +35 -0
- package/dist/default/playback/behaviors/dom/track-playback-rate.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-player-resolution.js +53 -0
- package/dist/default/playback/behaviors/dom/track-player-resolution.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-screen-resolution.js +28 -0
- package/dist/default/playback/behaviors/dom/track-screen-resolution.js.map +1 -0
- package/dist/default/playback/behaviors/dom/update-mediasource-duration.js +98 -0
- package/dist/default/playback/behaviors/dom/update-mediasource-duration.js.map +1 -0
- package/dist/default/playback/behaviors/establish-start-media-time.js +187 -0
- package/dist/default/playback/behaviors/establish-start-media-time.js.map +1 -0
- package/dist/default/playback/behaviors/resolve-presentation.js +76 -0
- package/dist/default/playback/behaviors/resolve-presentation.js.map +1 -0
- package/dist/default/playback/behaviors/resolve-track.js +134 -0
- package/dist/default/playback/behaviors/resolve-track.js.map +1 -0
- package/dist/default/playback/behaviors/select-tracks.js +189 -0
- package/dist/default/playback/behaviors/select-tracks.js.map +1 -0
- package/dist/default/playback/behaviors/setup-failover-monitor.js +61 -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 +407 -0
- package/dist/default/playback/behaviors/track-switching.js.map +1 -0
- package/dist/default/playback/engines/hls/engine-audio-only.js +94 -0
- package/dist/default/playback/engines/hls/engine-audio-only.js.map +1 -0
- package/dist/default/playback/engines/hls/engine-background-video.js +87 -0
- package/dist/default/playback/engines/hls/engine-background-video.js.map +1 -0
- package/dist/default/playback/engines/hls/engine.js +144 -0
- package/dist/default/playback/engines/hls/engine.js.map +1 -0
- package/dist/default/playback/primitives/error-messages.js +42 -0
- package/dist/default/playback/primitives/error-messages.js.map +1 -0
- package/dist/default/playback/primitives/failover-fetch.js +37 -0
- package/dist/default/playback/primitives/failover-fetch.js.map +1 -0
- package/dist/default/playback/primitives/head-peek.js +41 -0
- package/dist/default/playback/primitives/head-peek.js.map +1 -0
- package/dist/default/playback/primitives/live-window.js +63 -0
- package/dist/default/playback/primitives/live-window.js.map +1 -0
- package/dist/default/playback/primitives/relocation-pipelines.js +191 -0
- package/dist/default/playback/primitives/relocation-pipelines.js.map +1 -0
- package/dist/default/playback/primitives/report-track-conditions.js +74 -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 +115 -0
- package/dist/default/playback/primitives/selection-rules.js.map +1 -0
- package/dist/default/playback/primitives/text-segment-load-pipeline.js +36 -0
- package/dist/default/playback/primitives/text-segment-load-pipeline.js.map +1 -0
- package/dist/default/playback/primitives/track-types.js +53 -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 +119 -0
- package/dist/dev/core/actors/create-machine-actor.d.ts.map +1 -0
- package/dist/dev/core/actors/create-machine-actor.js +89 -0
- package/dist/dev/core/actors/create-machine-actor.js.map +1 -0
- package/dist/dev/core/actors/create-transition-actor.d.ts +37 -0
- package/dist/dev/core/actors/create-transition-actor.d.ts.map +1 -0
- package/dist/dev/core/actors/create-transition-actor.js +44 -0
- package/dist/dev/core/actors/create-transition-actor.js.map +1 -0
- package/dist/dev/core/composition/create-composition.d.ts +241 -0
- package/dist/dev/core/composition/create-composition.d.ts.map +1 -0
- package/dist/dev/core/composition/create-composition.js +82 -0
- package/dist/dev/core/composition/create-composition.js.map +1 -0
- package/dist/dev/core/composition/share-signals.d.ts +39 -0
- package/dist/dev/core/composition/share-signals.d.ts.map +1 -0
- package/dist/dev/core/composition/share-signals.js +34 -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 +25 -0
- package/dist/dev/core/machine.js.map +1 -0
- package/dist/dev/core/reactors/create-machine-reactor.d.ts +87 -0
- package/dist/dev/core/reactors/create-machine-reactor.d.ts.map +1 -0
- package/dist/dev/core/reactors/create-machine-reactor.js +84 -0
- package/dist/dev/core/reactors/create-machine-reactor.js.map +1 -0
- package/dist/dev/core/signals/effect.d.ts +14 -0
- package/dist/dev/core/signals/effect.d.ts.map +1 -0
- package/dist/dev/core/signals/effect.js +61 -0
- package/dist/dev/core/signals/effect.js.map +1 -0
- package/dist/dev/core/signals/primitives.d.ts +44 -0
- package/dist/dev/core/signals/primitives.d.ts.map +1 -0
- package/dist/dev/core/signals/primitives.js +50 -0
- package/dist/dev/core/signals/primitives.js.map +1 -0
- package/dist/dev/core/signals/when.js +36 -0
- package/dist/dev/core/signals/when.js.map +1 -0
- package/dist/dev/core/tasks/delayed-reschedule.js +27 -0
- package/dist/dev/core/tasks/delayed-reschedule.js.map +1 -0
- package/dist/dev/core/tasks/task.d.ts +144 -0
- package/dist/dev/core/tasks/task.d.ts.map +1 -0
- package/dist/dev/core/tasks/task.js +298 -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 +11 -0
- package/dist/dev/hls.js +10 -0
- package/dist/dev/index.d.ts +23 -0
- package/dist/dev/index.d.ts.map +1 -0
- package/dist/dev/index.js +22 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/dev/media/abr/quality-selection.d.ts +19 -0
- package/dist/dev/media/abr/quality-selection.d.ts.map +1 -0
- package/dist/dev/media/abr/quality-selection.js +17 -0
- package/dist/dev/media/abr/quality-selection.js.map +1 -0
- package/dist/dev/media/buffer/back-buffer.d.ts +9 -0
- package/dist/dev/media/buffer/back-buffer.d.ts.map +1 -0
- package/dist/dev/media/buffer/back-buffer.js +42 -0
- package/dist/dev/media/buffer/back-buffer.js.map +1 -0
- package/dist/dev/media/buffer/forward-buffer.d.ts +9 -0
- package/dist/dev/media/buffer/forward-buffer.d.ts.map +1 -0
- package/dist/dev/media/buffer/forward-buffer.js +110 -0
- package/dist/dev/media/buffer/forward-buffer.js.map +1 -0
- package/dist/dev/media/dom/capabilities.js +61 -0
- package/dist/dev/media/dom/capabilities.js.map +1 -0
- package/dist/dev/media/dom/mse/append-segment.d.ts +16 -0
- package/dist/dev/media/dom/mse/append-segment.d.ts.map +1 -0
- package/dist/dev/media/dom/mse/append-segment.js +58 -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 +87 -0
- package/dist/dev/media/dom/mse/duration.js.map +1 -0
- package/dist/dev/media/dom/mse/end-of-stream.js +17 -0
- package/dist/dev/media/dom/mse/end-of-stream.js.map +1 -0
- package/dist/dev/media/dom/mse/mediasource-setup.js +227 -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 +95 -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 +24 -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 +61 -0
- package/dist/dev/media/dom/text/text-track-slots.js.map +1 -0
- package/dist/dev/media/errors.d.ts +68 -0
- package/dist/dev/media/errors.d.ts.map +1 -0
- package/dist/dev/media/errors.js +60 -0
- package/dist/dev/media/errors.js.map +1 -0
- package/dist/dev/media/hls/parse-attributes.js +131 -0
- package/dist/dev/media/hls/parse-attributes.js.map +1 -0
- package/dist/dev/media/hls/parse-media-playlist.js +253 -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 +63 -0
- package/dist/dev/media/hls/reload-policy.js.map +1 -0
- package/dist/dev/media/hls/resolve-url.js +9 -0
- package/dist/dev/media/hls/resolve-url.js.map +1 -0
- package/dist/dev/media/live-window.js +32 -0
- package/dist/dev/media/live-window.js.map +1 -0
- package/dist/dev/media/media-tracks/media-tracks.d.ts +46 -0
- package/dist/dev/media/media-tracks/media-tracks.d.ts.map +1 -0
- package/dist/dev/media/media-tracks/media-tracks.js +96 -0
- package/dist/dev/media/media-tracks/media-tracks.js.map +1 -0
- package/dist/dev/media/mp4/box.js +57 -0
- package/dist/dev/media/mp4/box.js.map +1 -0
- package/dist/dev/media/mp4/timestamp-origin.js +95 -0
- package/dist/dev/media/mp4/timestamp-origin.js.map +1 -0
- package/dist/dev/media/primitives/resolution.d.ts +22 -0
- package/dist/dev/media/primitives/resolution.d.ts.map +1 -0
- package/dist/dev/media/primitives/resolution.js +26 -0
- package/dist/dev/media/primitives/resolution.js.map +1 -0
- package/dist/dev/media/primitives/select-tracks.js +97 -0
- package/dist/dev/media/primitives/select-tracks.js.map +1 -0
- package/dist/dev/media/text/parse-vtt-timestamp-map.js +40 -0
- package/dist/dev/media/text/parse-vtt-timestamp-map.js.map +1 -0
- package/dist/dev/media/text/resolve-vtt-metadata.js +22 -0
- package/dist/dev/media/text/resolve-vtt-metadata.js.map +1 -0
- package/dist/dev/media/types/index.d.ts +306 -0
- package/dist/dev/media/types/index.d.ts.map +1 -0
- package/dist/dev/media/types/index.js +42 -0
- package/dist/dev/media/types/index.js.map +1 -0
- package/dist/dev/media/utils/cdn.d.ts +11 -0
- package/dist/dev/media/utils/cdn.d.ts.map +1 -0
- package/dist/dev/media/utils/cdn.js +50 -0
- package/dist/dev/media/utils/cdn.js.map +1 -0
- package/dist/dev/media/utils/preload.js +21 -0
- package/dist/dev/media/utils/preload.js.map +1 -0
- package/dist/dev/media/utils/track-selection.js +43 -0
- package/dist/dev/media/utils/track-selection.js.map +1 -0
- package/dist/dev/media/utils/tracks.js +146 -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/network/bandwidth-estimator.d.ts +48 -0
- package/dist/dev/network/bandwidth-estimator.d.ts.map +1 -0
- package/dist/dev/network/bandwidth-estimator.js +95 -0
- package/dist/dev/network/bandwidth-estimator.js.map +1 -0
- package/dist/dev/network/chunked-stream-iterable.js +47 -0
- package/dist/dev/network/chunked-stream-iterable.js.map +1 -0
- package/dist/dev/network/ewma.js +68 -0
- package/dist/dev/network/ewma.js.map +1 -0
- package/dist/dev/network/fetch.js +108 -0
- package/dist/dev/network/fetch.js.map +1 -0
- package/dist/dev/playback/actors/dom/segment-loader.d.ts +44 -0
- package/dist/dev/playback/actors/dom/segment-loader.d.ts.map +1 -0
- package/dist/dev/playback/actors/dom/segment-loader.js +233 -0
- package/dist/dev/playback/actors/dom/segment-loader.js.map +1 -0
- package/dist/dev/playback/actors/dom/source-buffer.d.ts +45 -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 +48 -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 +138 -0
- package/dist/dev/playback/actors/text-track-segment-loader.js.map +1 -0
- package/dist/dev/playback/actors/text-tracks.d.ts +30 -0
- package/dist/dev/playback/actors/text-tracks.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-audio/adapter.d.ts +11 -0
- package/dist/dev/playback/adapters/hls-audio/adapter.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-audio/adapter.js +8 -0
- package/dist/dev/playback/adapters/hls-audio/adapter.js.map +1 -0
- package/dist/dev/playback/adapters/hls-audio/mixin.d.ts +52 -0
- package/dist/dev/playback/adapters/hls-audio/mixin.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-audio/mixin.js +178 -0
- package/dist/dev/playback/adapters/hls-audio/mixin.js.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/adapter.d.ts +19 -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 +17 -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 +34 -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 +56 -0
- package/dist/dev/playback/adapters/hls-background-video/host.js.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/mixin.d.ts +69 -0
- package/dist/dev/playback/adapters/hls-background-video/mixin.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-background-video/mixin.js +191 -0
- package/dist/dev/playback/adapters/hls-background-video/mixin.js.map +1 -0
- package/dist/dev/playback/adapters/hls-video/adapter.d.ts +11 -0
- package/dist/dev/playback/adapters/hls-video/adapter.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-video/adapter.js +11 -0
- package/dist/dev/playback/adapters/hls-video/adapter.js.map +1 -0
- package/dist/dev/playback/adapters/hls-video/error-surface.d.ts +17 -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 +46 -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 +21 -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 +125 -0
- package/dist/dev/playback/adapters/hls-video/media-tracks.js.map +1 -0
- package/dist/dev/playback/adapters/hls-video/mixin.d.ts +62 -0
- package/dist/dev/playback/adapters/hls-video/mixin.d.ts.map +1 -0
- package/dist/dev/playback/adapters/hls-video/mixin.js +299 -0
- package/dist/dev/playback/adapters/hls-video/mixin.js.map +1 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.d.ts +23 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.js +33 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.js.map +1 -0
- package/dist/dev/playback/behaviors/collect-errors.d.ts +2 -0
- package/dist/dev/playback/behaviors/collect-errors.js +98 -0
- package/dist/dev/playback/behaviors/collect-errors.js.map +1 -0
- package/dist/dev/playback/behaviors/derive-cdn-priority.js +61 -0
- package/dist/dev/playback/behaviors/derive-cdn-priority.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/airplay.js +188 -0
- package/dist/dev/playback/behaviors/dom/airplay.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/apply-start-position.js +81 -0
- package/dist/dev/playback/behaviors/dom/apply-start-position.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/end-of-stream.js +97 -0
- package/dist/dev/playback/behaviors/dom/end-of-stream.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/load-segments.d.ts +69 -0
- package/dist/dev/playback/behaviors/dom/load-segments.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/load-segments.js +169 -0
- package/dist/dev/playback/behaviors/dom/load-segments.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/recover-end-stall.js +72 -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 +113 -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 +181 -0
- package/dist/dev/playback/behaviors/dom/setup-buffer-actors.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/setup-mediasource.js +100 -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 +25 -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 +109 -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 +50 -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 +41 -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 +86 -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 +35 -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 +53 -0
- package/dist/dev/playback/behaviors/dom/track-player-resolution.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-screen-resolution.js +28 -0
- package/dist/dev/playback/behaviors/dom/track-screen-resolution.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/update-mediasource-duration.js +98 -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 +32 -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 +187 -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 +76 -0
- package/dist/dev/playback/behaviors/resolve-presentation.js.map +1 -0
- package/dist/dev/playback/behaviors/resolve-track.js +134 -0
- package/dist/dev/playback/behaviors/resolve-track.js.map +1 -0
- package/dist/dev/playback/behaviors/select-tracks.d.ts +61 -0
- package/dist/dev/playback/behaviors/select-tracks.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/select-tracks.js +189 -0
- package/dist/dev/playback/behaviors/select-tracks.js.map +1 -0
- package/dist/dev/playback/behaviors/setup-failover-monitor.d.ts +11 -0
- package/dist/dev/playback/behaviors/setup-failover-monitor.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/setup-failover-monitor.js +61 -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.d.ts +110 -0
- package/dist/dev/playback/behaviors/track-switching.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/track-switching.js +407 -0
- package/dist/dev/playback/behaviors/track-switching.js.map +1 -0
- package/dist/dev/playback/engines/hls/engine-audio-only.d.ts +160 -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 +94 -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 +131 -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 +87 -0
- package/dist/dev/playback/engines/hls/engine-background-video.js.map +1 -0
- package/dist/dev/playback/engines/hls/engine.d.ts +289 -0
- package/dist/dev/playback/engines/hls/engine.d.ts.map +1 -0
- package/dist/dev/playback/engines/hls/engine.js +144 -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 +42 -0
- package/dist/dev/playback/primitives/error-messages.js.map +1 -0
- package/dist/dev/playback/primitives/failover-fetch.js +37 -0
- package/dist/dev/playback/primitives/failover-fetch.js.map +1 -0
- package/dist/dev/playback/primitives/head-peek.js +41 -0
- package/dist/dev/playback/primitives/head-peek.js.map +1 -0
- package/dist/dev/playback/primitives/live-window.js +63 -0
- package/dist/dev/playback/primitives/live-window.js.map +1 -0
- package/dist/dev/playback/primitives/relocation-pipelines.js +191 -0
- package/dist/dev/playback/primitives/relocation-pipelines.js.map +1 -0
- package/dist/dev/playback/primitives/report-track-conditions.d.ts +8 -0
- package/dist/dev/playback/primitives/report-track-conditions.d.ts.map +1 -0
- package/dist/dev/playback/primitives/report-track-conditions.js +74 -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 +66 -0
- package/dist/dev/playback/primitives/selection-rules.d.ts.map +1 -0
- package/dist/dev/playback/primitives/selection-rules.js +115 -0
- package/dist/dev/playback/primitives/selection-rules.js.map +1 -0
- package/dist/dev/playback/primitives/source-buffer-messages.d.ts +40 -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 +56 -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 +36 -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 +53 -0
- package/dist/dev/playback/primitives/track-types.js.map +1 -0
- package/package.json +60 -41
- package/dist/adapter-25AtMN8s.d.ts +0 -719
- package/dist/adapter-25AtMN8s.d.ts.map +0 -1
- package/dist/adapter-CflgYzjF.js +0 -3556
- package/dist/adapter-CflgYzjF.js.map +0 -1
- package/dist/dom/index.d.ts +0 -221
- 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 @@
|
|
|
1
|
+
{"version":3,"file":"track-playback-rate.js","names":[],"sources":["../../../../../src/playback/behaviors/dom/track-playback-rate.ts"],"sourcesContent":["/**\n * Mirror `mediaElement.playbackRate` into reactive state. On each `ratechange` event, write the new value to\n * `state.playbackRate`. Also syncs immediately when a media element becomes available so consumers don't wait for the\n * first event.\n *\n * When no media element is attached, writes `config.defaultPlaybackRate` (default-default `1`, matching the\n * HTMLMediaElement spec) so consumers always see the rate a freshly attached element would have. Read-only mirror; does\n * not push `state.playbackRate` back to the element.\n */\nimport { listen } from '@videojs/utils/dom';\n\nimport { defineBehavior } from '../../../core/composition/create-composition';\nimport { effect } from '../../../core/signals/effect';\nimport type { ReadonlySignal, Signal } from '../../../core/signals/primitives';\n\nexport interface PlaybackRateState {\n playbackRate?: number;\n}\n\nexport interface PlaybackRateContext {\n mediaElement?: HTMLMediaElement | undefined;\n}\n\nexport interface TrackPlaybackRateConfig {\n /**\n * Value written to `state.playbackRate` when no media element is attached. Defaults to `1` — the HTMLMediaElement\n * spec default.\n */\n defaultPlaybackRate?: number;\n}\n\nfunction trackPlaybackRateSetup({\n state,\n context,\n config,\n}: {\n state: { playbackRate: Signal<PlaybackRateState['playbackRate']> };\n context: { mediaElement: ReadonlySignal<PlaybackRateContext['mediaElement']> };\n config?: TrackPlaybackRateConfig;\n}): () => void {\n const defaultPlaybackRate = config?.defaultPlaybackRate ?? 1;\n\n return effect(() => {\n const mediaElement = context.mediaElement.get();\n\n if (!mediaElement) {\n state.playbackRate.set(defaultPlaybackRate);\n return;\n }\n\n const sync = () => state.playbackRate.set(mediaElement.playbackRate);\n\n sync();\n\n return listen(mediaElement, 'ratechange', sync);\n });\n}\n\nexport const trackPlaybackRate = defineBehavior({\n stateKeys: ['playbackRate'],\n contextKeys: ['mediaElement'],\n setup: trackPlaybackRateSetup,\n});\n"],"mappings":";;;;;;;;;;;;;AA+BA,SAAS,uBAAuB,EAC9B,OACA,SACA,UAKa;CACb,MAAM,sBAAsB,QAAQ,uBAAuB;CAE3D,OAAO,aAAa;EAClB,MAAM,eAAe,QAAQ,aAAa,IAAI;EAE9C,IAAI,CAAC,cAAc;GACjB,MAAM,aAAa,IAAI,mBAAmB;GAC1C;EACF;EAEA,MAAM,aAAa,MAAM,aAAa,IAAI,aAAa,YAAY;EAEnE,KAAK;EAEL,OAAO,OAAO,cAAc,cAAc,IAAI;CAChD,CAAC;AACH;AAEA,MAAa,oBAAoB,eAAe;CAC9C,WAAW,CAAC,cAAc;CAC1B,aAAa,CAAC,cAAc;CAC5B,OAAO;AACT,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { defineBehavior } from "../../../core/composition/create-composition.js";
|
|
2
|
+
import { effect } from "../../../core/signals/effect.js";
|
|
3
|
+
import { scaleResolution } from "../../../media/primitives/resolution.js";
|
|
4
|
+
import { observeElementSize, observeRenderedSize } from "@videojs/utils/dom";
|
|
5
|
+
import { shallowEqual } from "@videojs/utils/object";
|
|
6
|
+
//#region src/playback/behaviors/dom/track-player-resolution.ts
|
|
7
|
+
/**
|
|
8
|
+
* Mirror the player element's rendered pixel dimensions into reactive state, so a rendition cap can narrow candidates
|
|
9
|
+
* to what the element can actually show without reading the DOM at pick time — which would make the picker impure, and
|
|
10
|
+
* would never re-pick when the element resized.
|
|
11
|
+
*
|
|
12
|
+
* The player-element half of the caps in `internal/design/spf/features/rendition-selection-caps.md`, and the tighter
|
|
13
|
+
* half: a small embed on a large display is capped by its own box rather than by the screen behind it
|
|
14
|
+
* (`trackScreenResolution`).
|
|
15
|
+
*
|
|
16
|
+
* Reported as a width and a height in device pixels — the same units, and for the same reason, as `media/dom/screen`'s
|
|
17
|
+
* reading: the cap compares against real track dimensions, and a `"720p"`-style tier only describes a track once you
|
|
18
|
+
* assume its aspect ratio.
|
|
19
|
+
*
|
|
20
|
+
* `undefined` where there is nothing to measure — no element attached, or one that isn't being rendered (detached,
|
|
21
|
+
* `display: none`, not yet laid out) — which is the value the cap reads as "don't cap".
|
|
22
|
+
*/
|
|
23
|
+
function trackPlayerResolutionSetup({ state, context, config = {} }) {
|
|
24
|
+
const { capRenditionToPlayerSize = true, useDevicePixelRatio = true } = config;
|
|
25
|
+
return effect(() => {
|
|
26
|
+
const mediaElement = context.mediaElement.get();
|
|
27
|
+
let current;
|
|
28
|
+
state.playerResolution.set(current);
|
|
29
|
+
if (!capRenditionToPlayerSize || !mediaElement) return;
|
|
30
|
+
const write = (size) => {
|
|
31
|
+
const next = scaleResolution(size, size.scale);
|
|
32
|
+
if (shallowEqual(current, next)) return;
|
|
33
|
+
current = next;
|
|
34
|
+
state.playerResolution.set(next);
|
|
35
|
+
};
|
|
36
|
+
return useDevicePixelRatio ? observeRenderedSize(mediaElement, write) : observeElementSize(mediaElement, write);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Track the player element's rendered resolution in `state.playerResolution`.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const cleanup = trackPlayerResolution.setup({ state, context });
|
|
44
|
+
*/
|
|
45
|
+
const trackPlayerResolution = defineBehavior({
|
|
46
|
+
stateKeys: ["playerResolution"],
|
|
47
|
+
contextKeys: ["mediaElement"],
|
|
48
|
+
setup: trackPlayerResolutionSetup
|
|
49
|
+
});
|
|
50
|
+
//#endregion
|
|
51
|
+
export { trackPlayerResolution };
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=track-player-resolution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"track-player-resolution.js","names":[],"sources":["../../../../../src/playback/behaviors/dom/track-player-resolution.ts"],"sourcesContent":["/**\n * Mirror the player element's rendered pixel dimensions into reactive state, so a rendition cap can narrow candidates\n * to what the element can actually show without reading the DOM at pick time — which would make the picker impure, and\n * would never re-pick when the element resized.\n *\n * The player-element half of the caps in `internal/design/spf/features/rendition-selection-caps.md`, and the tighter\n * half: a small embed on a large display is capped by its own box rather than by the screen behind it\n * (`trackScreenResolution`).\n *\n * Reported as a width and a height in device pixels — the same units, and for the same reason, as `media/dom/screen`'s\n * reading: the cap compares against real track dimensions, and a `\"720p\"`-style tier only describes a track once you\n * assume its aspect ratio.\n *\n * `undefined` where there is nothing to measure — no element attached, or one that isn't being rendered (detached,\n * `display: none`, not yet laid out) — which is the value the cap reads as \"don't cap\".\n */\n\nimport { type ElementSize, observeElementSize, observeRenderedSize } from '@videojs/utils/dom';\nimport { shallowEqual } from '@videojs/utils/object';\n\nimport { defineBehavior } from '../../../core/composition/create-composition';\nimport { effect } from '../../../core/signals/effect';\nimport type { ReadonlySignal, Signal } from '../../../core/signals/primitives';\nimport { type Resolution, scaleResolution } from '../../../media/primitives/resolution';\n\n/** A player element's rendered pixel dimensions. */\nexport type PlayerResolution = Resolution;\n\nexport interface PlayerResolutionState {\n playerResolution?: PlayerResolution;\n}\n\nexport interface PlayerResolutionContext {\n mediaElement?: HTMLMediaElement | undefined;\n}\n\nexport interface TrackPlayerResolutionConfig {\n /**\n * Whether to cap renditions to the player's rendered size at all. `false` measures nothing, which leaves\n * `state.playerResolution` unset and the cap inert. Defaults to `true`.\n *\n * Named for the policy rather than the measurement because it is the public switch for the feature — the same one\n * hls.js spells `capLevelToPlayerSize` and the Mux Video element spells `cap-rendition-to-player-size`.\n */\n capRenditionToPlayerSize?: boolean;\n /**\n * Whether the reading is scaled into device pixels. Defaults to `true` — see\n * `ScreenResolutionOptions.useDevicePixelRatio` in `media/dom/screen.ts`, including its note on page zoom being\n * folded into the ratio outside WebKit.\n */\n useDevicePixelRatio?: boolean;\n}\n\nfunction trackPlayerResolutionSetup({\n state,\n context,\n config = {},\n}: {\n state: { playerResolution: Signal<PlayerResolutionState['playerResolution']> };\n context: { mediaElement: ReadonlySignal<PlayerResolutionContext['mediaElement']> };\n config?: TrackPlayerResolutionConfig;\n}): () => void {\n const { capRenditionToPlayerSize = true, useDevicePixelRatio = true } = config;\n\n return effect(() => {\n const mediaElement = context.mediaElement.get();\n // Clear before (re-)observing so the previous element's measurement can't\n // stand while the new one's first observation is in flight.\n let current: PlayerResolution | undefined;\n\n state.playerResolution.set(current);\n\n if (!capRenditionToPlayerSize || !mediaElement) return;\n\n // Compared rather than written straight through, since the slot holds an\n // object and would otherwise notify on identity alone: a resize that rounds\n // to the same device pixels is not a change worth re-running selection for.\n // Same reason `watchScreenResolution` compares its readings.\n const write = (size: ElementSize & { scale?: number }) => {\n const next = scaleResolution(size, size.scale);\n if (shallowEqual(current, next)) return;\n\n current = next;\n state.playerResolution.set(next);\n };\n\n return useDevicePixelRatio ? observeRenderedSize(mediaElement, write) : observeElementSize(mediaElement, write);\n });\n}\n\n/**\n * Track the player element's rendered resolution in `state.playerResolution`.\n *\n * @example\n * const cleanup = trackPlayerResolution.setup({ state, context });\n */\nexport const trackPlayerResolution = defineBehavior({\n stateKeys: ['playerResolution'],\n contextKeys: ['mediaElement'],\n setup: trackPlayerResolutionSetup,\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAqDA,SAAS,2BAA2B,EAClC,OACA,SACA,SAAS,CAAC,KAKG;CACb,MAAM,EAAE,2BAA2B,MAAM,sBAAsB,SAAS;CAExE,OAAO,aAAa;EAClB,MAAM,eAAe,QAAQ,aAAa,IAAI;EAG9C,IAAI;EAEJ,MAAM,iBAAiB,IAAI,OAAO;EAElC,IAAI,CAAC,4BAA4B,CAAC,cAAc;EAMhD,MAAM,SAAS,SAA2C;GACxD,MAAM,OAAO,gBAAgB,MAAM,KAAK,KAAK;GAC7C,IAAI,aAAa,SAAS,IAAI,GAAG;GAEjC,UAAU;GACV,MAAM,iBAAiB,IAAI,IAAI;EACjC;EAEA,OAAO,sBAAsB,oBAAoB,cAAc,KAAK,IAAI,mBAAmB,cAAc,KAAK;CAChH,CAAC;AACH;;;;;;;AAQA,MAAa,wBAAwB,eAAe;CAClD,WAAW,CAAC,kBAAkB;CAC9B,aAAa,CAAC,cAAc;CAC5B,OAAO;AACT,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { defineBehavior } from "../../../core/composition/create-composition.js";
|
|
2
|
+
import { watchScreenResolution } from "../../../media/dom/screen.js";
|
|
3
|
+
//#region src/playback/behaviors/dom/track-screen-resolution.ts
|
|
4
|
+
/**
|
|
5
|
+
* Mirror the screen's pixel dimensions into reactive state, so a rendition cap can narrow candidates to what the screen
|
|
6
|
+
* can actually show without reading the environment at pick time — which would make the picker impure, and would never
|
|
7
|
+
* re-pick when the screen changed.
|
|
8
|
+
*
|
|
9
|
+
* Populated at setup rather than on the first change: `watchScreenResolution` reports its starting value, so nothing
|
|
10
|
+
* downstream waits on a screen that may never move. `undefined` where there is no screen to read, which is the value a
|
|
11
|
+
* cap reads as "no cap" — see `getScreenResolution` on why that beats a zero.
|
|
12
|
+
*
|
|
13
|
+
* Reads no other slot, and has no source-identity reset: the screen is independent of the presentation, so a new `src`
|
|
14
|
+
* doesn't invalidate the reading.
|
|
15
|
+
*/
|
|
16
|
+
function trackScreenResolutionSetup({ state, config }) {
|
|
17
|
+
const useDevicePixelRatio = config?.useDevicePixelRatio ?? true;
|
|
18
|
+
return watchScreenResolution((resolution) => state.screenResolution.set(resolution), { useDevicePixelRatio });
|
|
19
|
+
}
|
|
20
|
+
const trackScreenResolution = defineBehavior({
|
|
21
|
+
stateKeys: ["screenResolution"],
|
|
22
|
+
contextKeys: [],
|
|
23
|
+
setup: trackScreenResolutionSetup
|
|
24
|
+
});
|
|
25
|
+
//#endregion
|
|
26
|
+
export { trackScreenResolution };
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=track-screen-resolution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"track-screen-resolution.js","names":[],"sources":["../../../../../src/playback/behaviors/dom/track-screen-resolution.ts"],"sourcesContent":["/**\n * Mirror the screen's pixel dimensions into reactive state, so a rendition cap can narrow candidates to what the screen\n * can actually show without reading the environment at pick time — which would make the picker impure, and would never\n * re-pick when the screen changed.\n *\n * Populated at setup rather than on the first change: `watchScreenResolution` reports its starting value, so nothing\n * downstream waits on a screen that may never move. `undefined` where there is no screen to read, which is the value a\n * cap reads as \"no cap\" — see `getScreenResolution` on why that beats a zero.\n *\n * Reads no other slot, and has no source-identity reset: the screen is independent of the presentation, so a new `src`\n * doesn't invalidate the reading.\n */\nimport { defineBehavior } from '../../../core/composition/create-composition';\nimport type { Signal } from '../../../core/signals/primitives';\nimport { type ScreenResolution, watchScreenResolution } from '../../../media/dom/screen';\n\nexport interface ScreenResolutionState {\n screenResolution?: ScreenResolution;\n}\n\nexport interface TrackScreenResolutionConfig {\n /**\n * Whether the reading is scaled into device pixels. Defaults to `true` — see\n * `ScreenResolutionOptions.useDevicePixelRatio`, including its note on page zoom being folded into the ratio outside\n * WebKit.\n */\n useDevicePixelRatio?: boolean;\n}\n\nfunction trackScreenResolutionSetup({\n state,\n config,\n}: {\n state: { screenResolution: Signal<ScreenResolutionState['screenResolution']> };\n config?: TrackScreenResolutionConfig;\n}): () => void {\n const useDevicePixelRatio = config?.useDevicePixelRatio ?? true;\n\n // No `effect` wrapper, unlike its `track*` siblings: they re-subscribe when\n // `context.mediaElement` changes, and this behavior has no reactive dependency\n // to re-run on. The watcher's own teardown is the whole cleanup.\n return watchScreenResolution((resolution) => state.screenResolution.set(resolution), { useDevicePixelRatio });\n}\n\nexport const trackScreenResolution = defineBehavior({\n stateKeys: ['screenResolution'],\n contextKeys: [],\n setup: trackScreenResolutionSetup,\n});\n"],"mappings":";;;;;;;;;;;;;;;AA6BA,SAAS,2BAA2B,EAClC,OACA,UAIa;CACb,MAAM,sBAAsB,QAAQ,uBAAuB;CAK3D,OAAO,uBAAuB,eAAe,MAAM,iBAAiB,IAAI,UAAU,GAAG,EAAE,oBAAoB,CAAC;AAC9G;AAEA,MAAa,wBAAwB,eAAe;CAClD,WAAW,CAAC,kBAAkB;CAC9B,aAAa,CAAC;CACd,OAAO;AACT,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { computed } from "../../../core/signals/primitives.js";
|
|
2
|
+
import { defineBehavior } from "../../../core/composition/create-composition.js";
|
|
3
|
+
import { createMachineReactor } from "../../../core/reactors/create-machine-reactor.js";
|
|
4
|
+
import { waitForMediaSourceOpen } from "../../../media/dom/mse/mediasource-setup.js";
|
|
5
|
+
import { getMaxBufferedEnd, shouldUpdateDuration, waitForSourceBuffersReady } from "../../../media/dom/mse/duration.js";
|
|
6
|
+
//#region src/playback/behaviors/dom/update-mediasource-duration.ts
|
|
7
|
+
/**
|
|
8
|
+
* **Propagate `presentation.duration` to `mediaSource.duration` — exactly once per MediaSource.**
|
|
9
|
+
*
|
|
10
|
+
* Two paths, by whether the presentation is live:
|
|
11
|
+
*
|
|
12
|
+
* - **Live** (`presentation.duration === Infinity`): write `Infinity` once the MediaSource is open and no SourceBuffer is
|
|
13
|
+
* mid-append. No buffered clamp is needed (`Infinity` ≥ any range) and — unlike the finite case — it needn't precede
|
|
14
|
+
* the first append: `Infinity` overrides whatever finite live-edge value an append may have pinned (a finite duration
|
|
15
|
+
* would otherwise stall the stream once the window slides past it). The wait-for-idle is required because the MSE
|
|
16
|
+
* spec forbids setting `duration` while a buffer is `updating`; both waits resolve immediately when already open /
|
|
17
|
+
* idle.
|
|
18
|
+
* - **VoD** (finite): the value is written once, after `mediaSource` is open and all SourceBuffers are idle, clamped to
|
|
19
|
+
* be ≥ the highest buffered range (MSE spec). Written only while `mediaSource.duration` is still `NaN`; once any
|
|
20
|
+
* non-NaN value is present (us on a prior entry, or `endOfStream` from the buffered end), the property is left alone
|
|
21
|
+
* — re-syncing would race concurrent `appendBuffer()` calls.
|
|
22
|
+
*
|
|
23
|
+
* The entry resolves three async preconditions in order before writing:
|
|
24
|
+
*
|
|
25
|
+
* 1. **MediaSource open** — `waitForMediaSourceOpen` defers until the first `sourceopen` event (or any readyState
|
|
26
|
+
* transition, since `'ended'` / `'closed'` mean we've missed the window and should bail).
|
|
27
|
+
* 2. **All SourceBuffers idle** — `waitForSourceBuffersReady` defers per the MSE-spec rule that `duration` cannot be set
|
|
28
|
+
* while any buffer has `updating === true`.
|
|
29
|
+
* 3. **Buffered-range clamp** — `getMaxBufferedEnd` ensures the written duration is at least the highest buffered end (MSE
|
|
30
|
+
* spec disallows a smaller `duration` than any buffered range).
|
|
31
|
+
*
|
|
32
|
+
* The buffer-set helpers operate across `mediaSource.sourceBuffers` (the canonical aggregate), so the behavior composes
|
|
33
|
+
* uniformly across audio-only, video-only, and mixed configurations.
|
|
34
|
+
*
|
|
35
|
+
* Single-positive-state reactor (`'preconditions-unmet'` ↔ `'duration-writable'`): state derivation is purely
|
|
36
|
+
* signal-driven (presentation validity + mediaSource existence). MediaSource lifecycle state (`readyState`) and the
|
|
37
|
+
* `duration` itself are non-signal DOM properties resolved inside the entry's async sequence. The state-exit cleanup
|
|
38
|
+
* aborts the in-flight wait, so source resets and behavior destroy structurally cancel the pending write. A post-await
|
|
39
|
+
* re-check of `mediaSource.readyState === 'open'` covers the narrow race where `endOfStream()` synchronously
|
|
40
|
+
* transitions readyState to `'ended'` between our `waitForMediaSourceOpen` resolution and the `mediaSource.duration`
|
|
41
|
+
* write.
|
|
42
|
+
*
|
|
43
|
+
* Downstream of `calculatePresentationDuration` (which writes `presentation.duration`); concurrent with `endOfStream`
|
|
44
|
+
* (which may later write `mediaSource.duration` — the "exactly once" contract keeps us out of that path).
|
|
45
|
+
*/
|
|
46
|
+
function deriveState(presentation, mediaSource) {
|
|
47
|
+
return shouldUpdateDuration(presentation, mediaSource) ? "duration-writable" : "preconditions-unmet";
|
|
48
|
+
}
|
|
49
|
+
function updateMediaSourceDurationSetup({ state, context }) {
|
|
50
|
+
const derivedStateSignal = computed(() => deriveState(state.presentation.get(), context.mediaSource.get()));
|
|
51
|
+
return createMachineReactor({
|
|
52
|
+
initial: "preconditions-unmet",
|
|
53
|
+
monitor: () => derivedStateSignal.get(),
|
|
54
|
+
states: {
|
|
55
|
+
"preconditions-unmet": {},
|
|
56
|
+
"duration-writable": { entry: () => {
|
|
57
|
+
const presentation = state.presentation.get();
|
|
58
|
+
const mediaSource = context.mediaSource.get();
|
|
59
|
+
if (presentation.duration === Number.POSITIVE_INFINITY) {
|
|
60
|
+
if (mediaSource.duration === Number.POSITIVE_INFINITY) return;
|
|
61
|
+
const controller = new AbortController();
|
|
62
|
+
(async () => {
|
|
63
|
+
await waitForMediaSourceOpen(mediaSource, controller.signal);
|
|
64
|
+
if (controller.signal.aborted || mediaSource.readyState !== "open") return;
|
|
65
|
+
await waitForSourceBuffersReady(mediaSource.sourceBuffers, controller.signal);
|
|
66
|
+
if (controller.signal.aborted || mediaSource.readyState !== "open") return;
|
|
67
|
+
if (mediaSource.duration !== Number.POSITIVE_INFINITY) mediaSource.duration = Number.POSITIVE_INFINITY;
|
|
68
|
+
})();
|
|
69
|
+
return () => controller.abort();
|
|
70
|
+
}
|
|
71
|
+
if (!Number.isNaN(mediaSource.duration)) return;
|
|
72
|
+
const controller = new AbortController();
|
|
73
|
+
const writeWhenReady = async () => {
|
|
74
|
+
await waitForMediaSourceOpen(mediaSource, controller.signal);
|
|
75
|
+
if (controller.signal.aborted) return;
|
|
76
|
+
if (mediaSource.readyState !== "open") return;
|
|
77
|
+
await waitForSourceBuffersReady(mediaSource.sourceBuffers, controller.signal);
|
|
78
|
+
if (controller.signal.aborted) return;
|
|
79
|
+
if (mediaSource.readyState !== "open") return;
|
|
80
|
+
const maxBufferedEnd = getMaxBufferedEnd(mediaSource.sourceBuffers);
|
|
81
|
+
const duration = maxBufferedEnd > presentation.duration ? maxBufferedEnd : presentation.duration;
|
|
82
|
+
mediaSource.duration = duration;
|
|
83
|
+
};
|
|
84
|
+
writeWhenReady();
|
|
85
|
+
return () => controller.abort();
|
|
86
|
+
} }
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
const updateMediaSourceDuration = defineBehavior({
|
|
91
|
+
stateKeys: ["presentation"],
|
|
92
|
+
contextKeys: ["mediaSource"],
|
|
93
|
+
setup: updateMediaSourceDurationSetup
|
|
94
|
+
});
|
|
95
|
+
//#endregion
|
|
96
|
+
export { updateMediaSourceDuration };
|
|
97
|
+
|
|
98
|
+
//# sourceMappingURL=update-mediasource-duration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-mediasource-duration.js","names":[],"sources":["../../../../../src/playback/behaviors/dom/update-mediasource-duration.ts"],"sourcesContent":["/**\n * **Propagate `presentation.duration` to `mediaSource.duration` — exactly once per MediaSource.**\n *\n * Two paths, by whether the presentation is live:\n *\n * - **Live** (`presentation.duration === Infinity`): write `Infinity` once the MediaSource is open and no SourceBuffer is\n * mid-append. No buffered clamp is needed (`Infinity` ≥ any range) and — unlike the finite case — it needn't precede\n * the first append: `Infinity` overrides whatever finite live-edge value an append may have pinned (a finite duration\n * would otherwise stall the stream once the window slides past it). The wait-for-idle is required because the MSE\n * spec forbids setting `duration` while a buffer is `updating`; both waits resolve immediately when already open /\n * idle.\n * - **VoD** (finite): the value is written once, after `mediaSource` is open and all SourceBuffers are idle, clamped to\n * be ≥ the highest buffered range (MSE spec). Written only while `mediaSource.duration` is still `NaN`; once any\n * non-NaN value is present (us on a prior entry, or `endOfStream` from the buffered end), the property is left alone\n * — re-syncing would race concurrent `appendBuffer()` calls.\n *\n * The entry resolves three async preconditions in order before writing:\n *\n * 1. **MediaSource open** — `waitForMediaSourceOpen` defers until the first `sourceopen` event (or any readyState\n * transition, since `'ended'` / `'closed'` mean we've missed the window and should bail).\n * 2. **All SourceBuffers idle** — `waitForSourceBuffersReady` defers per the MSE-spec rule that `duration` cannot be set\n * while any buffer has `updating === true`.\n * 3. **Buffered-range clamp** — `getMaxBufferedEnd` ensures the written duration is at least the highest buffered end (MSE\n * spec disallows a smaller `duration` than any buffered range).\n *\n * The buffer-set helpers operate across `mediaSource.sourceBuffers` (the canonical aggregate), so the behavior composes\n * uniformly across audio-only, video-only, and mixed configurations.\n *\n * Single-positive-state reactor (`'preconditions-unmet'` ↔ `'duration-writable'`): state derivation is purely\n * signal-driven (presentation validity + mediaSource existence). MediaSource lifecycle state (`readyState`) and the\n * `duration` itself are non-signal DOM properties resolved inside the entry's async sequence. The state-exit cleanup\n * aborts the in-flight wait, so source resets and behavior destroy structurally cancel the pending write. A post-await\n * re-check of `mediaSource.readyState === 'open'` covers the narrow race where `endOfStream()` synchronously\n * transitions readyState to `'ended'` between our `waitForMediaSourceOpen` resolution and the `mediaSource.duration`\n * write.\n *\n * Downstream of `calculatePresentationDuration` (which writes `presentation.duration`); concurrent with `endOfStream`\n * (which may later write `mediaSource.duration` — the \"exactly once\" contract keeps us out of that path).\n */\nimport { defineBehavior } from '../../../core/composition/create-composition';\nimport type { Reactor } from '../../../core/reactors/create-machine-reactor';\nimport { createMachineReactor } from '../../../core/reactors/create-machine-reactor';\nimport { computed, type ReadonlySignal } from '../../../core/signals/primitives';\nimport { getMaxBufferedEnd, shouldUpdateDuration, waitForSourceBuffersReady } from '../../../media/dom/mse/duration';\nimport { waitForMediaSourceOpen } from '../../../media/dom/mse/mediasource-setup';\nimport type { MaybeResolvedPresentation } from '../../../media/types';\n\ntype DurationFsmState = 'preconditions-unmet' | 'duration-writable';\n\nfunction deriveState(\n presentation: MaybeResolvedPresentation | undefined,\n mediaSource: MediaSource | undefined\n): DurationFsmState {\n return shouldUpdateDuration(presentation, mediaSource) ? 'duration-writable' : 'preconditions-unmet';\n}\n\nfunction updateMediaSourceDurationSetup({\n state,\n context,\n}: {\n state: { presentation: ReadonlySignal<MaybeResolvedPresentation | undefined> };\n context: { mediaSource: ReadonlySignal<MediaSource | undefined> };\n}): Reactor<DurationFsmState | 'destroying' | 'destroyed'> {\n // Purely signal-driven derivation: only `presentation` validity and\n // `mediaSource` existence. MediaSource lifecycle (`readyState`),\n // its attached `sourceBuffers`, and `mediaSource.duration` itself are\n // non-signal DOM properties consumed inside the entry — none of them\n // sneak into `computed(...)`.\n const derivedStateSignal = computed(() => deriveState(state.presentation.get(), context.mediaSource.get()));\n\n return createMachineReactor<DurationFsmState>({\n initial: 'preconditions-unmet',\n monitor: () => derivedStateSignal.get(),\n states: {\n 'preconditions-unmet': {},\n\n 'duration-writable': {\n // entry body is auto-untracked. The state machine handles source\n // resets via deriveState; this entry resolves the MediaSource\n // lifecycle preconditions in sequence and binds its cleanup\n // (abort) to state exit + destroy.\n entry: () => {\n const presentation = state.presentation.get()!;\n const mediaSource = context.mediaSource.get()!;\n\n // Live: write Infinity once the MediaSource is open and no buffer is\n // mid-append (the MSE spec forbids setting `duration` while a\n // SourceBuffer is `updating`, and racing an in-flight append throws).\n // No `NaN` guard, unlike the VoD path below — Infinity must override\n // whatever finite live-edge value an append may have pinned.\n if (presentation.duration === Number.POSITIVE_INFINITY) {\n if (mediaSource.duration === Number.POSITIVE_INFINITY) return;\n\n const controller = new AbortController();\n\n void (async () => {\n await waitForMediaSourceOpen(mediaSource, controller.signal);\n\n if (controller.signal.aborted || mediaSource.readyState !== 'open') return;\n\n await waitForSourceBuffersReady(mediaSource.sourceBuffers, controller.signal);\n\n if (controller.signal.aborted || mediaSource.readyState !== 'open') return;\n\n if (mediaSource.duration !== Number.POSITIVE_INFINITY) {\n mediaSource.duration = Number.POSITIVE_INFINITY;\n }\n })();\n return () => controller.abort();\n }\n\n // VoD idempotency: someone (us on a prior entry, or concurrent\n // `endOfStream`) has already written. No-op and leave the state\n // alone — the next source-reset transition will produce a fresh\n // entry against the new MediaSource (whose `duration` starts at\n // `NaN` again).\n if (!Number.isNaN(mediaSource.duration)) return;\n\n const controller = new AbortController();\n\n const writeWhenReady = async () => {\n await waitForMediaSourceOpen(mediaSource, controller.signal);\n\n if (controller.signal.aborted) return;\n\n // `waitForMediaSourceOpen` resolves on any readyState transition\n // out of 'closed'; if we landed in 'ended' / 'closed' instead of\n // 'open', the write window is gone.\n if (mediaSource.readyState !== 'open') return;\n\n await waitForSourceBuffersReady(mediaSource.sourceBuffers, controller.signal);\n\n if (controller.signal.aborted) return;\n\n // Narrow race: `endOfStream()` synchronously transitions\n // readyState to 'ended' AND writes `mediaSource.duration`\n // between our `waitForMediaSourceOpen` resolution and here.\n // Re-read the DOM property to catch this window.\n if (mediaSource.readyState !== 'open') return;\n\n // MSE spec: duration cannot be less than any buffered range.\n // Re-read sourceBuffers after the await so any buffer added\n // during the wait is included in the clamp.\n const maxBufferedEnd = getMaxBufferedEnd(mediaSource.sourceBuffers);\n const duration = maxBufferedEnd > presentation.duration! ? maxBufferedEnd : presentation.duration!;\n\n mediaSource.duration = duration;\n };\n\n writeWhenReady();\n\n return () => controller.abort();\n },\n },\n },\n });\n}\n\nexport const updateMediaSourceDuration = defineBehavior({\n stateKeys: ['presentation'],\n contextKeys: ['mediaSource'],\n setup: updateMediaSourceDurationSetup,\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDA,SAAS,YACP,cACA,aACkB;CAClB,OAAO,qBAAqB,cAAc,WAAW,IAAI,sBAAsB;AACjF;AAEA,SAAS,+BAA+B,EACtC,OACA,WAIyD;CAMzD,MAAM,qBAAqB,eAAe,YAAY,MAAM,aAAa,IAAI,GAAG,QAAQ,YAAY,IAAI,CAAC,CAAC;CAE1G,OAAO,qBAAuC;EAC5C,SAAS;EACT,eAAe,mBAAmB,IAAI;EACtC,QAAQ;GACN,uBAAuB,CAAC;GAExB,qBAAqB,EAKnB,aAAa;IACX,MAAM,eAAe,MAAM,aAAa,IAAI;IAC5C,MAAM,cAAc,QAAQ,YAAY,IAAI;IAO5C,IAAI,aAAa,aAAa,OAAO,mBAAmB;KACtD,IAAI,YAAY,aAAa,OAAO,mBAAmB;KAEvD,MAAM,aAAa,IAAI,gBAAgB;KAEvC,CAAM,YAAY;MAChB,MAAM,uBAAuB,aAAa,WAAW,MAAM;MAE3D,IAAI,WAAW,OAAO,WAAW,YAAY,eAAe,QAAQ;MAEpE,MAAM,0BAA0B,YAAY,eAAe,WAAW,MAAM;MAE5E,IAAI,WAAW,OAAO,WAAW,YAAY,eAAe,QAAQ;MAEpE,IAAI,YAAY,aAAa,OAAO,mBAClC,YAAY,WAAW,OAAO;KAElC,EAAA,CAAG;KACH,aAAa,WAAW,MAAM;IAChC;IAOA,IAAI,CAAC,OAAO,MAAM,YAAY,QAAQ,GAAG;IAEzC,MAAM,aAAa,IAAI,gBAAgB;IAEvC,MAAM,iBAAiB,YAAY;KACjC,MAAM,uBAAuB,aAAa,WAAW,MAAM;KAE3D,IAAI,WAAW,OAAO,SAAS;KAK/B,IAAI,YAAY,eAAe,QAAQ;KAEvC,MAAM,0BAA0B,YAAY,eAAe,WAAW,MAAM;KAE5E,IAAI,WAAW,OAAO,SAAS;KAM/B,IAAI,YAAY,eAAe,QAAQ;KAKvC,MAAM,iBAAiB,kBAAkB,YAAY,aAAa;KAClE,MAAM,WAAW,iBAAiB,aAAa,WAAY,iBAAiB,aAAa;KAEzF,YAAY,WAAW;IACzB;IAEA,eAAe;IAEf,aAAa,WAAW,MAAM;GAChC,EACF;EACF;CACF,CAAC;AACH;AAEA,MAAa,4BAA4B,eAAe;CACtD,WAAW,CAAC,cAAc;CAC1B,aAAa,CAAC,aAAa;CAC3B,OAAO;AACT,CAAC"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { update } from "../../core/signals/primitives.js";
|
|
2
|
+
import { createMachineReactor } from "../../core/reactors/create-machine-reactor.js";
|
|
3
|
+
import { isResolvedPresentation, isResolvedTrack } from "../../media/types/index.js";
|
|
4
|
+
import { findTrackById } from "../../media/utils/tracks.js";
|
|
5
|
+
//#region src/playback/behaviors/establish-start-media-time.ts
|
|
6
|
+
/**
|
|
7
|
+
* A single type's own media-timeline origin: `baseMediaDecodeTime/timescale − segmentStartTime` (the `segmentStartTime`
|
|
8
|
+
* term makes it the stream origin even when the first loaded segment isn't the 0th). `undefined` until timescale +
|
|
9
|
+
* baseMediaDecodeTime + segmentStartTime are all present.
|
|
10
|
+
*/
|
|
11
|
+
function ownOrigin(data) {
|
|
12
|
+
const { timescale, baseMediaDecodeTime, segmentStartTime } = data ?? {};
|
|
13
|
+
return timescale != null && baseMediaDecodeTime != null && segmentStartTime != null ? baseMediaDecodeTime / timescale - segmentStartTime : void 0;
|
|
14
|
+
}
|
|
15
|
+
/** Snap a below-threshold (incl. negative) origin to `0` so it isn't relocated. */
|
|
16
|
+
function thresholdOrigin(origin) {
|
|
17
|
+
return origin < 1 ? 0 : origin;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The **default** — relocate the whole presentation by one shared origin: the `min` across the _selected_ A/V tracks'
|
|
21
|
+
* own origins, denormalized onto every type. This single reduce subsumes the "per-type" and "shared" tiers:
|
|
22
|
+
*
|
|
23
|
+
* - **aligned A/V** — `min` equals each origin (they're equal), so it matches per-type;
|
|
24
|
+
* - **skewed A/V** (e.g. Apple's 44ms audio-lead) — `min` keeps every track's earliest DTS ≥ 0 (relocating by ≤ each own
|
|
25
|
+
* origin never drives one negative) _and_ preserves the real skew (per-type would flatten it, desyncing A/V);
|
|
26
|
+
* - **single type / muxed** — `min` of the one origin is that origin.
|
|
27
|
+
*
|
|
28
|
+
* Returns `undefined` for every type until all _selected_ types have a complete origin (the shared-`min` barrier).
|
|
29
|
+
* Which types must contribute is read from `ctx` (the selected v/a ids); with no selection context it coordinates
|
|
30
|
+
* across whatever types have data. A shared origin below {@link NEAR_ZERO_ORIGIN_THRESHOLD} is returned as `0` (native
|
|
31
|
+
* — ordinary ~0-PTS VOD isn't relocated).
|
|
32
|
+
*/
|
|
33
|
+
const deriveSharedMinStartMediaTime = (containerData, ctx) => {
|
|
34
|
+
const contributingTypes = [];
|
|
35
|
+
if (ctx.selectedVideoTrackId != null) contributingTypes.push("video");
|
|
36
|
+
if (ctx.selectedAudioTrackId != null) contributingTypes.push("audio");
|
|
37
|
+
const origins = (contributingTypes.length > 0 ? contributingTypes : Object.keys(containerData)).map((type) => ownOrigin(containerData[type]));
|
|
38
|
+
if (origins.length === 0 || origins.some((origin) => origin === void 0)) return {};
|
|
39
|
+
const shared = thresholdOrigin(Math.min(...origins));
|
|
40
|
+
const out = {};
|
|
41
|
+
for (const type of Object.keys(containerData)) out[type] = shared;
|
|
42
|
+
return out;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Coordination-axis _off_ — each type relocates by its own origin, independently. Not the default: it flattens real A/V
|
|
46
|
+
* skew (see {@link deriveSharedMinStartMediaTime}). Kept as an opt-in for compositions that know their A/V is aligned
|
|
47
|
+
* and want to skip the shared-`min` barrier (each type stamps as soon as its own origin is discovered).
|
|
48
|
+
*
|
|
49
|
+
* Caution: {@link NEAR_ZERO_ORIGIN_THRESHOLD} applies independently per type here — if two types' origins straddle it,
|
|
50
|
+
* one snaps to `0` and the other doesn't, injecting up to a threshold's worth of A/V offset. Safe for the intended
|
|
51
|
+
* aligned-A/V opt-in; see `internal/design/spf/live-presentation-timeline-model.md` (collision 5).
|
|
52
|
+
*/
|
|
53
|
+
const derivePerTypeStartMediaTime = (containerData) => {
|
|
54
|
+
const out = {};
|
|
55
|
+
for (const [type, data] of Object.entries(containerData)) {
|
|
56
|
+
const origin = ownOrigin(data);
|
|
57
|
+
out[type] = origin === void 0 ? void 0 : thresholdOrigin(origin);
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* The anchor-source track: the selected video track, falling back to audio (audio-only). Deterministic — never "first
|
|
63
|
+
* resolved", which is race-dependent under concurrent resolves.
|
|
64
|
+
*/
|
|
65
|
+
function referenceTrackId(ctx) {
|
|
66
|
+
return ctx.selectedVideoTrackId ?? ctx.selectedAudioTrackId;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The live-anchor first-parse gate (the "parses align" step of the establishment order). Open for the reference track
|
|
70
|
+
* itself — its local-from-0 placement _is_ the presentation timeline (presentation-0 = the join point). Every other
|
|
71
|
+
* track holds until the reference's first parse settles the anchor question: no PDT → local placement is already
|
|
72
|
+
* correct, proceed; PDT anchor → hold until the establishment reactor stamps it onto this track, so the parse takes the
|
|
73
|
+
* `placeOnAnchor` path. Establishment is sticky-once, so an unanchored first parse would be permanently misaligned —
|
|
74
|
+
* that's the race this gate closes.
|
|
75
|
+
*
|
|
76
|
+
* Pairs with the {@link establishStartMediaTime} reactor (the stamp that opens the anchored branch); wire both or
|
|
77
|
+
* neither.
|
|
78
|
+
*/
|
|
79
|
+
const gateFirstParseOnAnchor = (presentation, ctx, trackId) => {
|
|
80
|
+
const referenceId = referenceTrackId(ctx);
|
|
81
|
+
if (referenceId === void 0 || referenceId === trackId) return true;
|
|
82
|
+
if (!isResolvedPresentation(presentation)) return false;
|
|
83
|
+
const reference = findTrackById(presentation, referenceId);
|
|
84
|
+
if (!reference) return true;
|
|
85
|
+
if (!isResolvedTrack(reference)) return false;
|
|
86
|
+
if (reference.startDate === void 0) return true;
|
|
87
|
+
return findTrackById(presentation, trackId)?.startDate !== void 0;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Stamp the frozen wall-clock anchor as `startDate` onto every track that lacks one (idempotent — same reference when
|
|
91
|
+
* nothing moved). Unresolved shells pick it up as the `placeOnAnchor` preset; covering _all_ tracks in one pass means
|
|
92
|
+
* any track selected later — an ABR rung, another audio language, late captions — resolves already anchored. The
|
|
93
|
+
* reference track's own parser-computed `startDate` reads back as the anchor, so it's naturally left untouched.
|
|
94
|
+
*/
|
|
95
|
+
function stampStartDates(presentation, anchor) {
|
|
96
|
+
let changed = false;
|
|
97
|
+
const selectionSets = presentation.selectionSets.map((selectionSet) => ({
|
|
98
|
+
...selectionSet,
|
|
99
|
+
switchingSets: selectionSet.switchingSets.map((switchingSet) => ({
|
|
100
|
+
...switchingSet,
|
|
101
|
+
tracks: switchingSet.tracks.map((track) => {
|
|
102
|
+
if (track.startDate !== void 0) return track;
|
|
103
|
+
changed = true;
|
|
104
|
+
return {
|
|
105
|
+
...track,
|
|
106
|
+
startDate: anchor
|
|
107
|
+
};
|
|
108
|
+
})
|
|
109
|
+
}))
|
|
110
|
+
}));
|
|
111
|
+
return changed ? {
|
|
112
|
+
...presentation,
|
|
113
|
+
selectionSets
|
|
114
|
+
} : presentation;
|
|
115
|
+
}
|
|
116
|
+
/** Stamp the derived per-track `startMediaTime` onto the model (idempotent — same reference when nothing moved). */
|
|
117
|
+
function stampTracks(presentation, startMediaTimes) {
|
|
118
|
+
let changed = false;
|
|
119
|
+
const selectionSets = presentation.selectionSets.map((selectionSet) => ({
|
|
120
|
+
...selectionSet,
|
|
121
|
+
switchingSets: selectionSet.switchingSets.map((switchingSet) => ({
|
|
122
|
+
...switchingSet,
|
|
123
|
+
tracks: switchingSet.tracks.map((track) => {
|
|
124
|
+
const startMediaTime = startMediaTimes[track.type];
|
|
125
|
+
if (startMediaTime === void 0 || track.startMediaTime === startMediaTime) return track;
|
|
126
|
+
changed = true;
|
|
127
|
+
return {
|
|
128
|
+
...track,
|
|
129
|
+
startMediaTime
|
|
130
|
+
};
|
|
131
|
+
})
|
|
132
|
+
}))
|
|
133
|
+
}));
|
|
134
|
+
return changed ? {
|
|
135
|
+
...presentation,
|
|
136
|
+
selectionSets
|
|
137
|
+
} : presentation;
|
|
138
|
+
}
|
|
139
|
+
function establishStartMediaTimeSetup({ state, config = {} }) {
|
|
140
|
+
const derive = config.deriveStartMediaTime ?? deriveSharedMinStartMediaTime;
|
|
141
|
+
const selectionContext = () => ({
|
|
142
|
+
selectedVideoTrackId: state.selectedVideoTrackId?.get(),
|
|
143
|
+
selectedAudioTrackId: state.selectedAudioTrackId?.get()
|
|
144
|
+
});
|
|
145
|
+
/** Established once the selected A/V tracks (whichever exist) carry `startMediaTime`. */
|
|
146
|
+
const established = () => {
|
|
147
|
+
const presentation = state.presentation.get();
|
|
148
|
+
if (!isResolvedPresentation(presentation)) return false;
|
|
149
|
+
const ids = [state.selectedVideoTrackId?.get(), state.selectedAudioTrackId?.get()].filter((id) => id !== void 0);
|
|
150
|
+
return ids.length > 0 && ids.every((id) => findTrackById(presentation, id)?.startMediaTime !== void 0);
|
|
151
|
+
};
|
|
152
|
+
return createMachineReactor({
|
|
153
|
+
initial: "inactive",
|
|
154
|
+
monitor: () => {
|
|
155
|
+
if (!isResolvedPresentation(state.presentation.get())) return "inactive";
|
|
156
|
+
return established() ? "established" : "monitoring";
|
|
157
|
+
},
|
|
158
|
+
states: {
|
|
159
|
+
inactive: { entry: () => state.mediaContainerData.set(void 0) },
|
|
160
|
+
monitoring: { effects: [() => {
|
|
161
|
+
const presentation = state.presentation.get();
|
|
162
|
+
if (!isResolvedPresentation(presentation)) return;
|
|
163
|
+
const referenceId = referenceTrackId(selectionContext());
|
|
164
|
+
const reference = referenceId === void 0 ? void 0 : findTrackById(presentation, referenceId);
|
|
165
|
+
if (!reference || !isResolvedTrack(reference)) return;
|
|
166
|
+
const anchor = reference.startDate;
|
|
167
|
+
if (anchor === void 0) return;
|
|
168
|
+
update(state.presentation, (current) => stampStartDates(current, anchor));
|
|
169
|
+
}, () => {
|
|
170
|
+
const containerData = state.mediaContainerData.get();
|
|
171
|
+
if (!containerData) return;
|
|
172
|
+
const startMediaTimes = derive(containerData, selectionContext());
|
|
173
|
+
update(state.presentation, (current) => stampTracks(current, startMediaTimes));
|
|
174
|
+
}] },
|
|
175
|
+
established: {}
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
const establishStartMediaTime = {
|
|
180
|
+
stateKeys: ["presentation", "mediaContainerData"],
|
|
181
|
+
contextKeys: [],
|
|
182
|
+
setup: establishStartMediaTimeSetup
|
|
183
|
+
};
|
|
184
|
+
//#endregion
|
|
185
|
+
export { derivePerTypeStartMediaTime, deriveSharedMinStartMediaTime, establishStartMediaTime, gateFirstParseOnAnchor };
|
|
186
|
+
|
|
187
|
+
//# sourceMappingURL=establish-start-media-time.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"establish-start-media-time.js","names":[],"sources":["../../../../src/playback/behaviors/establish-start-media-time.ts"],"sourcesContent":["/**\n * Establish the presentation's coordinate origin — the `startTime` / `startMediaTime` / `startDate` triple — once per\n * source, so every track lands on one 0-based presentation timeline. One establishment unit with an internal order: the\n * wall-clock **anchor** settles (live PDT sources), gated parses align to it, then `startMediaTime` latches — see\n * `internal/design/spf/live-presentation-timeline-model.md`.\n *\n * The two coordinate stamps it owns:\n *\n * - **`startDate` (wall-clock anchor).** The designated _reference track_ (selected video, else audio) resolves first;\n * its parser-computed `startDate` — PDT at presentation-0 — is frozen as the anchor and stamped onto every other\n * track that lacks one, so their first parses place via `placeOnAnchor` (the pre-applied-anchor path in\n * `parse-media-playlist`) and later-selected renditions resolve already aligned. Ordering is enforced by\n * {@link gateFirstParseOnAnchor}, which `resolve-track` awaits through its injected gate seam. Absent PDT (ordinary\n * VOD), no anchor is stamped and local-from-0 placement is already correct.\n * - **`startMediaTime` (decode origin).** Runs the injected {@link DeriveStartMediaTime} seam over the transient\n * `mediaContainerData` slot (owned here; `inactive` clears it per source) and stamps the settled value onto the model\n * until `established`. The byte-level discover/stamp steps that fill the slot are a separate, config\n * `messagePipelines` array (`primitives/relocation-pipelines`); the two coordinate only through the shared\n * `state.mediaContainerData` slot, never by import. See `internal/design/spf/presentation-timeline-model.md`.\n *\n * DOM-free reactor; sticky per source (`inactive → monitoring → established`).\n */\nimport type { Behavior } from '../../core/composition/create-composition';\nimport { createMachineReactor, type Reactor } from '../../core/reactors/create-machine-reactor';\nimport { type ReadonlySignal, type Signal, update } from '../../core/signals/primitives';\nimport {\n isResolvedPresentation,\n isResolvedTrack,\n type MaybeResolvedPresentation,\n type MediaContainerData,\n type Presentation,\n} from '../../media/types';\nimport { findTrackById } from '../../media/utils/tracks';\nimport type { DeriveStartMediaTime, DeriveStartMediaTimeContext } from '../primitives/derive-start-media-time';\nimport type { GateFirstParse, GateFirstParseContext } from '../primitives/gate-first-parse';\n\nexport type { DeriveStartMediaTime, DeriveStartMediaTimeContext, GateFirstParse, GateFirstParseContext };\n\n// ============================================================================\n// STATE / CONFIG\n// ============================================================================\n\nexport interface EstablishStartMediaTimeState {\n presentation?: MaybeResolvedPresentation;\n /**\n * Transient origin-establishment data, keyed by **track type** (`'video'` / `'audio'`) — per spec one init+media pair\n * per type suffices, and ABR rungs of a type share the origin. Filled by the discover steps across appends, reset per\n * source. Never the model — the churn stays here; only the settled `startMediaTime` reaches `Track`.\n */\n mediaContainerData?: Record<string, MediaContainerData>;\n selectedVideoTrackId?: string;\n selectedAudioTrackId?: string;\n}\n\n/**\n * A single type's own media-timeline origin: `baseMediaDecodeTime/timescale − segmentStartTime` (the `segmentStartTime`\n * term makes it the stream origin even when the first loaded segment isn't the 0th). `undefined` until timescale +\n * baseMediaDecodeTime + segmentStartTime are all present.\n */\nfunction ownOrigin(data: MediaContainerData | undefined): number | undefined {\n const { timescale, baseMediaDecodeTime, segmentStartTime } = data ?? {};\n\n return timescale != null && baseMediaDecodeTime != null && segmentStartTime != null\n ? baseMediaDecodeTime / timescale - segmentStartTime\n : undefined;\n}\n\n/**\n * Origins below this magnitude (seconds) are treated as `0` — the derive returns `0`, so the presentation is left on\n * its native (~0-based) timeline and no `timestampOffset` is set (the loader stamp no-ops on a derived `0`). Ordinary\n * VOD carries a small nonzero encode origin (audio priming, first-frame CTS, edit lists); relocating by a sub-second\n * amount is pointless, and setting `timestampOffset` at all can ripple edge segments. Relocation targets streams with\n * an intentional large origin (instant clips, bipbop @10s).\n *\n * Absolute basis, not proportional: the DTS-below-zero / ripple risk scales with the origin's absolute size, not with\n * the presentation's duration. Also snaps negatives to `0` — a negative origin would relocate _forward_, which is never\n * the intent.\n */\nexport const NEAR_ZERO_ORIGIN_THRESHOLD = 1;\n\n/** Snap a below-threshold (incl. negative) origin to `0` so it isn't relocated. */\nfunction thresholdOrigin(origin: number): number {\n return origin < NEAR_ZERO_ORIGIN_THRESHOLD ? 0 : origin;\n}\n\n/**\n * The **default** — relocate the whole presentation by one shared origin: the `min` across the _selected_ A/V tracks'\n * own origins, denormalized onto every type. This single reduce subsumes the \"per-type\" and \"shared\" tiers:\n *\n * - **aligned A/V** — `min` equals each origin (they're equal), so it matches per-type;\n * - **skewed A/V** (e.g. Apple's 44ms audio-lead) — `min` keeps every track's earliest DTS ≥ 0 (relocating by ≤ each own\n * origin never drives one negative) _and_ preserves the real skew (per-type would flatten it, desyncing A/V);\n * - **single type / muxed** — `min` of the one origin is that origin.\n *\n * Returns `undefined` for every type until all _selected_ types have a complete origin (the shared-`min` barrier).\n * Which types must contribute is read from `ctx` (the selected v/a ids); with no selection context it coordinates\n * across whatever types have data. A shared origin below {@link NEAR_ZERO_ORIGIN_THRESHOLD} is returned as `0` (native\n * — ordinary ~0-PTS VOD isn't relocated).\n */\nexport const deriveSharedMinStartMediaTime: DeriveStartMediaTime = (containerData, ctx) => {\n const contributingTypes: string[] = [];\n\n if (ctx.selectedVideoTrackId != null) contributingTypes.push('video');\n\n if (ctx.selectedAudioTrackId != null) contributingTypes.push('audio');\n\n const types = contributingTypes.length > 0 ? contributingTypes : Object.keys(containerData);\n\n const origins = types.map((type) => ownOrigin(containerData[type]));\n // Barrier: not ready until every contributing type has a complete origin.\n if (origins.length === 0 || origins.some((origin) => origin === undefined)) return {};\n\n const shared = thresholdOrigin(Math.min(...(origins as number[])));\n const out: Record<string, number | undefined> = {};\n\n for (const type of Object.keys(containerData)) out[type] = shared;\n\n return out;\n};\n\n/**\n * Coordination-axis _off_ — each type relocates by its own origin, independently. Not the default: it flattens real A/V\n * skew (see {@link deriveSharedMinStartMediaTime}). Kept as an opt-in for compositions that know their A/V is aligned\n * and want to skip the shared-`min` barrier (each type stamps as soon as its own origin is discovered).\n *\n * Caution: {@link NEAR_ZERO_ORIGIN_THRESHOLD} applies independently per type here — if two types' origins straddle it,\n * one snaps to `0` and the other doesn't, injecting up to a threshold's worth of A/V offset. Safe for the intended\n * aligned-A/V opt-in; see `internal/design/spf/live-presentation-timeline-model.md` (collision 5).\n */\nexport const derivePerTypeStartMediaTime: DeriveStartMediaTime = (containerData) => {\n const out: Record<string, number | undefined> = {};\n\n for (const [type, data] of Object.entries(containerData)) {\n const origin = ownOrigin(data);\n\n out[type] = origin === undefined ? undefined : thresholdOrigin(origin);\n }\n\n return out;\n};\n\n/**\n * The anchor-source track: the selected video track, falling back to audio (audio-only). Deterministic — never \"first\n * resolved\", which is race-dependent under concurrent resolves.\n */\nfunction referenceTrackId(ctx: GateFirstParseContext): string | undefined {\n return ctx.selectedVideoTrackId ?? ctx.selectedAudioTrackId;\n}\n\n/**\n * The live-anchor first-parse gate (the \"parses align\" step of the establishment order). Open for the reference track\n * itself — its local-from-0 placement _is_ the presentation timeline (presentation-0 = the join point). Every other\n * track holds until the reference's first parse settles the anchor question: no PDT → local placement is already\n * correct, proceed; PDT anchor → hold until the establishment reactor stamps it onto this track, so the parse takes the\n * `placeOnAnchor` path. Establishment is sticky-once, so an unanchored first parse would be permanently misaligned —\n * that's the race this gate closes.\n *\n * Pairs with the {@link establishStartMediaTime} reactor (the stamp that opens the anchored branch); wire both or\n * neither.\n */\nexport const gateFirstParseOnAnchor: GateFirstParse = (presentation, ctx, trackId) => {\n const referenceId = referenceTrackId(ctx);\n if (referenceId === undefined || referenceId === trackId) return true;\n\n if (!isResolvedPresentation(presentation)) return false;\n\n const reference = findTrackById(presentation, referenceId);\n // A dangling reference id can never anchor — don't deadlock on it.\n if (!reference) return true;\n\n if (!isResolvedTrack(reference)) return false;\n\n if (reference.startDate === undefined) return true;\n\n return findTrackById(presentation, trackId)?.startDate !== undefined;\n};\n\nexport interface EstablishStartMediaTimeConfig {\n /** The reduce seam (coordination knob). Defaults to {@link deriveSharedMinStartMediaTime}. */\n deriveStartMediaTime?: DeriveStartMediaTime;\n}\n\n// ============================================================================\n// REACTOR (owns the transient slot; derives + consumes onto the model)\n// ============================================================================\n\n/**\n * Stamp the frozen wall-clock anchor as `startDate` onto every track that lacks one (idempotent — same reference when\n * nothing moved). Unresolved shells pick it up as the `placeOnAnchor` preset; covering _all_ tracks in one pass means\n * any track selected later — an ABR rung, another audio language, late captions — resolves already anchored. The\n * reference track's own parser-computed `startDate` reads back as the anchor, so it's naturally left untouched.\n */\nfunction stampStartDates(presentation: Presentation, anchor: number): Presentation {\n let changed = false;\n const selectionSets = presentation.selectionSets.map((selectionSet) => ({\n ...selectionSet,\n switchingSets: selectionSet.switchingSets.map((switchingSet) => ({\n ...switchingSet,\n tracks: switchingSet.tracks.map((track) => {\n if (track.startDate !== undefined) return track;\n\n changed = true;\n return { ...track, startDate: anchor };\n }),\n })),\n }));\n\n return changed ? ({ ...presentation, selectionSets } as Presentation) : presentation;\n}\n\n/** Stamp the derived per-track `startMediaTime` onto the model (idempotent — same reference when nothing moved). */\nfunction stampTracks(presentation: Presentation, startMediaTimes: Record<string, number | undefined>): Presentation {\n let changed = false;\n const selectionSets = presentation.selectionSets.map((selectionSet) => ({\n ...selectionSet,\n switchingSets: selectionSet.switchingSets.map((switchingSet) => ({\n ...switchingSet,\n tracks: switchingSet.tracks.map((track) => {\n const startMediaTime = startMediaTimes[track.type];\n if (startMediaTime === undefined || track.startMediaTime === startMediaTime) return track;\n\n changed = true;\n return { ...track, startMediaTime };\n }),\n })),\n }));\n\n return changed ? ({ ...presentation, selectionSets } as Presentation) : presentation;\n}\n\ntype EstablishFsmState = 'inactive' | 'monitoring' | 'established';\n\ninterface EstablishStartMediaTimeDeps {\n state: {\n presentation: Signal<EstablishStartMediaTimeState['presentation']>;\n mediaContainerData: Signal<EstablishStartMediaTimeState['mediaContainerData']>;\n // Optional so the one behavior composes across video-only / audio-only / both,\n // like other cross-track-type behaviors (present at runtime iff a sibling owns it).\n selectedVideoTrackId?: ReadonlySignal<EstablishStartMediaTimeState['selectedVideoTrackId']>;\n selectedAudioTrackId?: ReadonlySignal<EstablishStartMediaTimeState['selectedAudioTrackId']>;\n };\n config?: EstablishStartMediaTimeConfig;\n}\n\nfunction establishStartMediaTimeSetup({\n state,\n config = {},\n}: EstablishStartMediaTimeDeps): Reactor<EstablishFsmState | 'destroying' | 'destroyed'> {\n const derive = config.deriveStartMediaTime ?? deriveSharedMinStartMediaTime;\n\n const selectionContext = (): DeriveStartMediaTimeContext => ({\n selectedVideoTrackId: state.selectedVideoTrackId?.get(),\n selectedAudioTrackId: state.selectedAudioTrackId?.get(),\n });\n\n /** Established once the selected A/V tracks (whichever exist) carry `startMediaTime`. */\n const established = (): boolean => {\n const presentation = state.presentation.get();\n if (!isResolvedPresentation(presentation)) return false;\n\n const ids = [state.selectedVideoTrackId?.get(), state.selectedAudioTrackId?.get()].filter(\n (id): id is string => id !== undefined\n );\n\n return ids.length > 0 && ids.every((id) => findTrackById(presentation, id)?.startMediaTime !== undefined);\n };\n\n return createMachineReactor<EstablishFsmState>({\n initial: 'inactive',\n monitor: () => {\n if (!isResolvedPresentation(state.presentation.get())) return 'inactive';\n\n return established() ? 'established' : 'monitoring';\n },\n states: {\n // Fresh per source: clear the transient slot so a new source re-discovers.\n inactive: { entry: () => state.mediaContainerData.set(undefined) },\n // The establishment order, as two effects: anchor first, derive second.\n // Both stamps are sticky per source — disabled on entry to `established`,\n // and a new source re-enters through `inactive`.\n monitoring: {\n effects: [\n // Anchor: freeze the wall-clock origin from the reference track's\n // first parse and stamp it onto every other track (the gate's open\n // condition + the `placeOnAnchor` preset for shells). Reads the\n // presentation tracked — it must see the reference resolve — and its\n // own write converges immediately (the stamp is idempotent, so the\n // re-run sets an identical value and stops).\n () => {\n const presentation = state.presentation.get();\n if (!isResolvedPresentation(presentation)) return;\n\n const referenceId = referenceTrackId(selectionContext());\n const reference = referenceId === undefined ? undefined : findTrackById(presentation, referenceId);\n if (!reference || !isResolvedTrack(reference)) return;\n\n const anchor = reference.startDate;\n if (anchor === undefined) return;\n\n update(state.presentation as Signal<MaybeResolvedPresentation>, (current) =>\n stampStartDates(current as Presentation, anchor)\n );\n },\n // Derive: reduce the accumulating container data into per-track startMediaTime\n // and stamp it onto the model. Re-runs as discover fills the slot; the update\n // reads presentation untracked, so no self-loop.\n () => {\n const containerData = state.mediaContainerData.get();\n if (!containerData) return;\n\n const startMediaTimes = derive(containerData, selectionContext());\n\n // `current` is always resolved here — the monitor gates `monitoring` on a\n // resolved presentation and transitions before effects re-run — so we cast\n // to `Presentation` rather than re-narrowing.\n update(state.presentation as Signal<MaybeResolvedPresentation>, (current) =>\n stampTracks(current as Presentation, startMediaTimes)\n );\n },\n ],\n },\n established: {},\n },\n });\n}\n\nexport const establishStartMediaTime: Behavior<\n {\n presentation: Signal<EstablishStartMediaTimeState['presentation']>;\n mediaContainerData: Signal<EstablishStartMediaTimeState['mediaContainerData']>;\n },\n Record<never, never>,\n EstablishStartMediaTimeConfig\n> = {\n stateKeys: ['presentation', 'mediaContainerData'],\n contextKeys: [],\n setup: establishStartMediaTimeSetup,\n};\n"],"mappings":";;;;;;;;;;AA2DA,SAAS,UAAU,MAA0D;CAC3E,MAAM,EAAE,WAAW,qBAAqB,qBAAqB,QAAQ,CAAC;CAEtE,OAAO,aAAa,QAAQ,uBAAuB,QAAQ,oBAAoB,OAC3E,sBAAsB,YAAY,mBAClC,KAAA;AACN;;AAgBA,SAAS,gBAAgB,QAAwB;CAC/C,OAAO,SAAA,IAAsC,IAAI;AACnD;;;;;;;;;;;;;;;AAgBA,MAAa,iCAAuD,eAAe,QAAQ;CACzF,MAAM,oBAA8B,CAAC;CAErC,IAAI,IAAI,wBAAwB,MAAM,kBAAkB,KAAK,OAAO;CAEpE,IAAI,IAAI,wBAAwB,MAAM,kBAAkB,KAAK,OAAO;CAIpE,MAAM,WAFQ,kBAAkB,SAAS,IAAI,oBAAoB,OAAO,KAAK,aAAa,EAAA,CAEpE,KAAK,SAAS,UAAU,cAAc,KAAK,CAAC;CAElE,IAAI,QAAQ,WAAW,KAAK,QAAQ,MAAM,WAAW,WAAW,KAAA,CAAS,GAAG,OAAO,CAAC;CAEpF,MAAM,SAAS,gBAAgB,KAAK,IAAI,GAAI,OAAoB,CAAC;CACjE,MAAM,MAA0C,CAAC;CAEjD,KAAK,MAAM,QAAQ,OAAO,KAAK,aAAa,GAAG,IAAI,QAAQ;CAE3D,OAAO;AACT;;;;;;;;;;AAWA,MAAa,+BAAqD,kBAAkB;CAClF,MAAM,MAA0C,CAAC;CAEjD,KAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,aAAa,GAAG;EACxD,MAAM,SAAS,UAAU,IAAI;EAE7B,IAAI,QAAQ,WAAW,KAAA,IAAY,KAAA,IAAY,gBAAgB,MAAM;CACvE;CAEA,OAAO;AACT;;;;;AAMA,SAAS,iBAAiB,KAAgD;CACxE,OAAO,IAAI,wBAAwB,IAAI;AACzC;;;;;;;;;;;;AAaA,MAAa,0BAA0C,cAAc,KAAK,YAAY;CACpF,MAAM,cAAc,iBAAiB,GAAG;CACxC,IAAI,gBAAgB,KAAA,KAAa,gBAAgB,SAAS,OAAO;CAEjE,IAAI,CAAC,uBAAuB,YAAY,GAAG,OAAO;CAElD,MAAM,YAAY,cAAc,cAAc,WAAW;CAEzD,IAAI,CAAC,WAAW,OAAO;CAEvB,IAAI,CAAC,gBAAgB,SAAS,GAAG,OAAO;CAExC,IAAI,UAAU,cAAc,KAAA,GAAW,OAAO;CAE9C,OAAO,cAAc,cAAc,OAAO,CAAC,EAAE,cAAc,KAAA;AAC7D;;;;;;;AAiBA,SAAS,gBAAgB,cAA4B,QAA8B;CACjF,IAAI,UAAU;CACd,MAAM,gBAAgB,aAAa,cAAc,KAAK,kBAAkB;EACtE,GAAG;EACH,eAAe,aAAa,cAAc,KAAK,kBAAkB;GAC/D,GAAG;GACH,QAAQ,aAAa,OAAO,KAAK,UAAU;IACzC,IAAI,MAAM,cAAc,KAAA,GAAW,OAAO;IAE1C,UAAU;IACV,OAAO;KAAE,GAAG;KAAO,WAAW;IAAO;GACvC,CAAC;EACH,EAAE;CACJ,EAAE;CAEF,OAAO,UAAW;EAAE,GAAG;EAAc;CAAc,IAAqB;AAC1E;;AAGA,SAAS,YAAY,cAA4B,iBAAmE;CAClH,IAAI,UAAU;CACd,MAAM,gBAAgB,aAAa,cAAc,KAAK,kBAAkB;EACtE,GAAG;EACH,eAAe,aAAa,cAAc,KAAK,kBAAkB;GAC/D,GAAG;GACH,QAAQ,aAAa,OAAO,KAAK,UAAU;IACzC,MAAM,iBAAiB,gBAAgB,MAAM;IAC7C,IAAI,mBAAmB,KAAA,KAAa,MAAM,mBAAmB,gBAAgB,OAAO;IAEpF,UAAU;IACV,OAAO;KAAE,GAAG;KAAO;IAAe;GACpC,CAAC;EACH,EAAE;CACJ,EAAE;CAEF,OAAO,UAAW;EAAE,GAAG;EAAc;CAAc,IAAqB;AAC1E;AAgBA,SAAS,6BAA6B,EACpC,OACA,SAAS,CAAC,KAC6E;CACvF,MAAM,SAAS,OAAO,wBAAwB;CAE9C,MAAM,0BAAuD;EAC3D,sBAAsB,MAAM,sBAAsB,IAAI;EACtD,sBAAsB,MAAM,sBAAsB,IAAI;CACxD;;CAGA,MAAM,oBAA6B;EACjC,MAAM,eAAe,MAAM,aAAa,IAAI;EAC5C,IAAI,CAAC,uBAAuB,YAAY,GAAG,OAAO;EAElD,MAAM,MAAM,CAAC,MAAM,sBAAsB,IAAI,GAAG,MAAM,sBAAsB,IAAI,CAAC,CAAC,CAAC,QAChF,OAAqB,OAAO,KAAA,CAC/B;EAEA,OAAO,IAAI,SAAS,KAAK,IAAI,OAAO,OAAO,cAAc,cAAc,EAAE,CAAC,EAAE,mBAAmB,KAAA,CAAS;CAC1G;CAEA,OAAO,qBAAwC;EAC7C,SAAS;EACT,eAAe;GACb,IAAI,CAAC,uBAAuB,MAAM,aAAa,IAAI,CAAC,GAAG,OAAO;GAE9D,OAAO,YAAY,IAAI,gBAAgB;EACzC;EACA,QAAQ;GAEN,UAAU,EAAE,aAAa,MAAM,mBAAmB,IAAI,KAAA,CAAS,EAAE;GAIjE,YAAY,EACV,SAAS,OAOD;IACJ,MAAM,eAAe,MAAM,aAAa,IAAI;IAC5C,IAAI,CAAC,uBAAuB,YAAY,GAAG;IAE3C,MAAM,cAAc,iBAAiB,iBAAiB,CAAC;IACvD,MAAM,YAAY,gBAAgB,KAAA,IAAY,KAAA,IAAY,cAAc,cAAc,WAAW;IACjG,IAAI,CAAC,aAAa,CAAC,gBAAgB,SAAS,GAAG;IAE/C,MAAM,SAAS,UAAU;IACzB,IAAI,WAAW,KAAA,GAAW;IAE1B,OAAO,MAAM,eAAoD,YAC/D,gBAAgB,SAAyB,MAAM,CACjD;GACF,SAIM;IACJ,MAAM,gBAAgB,MAAM,mBAAmB,IAAI;IACnD,IAAI,CAAC,eAAe;IAEpB,MAAM,kBAAkB,OAAO,eAAe,iBAAiB,CAAC;IAKhE,OAAO,MAAM,eAAoD,YAC/D,YAAY,SAAyB,eAAe,CACtD;GACF,CACF,EACF;GACA,aAAa,CAAC;EAChB;CACF,CAAC;AACH;AAEA,MAAa,0BAOT;CACF,WAAW,CAAC,gBAAgB,oBAAoB;CAChD,aAAa,CAAC;CACd,OAAO;AACT"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { computed } from "../../core/signals/primitives.js";
|
|
2
|
+
import { defineBehavior } from "../../core/composition/create-composition.js";
|
|
3
|
+
import { createMachineReactor } from "../../core/reactors/create-machine-reactor.js";
|
|
4
|
+
import { isResolvedPresentation } from "../../media/types/index.js";
|
|
5
|
+
import { fetchResolvable, getResponseText } from "../../network/fetch.js";
|
|
6
|
+
import { isBlockingPreload } from "../../media/utils/preload.js";
|
|
7
|
+
//#region src/playback/behaviors/resolve-presentation.ts
|
|
8
|
+
/**
|
|
9
|
+
* **Resolve an unresolved presentation by fetching and parsing its manifest.**
|
|
10
|
+
*
|
|
11
|
+
* Reads `state.presentation`; when it holds `{ url }` (unresolved) and the preload / load-activation gate is met,
|
|
12
|
+
* fetches the manifest, parses it via the **required** `config.parsePresentation`, and writes the resolved
|
|
13
|
+
* `Presentation` back to the same slot. The behavior is format-neutral: the composing engine wires in its parser (e.g.
|
|
14
|
+
* the HLS engine supplies the multivariant-playlist parser).
|
|
15
|
+
*
|
|
16
|
+
* Source-identity-driven, expressed as a 4-state machine:
|
|
17
|
+
*
|
|
18
|
+
* 'preconditions-unmet' → 'idle' → 'resolving' → 'resolved'
|
|
19
|
+
*
|
|
20
|
+
* - `'preconditions-unmet'`: no presentation, or presentation has no URL.
|
|
21
|
+
* - `'idle'`: URL present, unresolved, gate unmet (blocking preload + no load-activation). Waits for the gate to open.
|
|
22
|
+
* - `'resolving'`: URL present, unresolved, gate met. Entry starts the fetch and returns the AbortController — the
|
|
23
|
+
* reactor calls `.abort()` on state exit, so source change / gate-close / destroy all cancel cleanly.
|
|
24
|
+
* - `'resolved'`: `state.presentation` holds a resolved `Presentation`.
|
|
25
|
+
*
|
|
26
|
+
* Gate semantics: `state.preload` (or `config.defaultPreload`, default `'metadata'`, when state.preload is unset)
|
|
27
|
+
* blocks resolution when its value is `'none'` (see `isBlockingPreload` in `media/utils/preload`).
|
|
28
|
+
* `state.loadActivated` is an override — true bypasses the preload gate entirely.
|
|
29
|
+
*
|
|
30
|
+
* Multi-writer with the engine adapter, which writes the initial unresolved `{ url }` to `state.presentation` from src
|
|
31
|
+
* input. Different domains (config-input vs. derived state via fetch) — legitimate multi-writer.
|
|
32
|
+
*/
|
|
33
|
+
function deriveState(presentation, preload, loadActivated, defaultPreload) {
|
|
34
|
+
if (!presentation?.url) return "preconditions-unmet";
|
|
35
|
+
if (isResolvedPresentation(presentation)) return "resolved";
|
|
36
|
+
return !!loadActivated || !isBlockingPreload(preload, defaultPreload) ? "resolving" : "idle";
|
|
37
|
+
}
|
|
38
|
+
function resolvePresentationSetup({ state, config }) {
|
|
39
|
+
const { parsePresentation } = config;
|
|
40
|
+
const defaultPreload = config.defaultPreload ?? "metadata";
|
|
41
|
+
const derivedStateSignal = computed(() => deriveState(state.presentation.get(), state.preload.get(), state.loadActivated.get(), defaultPreload));
|
|
42
|
+
return createMachineReactor({
|
|
43
|
+
initial: "preconditions-unmet",
|
|
44
|
+
monitor: () => derivedStateSignal.get(),
|
|
45
|
+
states: {
|
|
46
|
+
"preconditions-unmet": {},
|
|
47
|
+
idle: {},
|
|
48
|
+
resolving: { entry: () => {
|
|
49
|
+
const presentation = state.presentation.get();
|
|
50
|
+
const ac = new AbortController();
|
|
51
|
+
fetchResolvable(presentation, { signal: ac.signal }).then((response) => getResponseText(response)).then((text) => {
|
|
52
|
+
const parsed = parsePresentation(text, presentation);
|
|
53
|
+
state.presentation.set(parsed);
|
|
54
|
+
}).catch((error) => {
|
|
55
|
+
if (error instanceof Error && error.name === "AbortError") return;
|
|
56
|
+
console.error("[resolvePresentation] manifest fetch/parse failed:", error);
|
|
57
|
+
});
|
|
58
|
+
return ac;
|
|
59
|
+
} },
|
|
60
|
+
resolved: {}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const resolvePresentation = defineBehavior({
|
|
65
|
+
stateKeys: [
|
|
66
|
+
"presentation",
|
|
67
|
+
"preload",
|
|
68
|
+
"loadActivated"
|
|
69
|
+
],
|
|
70
|
+
contextKeys: [],
|
|
71
|
+
setup: resolvePresentationSetup
|
|
72
|
+
});
|
|
73
|
+
//#endregion
|
|
74
|
+
export { resolvePresentation };
|
|
75
|
+
|
|
76
|
+
//# sourceMappingURL=resolve-presentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-presentation.js","names":[],"sources":["../../../../src/playback/behaviors/resolve-presentation.ts"],"sourcesContent":["/**\n * **Resolve an unresolved presentation by fetching and parsing its manifest.**\n *\n * Reads `state.presentation`; when it holds `{ url }` (unresolved) and the preload / load-activation gate is met,\n * fetches the manifest, parses it via the **required** `config.parsePresentation`, and writes the resolved\n * `Presentation` back to the same slot. The behavior is format-neutral: the composing engine wires in its parser (e.g.\n * the HLS engine supplies the multivariant-playlist parser).\n *\n * Source-identity-driven, expressed as a 4-state machine:\n *\n * 'preconditions-unmet' → 'idle' → 'resolving' → 'resolved'\n *\n * - `'preconditions-unmet'`: no presentation, or presentation has no URL.\n * - `'idle'`: URL present, unresolved, gate unmet (blocking preload + no load-activation). Waits for the gate to open.\n * - `'resolving'`: URL present, unresolved, gate met. Entry starts the fetch and returns the AbortController — the\n * reactor calls `.abort()` on state exit, so source change / gate-close / destroy all cancel cleanly.\n * - `'resolved'`: `state.presentation` holds a resolved `Presentation`.\n *\n * Gate semantics: `state.preload` (or `config.defaultPreload`, default `'metadata'`, when state.preload is unset)\n * blocks resolution when its value is `'none'` (see `isBlockingPreload` in `media/utils/preload`).\n * `state.loadActivated` is an override — true bypasses the preload gate entirely.\n *\n * Multi-writer with the engine adapter, which writes the initial unresolved `{ url }` to `state.presentation` from src\n * input. Different domains (config-input vs. derived state via fetch) — legitimate multi-writer.\n */\nimport { defineBehavior } from '../../core/composition/create-composition';\nimport type { Reactor } from '../../core/reactors/create-machine-reactor';\nimport { createMachineReactor } from '../../core/reactors/create-machine-reactor';\nimport { computed, type ReadonlySignal, type Signal } from '../../core/signals/primitives';\nimport { isResolvedPresentation, type MaybeResolvedPresentation, type Presentation } from '../../media/types';\nimport { DEFAULT_PRELOAD, isBlockingPreload, type StandardPreload } from '../../media/utils/preload';\nimport { fetchResolvable, getResponseText } from '../../network/fetch';\n\nexport interface PresentationState {\n presentation?: MaybeResolvedPresentation;\n preload?: 'auto' | 'metadata' | 'none' | undefined;\n /** True once a preload-overriding event has fired for the current source — enables resolution regardless of preload. */\n loadActivated?: boolean;\n}\n\nexport type ParsePresentation = (text: string, presentation: MaybeResolvedPresentation) => Presentation;\n\nexport interface ResolvePresentationConfig {\n /**\n * Parses a manifest body into a resolved `Presentation`. **Required** — the behavior is format-neutral and the\n * composing engine supplies its own parser (HLS, DASH, etc.).\n */\n parsePresentation: ParsePresentation;\n /**\n * Fallback used when `state.preload` is unset (undefined / empty) for the resolution-gate decision. Defaults to\n * `'metadata'`, matching `syncPreload`'s own `defaultPreload`.\n */\n defaultPreload?: StandardPreload;\n}\n\nexport type ResolvePresentationState = 'preconditions-unmet' | 'idle' | 'resolving' | 'resolved';\n\nfunction deriveState(\n presentation: MaybeResolvedPresentation | undefined,\n preload: PresentationState['preload'],\n loadActivated: boolean | undefined,\n defaultPreload: StandardPreload\n): ResolvePresentationState {\n if (!presentation?.url) return 'preconditions-unmet';\n\n if (isResolvedPresentation(presentation)) return 'resolved';\n\n const gateOpen = !!loadActivated || !isBlockingPreload(preload, defaultPreload);\n\n return gateOpen ? 'resolving' : 'idle';\n}\n\nfunction resolvePresentationSetup({\n state,\n config,\n}: {\n state: {\n presentation: Signal<PresentationState['presentation']>;\n preload: ReadonlySignal<PresentationState['preload']>;\n loadActivated: ReadonlySignal<PresentationState['loadActivated']>;\n };\n config: ResolvePresentationConfig;\n}): Reactor<ResolvePresentationState | 'destroying' | 'destroyed'> {\n const { parsePresentation } = config;\n const defaultPreload: StandardPreload = config.defaultPreload ?? DEFAULT_PRELOAD;\n\n const derivedStateSignal = computed(() =>\n deriveState(state.presentation.get(), state.preload.get(), state.loadActivated.get(), defaultPreload)\n );\n\n return createMachineReactor<ResolvePresentationState>({\n initial: 'preconditions-unmet',\n monitor: () => derivedStateSignal.get(),\n states: {\n 'preconditions-unmet': {},\n idle: {},\n resolving: {\n entry: () => {\n const presentation = state.presentation.get()!;\n const ac = new AbortController();\n\n fetchResolvable(presentation, { signal: ac.signal })\n .then((response) => getResponseText(response))\n .then((text) => {\n const parsed = parsePresentation(text, presentation);\n\n state.presentation.set(parsed);\n })\n .catch((error) => {\n if (error instanceof Error && error.name === 'AbortError') return;\n\n // TODO(error-management): route to a state-error slot once one exists.\n console.error('[resolvePresentation] manifest fetch/parse failed:', error);\n });\n\n return ac;\n },\n },\n resolved: {},\n },\n });\n}\n\nexport const resolvePresentation = defineBehavior({\n stateKeys: ['presentation', 'preload', 'loadActivated'],\n contextKeys: [],\n setup: resolvePresentationSetup,\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDA,SAAS,YACP,cACA,SACA,eACA,gBAC0B;CAC1B,IAAI,CAAC,cAAc,KAAK,OAAO;CAE/B,IAAI,uBAAuB,YAAY,GAAG,OAAO;CAIjD,OAFiB,CAAC,CAAC,iBAAiB,CAAC,kBAAkB,SAAS,cAAc,IAE5D,cAAc;AAClC;AAEA,SAAS,yBAAyB,EAChC,OACA,UAQiE;CACjE,MAAM,EAAE,sBAAsB;CAC9B,MAAM,iBAAkC,OAAO,kBAAA;CAE/C,MAAM,qBAAqB,eACzB,YAAY,MAAM,aAAa,IAAI,GAAG,MAAM,QAAQ,IAAI,GAAG,MAAM,cAAc,IAAI,GAAG,cAAc,CACtG;CAEA,OAAO,qBAA+C;EACpD,SAAS;EACT,eAAe,mBAAmB,IAAI;EACtC,QAAQ;GACN,uBAAuB,CAAC;GACxB,MAAM,CAAC;GACP,WAAW,EACT,aAAa;IACX,MAAM,eAAe,MAAM,aAAa,IAAI;IAC5C,MAAM,KAAK,IAAI,gBAAgB;IAE/B,gBAAgB,cAAc,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,CACjD,MAAM,aAAa,gBAAgB,QAAQ,CAAC,CAAC,CAC7C,MAAM,SAAS;KACd,MAAM,SAAS,kBAAkB,MAAM,YAAY;KAEnD,MAAM,aAAa,IAAI,MAAM;IAC/B,CAAC,CAAC,CACD,OAAO,UAAU;KAChB,IAAI,iBAAiB,SAAS,MAAM,SAAS,cAAc;KAG3D,QAAQ,MAAM,sDAAsD,KAAK;IAC3E,CAAC;IAEH,OAAO;GACT,EACF;GACA,UAAU,CAAC;EACb;CACF,CAAC;AACH;AAEA,MAAa,sBAAsB,eAAe;CAChD,WAAW;EAAC;EAAgB;EAAW;CAAe;CACtD,aAAa,CAAC;CACd,OAAO;AACT,CAAC"}
|