@videojs/spf 10.0.0-beta.22 → 10.0.0-beta.24
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/dist/{dev/core → default/core/actors}/create-machine-actor.js +3 -3
- package/dist/default/core/actors/create-machine-actor.js.map +1 -0
- package/dist/default/core/{create-transition-actor.js → actors/create-transition-actor.js} +3 -3
- package/dist/default/core/actors/create-transition-actor.js.map +1 -0
- package/dist/default/core/composition/create-composition.js +85 -0
- package/dist/default/core/composition/create-composition.js.map +1 -0
- package/dist/default/core/composition/share-signals.js +37 -0
- package/dist/default/core/composition/share-signals.js.map +1 -0
- package/dist/{dev/core → default/core/reactors}/create-machine-reactor.js +4 -4
- package/dist/default/core/reactors/create-machine-reactor.js.map +1 -0
- package/dist/default/core/signals/primitives.js +33 -11
- package/dist/default/core/signals/primitives.js.map +1 -1
- package/dist/default/core/{task.js → tasks/task.js} +2 -2
- package/dist/default/core/tasks/task.js.map +1 -0
- package/dist/default/dom.js +9 -10
- package/dist/default/hls.js +3 -0
- package/dist/default/index.js +12 -3
- package/dist/default/index.js.map +1 -1
- package/dist/default/media/abr/quality-selection.js +83 -0
- package/dist/default/media/abr/quality-selection.js.map +1 -0
- package/dist/default/{core → media}/buffer/back-buffer.js +2 -2
- package/dist/default/media/buffer/back-buffer.js.map +1 -0
- package/dist/{dev/core → default/media}/buffer/forward-buffer.js +14 -2
- package/dist/default/media/buffer/forward-buffer.js.map +1 -0
- package/dist/{dev/dom/media → default/media/dom/mse}/append-segment.js +1 -1
- package/dist/default/media/dom/mse/append-segment.js.map +1 -0
- package/dist/default/{dom/media → media/dom/mse}/buffer-flusher.js +1 -1
- package/dist/default/media/dom/mse/buffer-flusher.js.map +1 -0
- package/dist/default/media/dom/mse/duration.js +78 -0
- package/dist/default/media/dom/mse/duration.js.map +1 -0
- package/dist/default/media/dom/mse/end-of-stream.js +20 -0
- package/dist/default/media/dom/mse/end-of-stream.js.map +1 -0
- package/dist/default/{dom/media → media/dom/mse}/mediasource-setup.js +63 -18
- package/dist/default/media/dom/mse/mediasource-setup.js.map +1 -0
- package/dist/default/{dom/text/parse-vtt-segment.js → media/dom/text/resolve-vtt-segment.js} +5 -5
- package/dist/default/media/dom/text/resolve-vtt-segment.js.map +1 -0
- package/dist/default/media/dom/text/text-track-slots.js +69 -0
- package/dist/default/media/dom/text/text-track-slots.js.map +1 -0
- package/dist/{dev/core → default/media}/hls/parse-attributes.js +1 -1
- package/dist/default/media/hls/parse-attributes.js.map +1 -0
- package/dist/{dev/core → default/media}/hls/parse-media-playlist.js +1 -1
- package/dist/default/media/hls/parse-media-playlist.js.map +1 -0
- package/dist/{dev/core → default/media}/hls/parse-multivariant.js +2 -2
- package/dist/default/media/hls/parse-multivariant.js.map +1 -0
- package/dist/default/{core → media}/hls/resolve-url.js +1 -1
- package/dist/default/media/hls/resolve-url.js.map +1 -0
- package/dist/default/media/primitives/select-tracks.js +45 -0
- package/dist/default/media/primitives/select-tracks.js.map +1 -0
- package/dist/default/media/types/index.js +36 -0
- package/dist/default/media/types/index.js.map +1 -0
- package/dist/default/media/utils/preload.js +22 -0
- package/dist/default/media/utils/preload.js.map +1 -0
- package/dist/default/media/utils/track-selection.js +47 -0
- package/dist/default/media/utils/track-selection.js.map +1 -0
- package/dist/default/media/utils/tracks.js +103 -0
- package/dist/default/media/utils/tracks.js.map +1 -0
- package/dist/default/{core/abr → network}/bandwidth-estimator.js +6 -5
- package/dist/default/network/bandwidth-estimator.js.map +1 -0
- package/dist/{dev/dom → default}/network/chunked-stream-iterable.js +1 -1
- package/dist/default/network/chunked-stream-iterable.js.map +1 -0
- package/dist/{dev/core/abr → default/network}/ewma.js +1 -1
- package/dist/default/network/ewma.js.map +1 -0
- package/dist/default/network/fetch.js +109 -0
- package/dist/default/network/fetch.js.map +1 -0
- package/dist/{dev/dom/features/segment-loader-actor.js → default/playback/actors/dom/segment-loader.js} +24 -15
- package/dist/default/playback/actors/dom/segment-loader.js.map +1 -0
- package/dist/{dev/dom/media/source-buffer-actor.js → default/playback/actors/dom/source-buffer.js} +8 -8
- package/dist/default/playback/actors/dom/source-buffer.js.map +1 -0
- package/dist/{dev/dom/features/text-tracks-actor.js → default/playback/actors/dom/text-tracks.js} +7 -3
- package/dist/default/playback/actors/dom/text-tracks.js.map +1 -0
- package/dist/default/playback/actors/text-track-segment-loader.js +135 -0
- package/dist/default/playback/actors/text-track-segment-loader.js.map +1 -0
- package/dist/default/playback/behaviors/calculate-presentation-duration.js +58 -0
- package/dist/default/playback/behaviors/calculate-presentation-duration.js.map +1 -0
- package/dist/default/playback/behaviors/dom/end-of-stream.js +178 -0
- package/dist/default/playback/behaviors/dom/end-of-stream.js.map +1 -0
- package/dist/default/playback/behaviors/dom/load-segments.js +177 -0
- package/dist/default/playback/behaviors/dom/load-segments.js.map +1 -0
- package/dist/default/playback/behaviors/dom/setup-buffer-actors.js +173 -0
- package/dist/default/playback/behaviors/dom/setup-buffer-actors.js.map +1 -0
- package/dist/default/playback/behaviors/dom/setup-mediasource.js +89 -0
- package/dist/default/playback/behaviors/dom/setup-mediasource.js.map +1 -0
- package/dist/default/playback/behaviors/dom/setup-text-track-actors.js +54 -0
- package/dist/default/playback/behaviors/dom/setup-text-track-actors.js.map +1 -0
- package/dist/default/playback/behaviors/dom/sync-text-tracks.js +99 -0
- package/dist/default/playback/behaviors/dom/sync-text-tracks.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-current-time.js +46 -0
- package/dist/default/playback/behaviors/dom/track-current-time.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-load-triggers.js +94 -0
- package/dist/default/playback/behaviors/dom/track-load-triggers.js.map +1 -0
- package/dist/default/playback/behaviors/dom/track-playback-rate.js +37 -0
- package/dist/default/playback/behaviors/dom/track-playback-rate.js.map +1 -0
- package/dist/default/playback/behaviors/dom/update-mediasource-duration.js +90 -0
- package/dist/default/playback/behaviors/dom/update-mediasource-duration.js.map +1 -0
- package/dist/default/playback/behaviors/quality-switching.js +96 -0
- package/dist/default/playback/behaviors/quality-switching.js.map +1 -0
- package/dist/default/playback/behaviors/resolve-presentation.js +85 -0
- package/dist/default/playback/behaviors/resolve-presentation.js.map +1 -0
- package/dist/default/playback/behaviors/resolve-track.js +97 -0
- package/dist/default/playback/behaviors/resolve-track.js.map +1 -0
- package/dist/default/playback/behaviors/select-tracks.js +132 -0
- package/dist/default/playback/behaviors/select-tracks.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-types.js +61 -0
- package/dist/default/playback/behaviors/track-types.js.map +1 -0
- package/dist/default/{dom/playback-engine → playback/engines/hls}/adapter.js +36 -25
- package/dist/default/playback/engines/hls/adapter.js.map +1 -0
- package/dist/default/playback/engines/hls/engine.js +102 -0
- package/dist/default/playback/engines/hls/engine.js.map +1 -0
- package/dist/dev/core/{actor.d.ts → actors/actor.d.ts} +2 -2
- package/dist/dev/core/actors/actor.d.ts.map +1 -0
- package/dist/dev/core/actors/create-machine-actor.d.ts +125 -0
- package/dist/dev/core/actors/create-machine-actor.d.ts.map +1 -0
- package/dist/{default/core → dev/core/actors}/create-machine-actor.js +3 -3
- package/dist/dev/core/actors/create-machine-actor.js.map +1 -0
- package/dist/dev/core/actors/create-transition-actor.d.ts +42 -0
- package/dist/dev/core/actors/create-transition-actor.d.ts.map +1 -0
- package/dist/dev/core/{create-transition-actor.js → actors/create-transition-actor.js} +3 -3
- package/dist/dev/core/actors/create-transition-actor.js.map +1 -0
- package/dist/dev/core/composition/create-composition.d.ts +274 -0
- package/dist/dev/core/composition/create-composition.d.ts.map +1 -0
- package/dist/dev/core/composition/create-composition.js +85 -0
- package/dist/dev/core/composition/create-composition.js.map +1 -0
- package/dist/dev/core/composition/share-signals.d.ts +45 -0
- package/dist/dev/core/composition/share-signals.d.ts.map +1 -0
- package/dist/dev/core/composition/share-signals.js +37 -0
- package/dist/dev/core/composition/share-signals.js.map +1 -0
- package/dist/dev/core/machine.d.ts +0 -1
- package/dist/dev/core/machine.d.ts.map +1 -1
- package/dist/dev/core/reactors/create-machine-reactor.d.ts +93 -0
- package/dist/dev/core/reactors/create-machine-reactor.d.ts.map +1 -0
- package/dist/{default/core → dev/core/reactors}/create-machine-reactor.js +4 -4
- package/dist/dev/core/reactors/create-machine-reactor.js.map +1 -0
- package/dist/dev/core/signals/primitives.d.ts +38 -1
- package/dist/dev/core/signals/primitives.d.ts.map +1 -1
- package/dist/dev/core/signals/primitives.js +33 -11
- package/dist/dev/core/signals/primitives.js.map +1 -1
- package/dist/dev/core/tasks/task.d.ts +115 -0
- package/dist/dev/core/tasks/task.d.ts.map +1 -0
- package/dist/dev/core/{task.js → tasks/task.js} +2 -2
- package/dist/dev/core/tasks/task.js.map +1 -0
- package/dist/dev/dom.d.ts +9 -10
- package/dist/dev/dom.js +9 -10
- package/dist/dev/hls.d.ts +3 -0
- package/dist/dev/hls.js +3 -0
- package/dist/dev/index.d.ts +15 -3
- package/dist/dev/index.d.ts.map +1 -1
- package/dist/dev/index.js +12 -3
- package/dist/dev/index.js.map +1 -1
- package/dist/dev/media/abr/quality-selection.d.ts +22 -0
- package/dist/dev/media/abr/quality-selection.d.ts.map +1 -0
- package/dist/dev/media/abr/quality-selection.js +83 -0
- package/dist/dev/media/abr/quality-selection.js.map +1 -0
- package/dist/dev/media/buffer/back-buffer.d.ts +14 -0
- package/dist/dev/media/buffer/back-buffer.d.ts.map +1 -0
- package/dist/dev/{core → media}/buffer/back-buffer.js +2 -2
- package/dist/dev/media/buffer/back-buffer.js.map +1 -0
- package/dist/dev/media/buffer/forward-buffer.d.ts +14 -0
- package/dist/dev/media/buffer/forward-buffer.d.ts.map +1 -0
- package/dist/{default/core → dev/media}/buffer/forward-buffer.js +14 -2
- package/dist/dev/media/buffer/forward-buffer.js.map +1 -0
- package/dist/dev/{dom/media → media/dom/mse}/append-segment.d.ts +1 -1
- package/dist/dev/media/dom/mse/append-segment.d.ts.map +1 -0
- package/dist/{default/dom/media → dev/media/dom/mse}/append-segment.js +1 -1
- package/dist/dev/media/dom/mse/append-segment.js.map +1 -0
- package/dist/dev/{dom/media → media/dom/mse}/buffer-flusher.d.ts +1 -1
- package/dist/dev/media/dom/mse/buffer-flusher.d.ts.map +1 -0
- package/dist/dev/{dom/media → media/dom/mse}/buffer-flusher.js +1 -1
- package/dist/dev/media/dom/mse/buffer-flusher.js.map +1 -0
- package/dist/dev/media/dom/mse/duration.js +78 -0
- package/dist/dev/media/dom/mse/duration.js.map +1 -0
- package/dist/dev/media/dom/mse/end-of-stream.js +20 -0
- package/dist/dev/media/dom/mse/end-of-stream.js.map +1 -0
- package/dist/dev/{dom/media → media/dom/mse}/mediasource-setup.js +63 -18
- package/dist/dev/media/dom/mse/mediasource-setup.js.map +1 -0
- package/dist/dev/media/dom/text/resolve-vtt-segment.d.ts +12 -0
- package/dist/dev/media/dom/text/resolve-vtt-segment.d.ts.map +1 -0
- package/dist/dev/{dom/text/parse-vtt-segment.js → media/dom/text/resolve-vtt-segment.js} +5 -5
- package/dist/dev/media/dom/text/resolve-vtt-segment.js.map +1 -0
- package/dist/dev/media/dom/text/text-track-slots.d.ts +31 -0
- package/dist/dev/media/dom/text/text-track-slots.d.ts.map +1 -0
- package/dist/dev/media/dom/text/text-track-slots.js +69 -0
- package/dist/dev/media/dom/text/text-track-slots.js.map +1 -0
- package/dist/{default/core → dev/media}/hls/parse-attributes.js +1 -1
- package/dist/dev/media/hls/parse-attributes.js.map +1 -0
- package/dist/{default/core → dev/media}/hls/parse-media-playlist.js +1 -1
- package/dist/dev/media/hls/parse-media-playlist.js.map +1 -0
- package/dist/{default/core → dev/media}/hls/parse-multivariant.js +2 -2
- package/dist/dev/media/hls/parse-multivariant.js.map +1 -0
- package/dist/dev/{core → media}/hls/resolve-url.js +1 -1
- package/dist/dev/media/hls/resolve-url.js.map +1 -0
- package/dist/dev/media/primitives/select-tracks.js +45 -0
- package/dist/dev/media/primitives/select-tracks.js.map +1 -0
- package/dist/dev/{core → media}/types/index.d.ts +30 -2
- package/dist/dev/media/types/index.d.ts.map +1 -0
- package/dist/dev/media/types/index.js +36 -0
- package/dist/dev/media/types/index.js.map +1 -0
- package/dist/dev/media/utils/preload.js +22 -0
- package/dist/dev/media/utils/preload.js.map +1 -0
- package/dist/dev/media/utils/track-selection.js +47 -0
- package/dist/dev/media/utils/track-selection.js.map +1 -0
- package/dist/dev/media/utils/tracks.js +103 -0
- package/dist/dev/media/utils/tracks.js.map +1 -0
- package/dist/dev/{core/abr → network}/bandwidth-estimator.d.ts +17 -2
- package/dist/dev/network/bandwidth-estimator.d.ts.map +1 -0
- package/dist/dev/{core/abr → network}/bandwidth-estimator.js +6 -5
- package/dist/dev/network/bandwidth-estimator.js.map +1 -0
- package/dist/{default/dom → dev}/network/chunked-stream-iterable.js +1 -1
- package/dist/dev/network/chunked-stream-iterable.js.map +1 -0
- package/dist/{default/core/abr → dev/network}/ewma.js +1 -1
- package/dist/dev/network/ewma.js.map +1 -0
- package/dist/dev/network/fetch.js +109 -0
- package/dist/dev/network/fetch.js.map +1 -0
- package/dist/dev/playback/actors/dom/segment-loader.d.ts +36 -0
- package/dist/dev/playback/actors/dom/segment-loader.d.ts.map +1 -0
- package/dist/{default/dom/features/segment-loader-actor.js → dev/playback/actors/dom/segment-loader.js} +24 -15
- package/dist/dev/playback/actors/dom/segment-loader.js.map +1 -0
- package/dist/dev/{dom/media/source-buffer-actor.d.ts → playback/actors/dom/source-buffer.d.ts} +5 -5
- package/dist/dev/playback/actors/dom/source-buffer.d.ts.map +1 -0
- package/dist/{default/dom/media/source-buffer-actor.js → dev/playback/actors/dom/source-buffer.js} +8 -8
- package/dist/dev/playback/actors/dom/source-buffer.js.map +1 -0
- package/dist/dev/playback/actors/dom/text-tracks.d.ts +1 -0
- package/dist/{default/dom/features/text-tracks-actor.js → dev/playback/actors/dom/text-tracks.js} +7 -3
- package/dist/dev/playback/actors/dom/text-tracks.js.map +1 -0
- package/dist/dev/playback/actors/text-track-segment-loader.d.ts +59 -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 +135 -0
- package/dist/dev/playback/actors/text-track-segment-loader.js.map +1 -0
- package/dist/dev/playback/actors/text-tracks.d.ts +42 -0
- package/dist/dev/playback/actors/text-tracks.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.d.ts +17 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.js +58 -0
- package/dist/dev/playback/behaviors/calculate-presentation-duration.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/end-of-stream.js +178 -0
- package/dist/dev/playback/behaviors/dom/end-of-stream.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/load-segments.d.ts +62 -0
- package/dist/dev/playback/behaviors/dom/load-segments.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/load-segments.js +177 -0
- package/dist/dev/playback/behaviors/dom/load-segments.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/setup-buffer-actors.js +173 -0
- package/dist/dev/playback/behaviors/dom/setup-buffer-actors.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/setup-mediasource.js +89 -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 +31 -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 +54 -0
- package/dist/dev/playback/behaviors/dom/setup-text-track-actors.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/sync-text-tracks.js +99 -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 +34 -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 +46 -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 +48 -0
- package/dist/dev/playback/behaviors/dom/track-load-triggers.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-load-triggers.js +94 -0
- package/dist/dev/playback/behaviors/dom/track-load-triggers.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-playback-rate.d.ts +34 -0
- package/dist/dev/playback/behaviors/dom/track-playback-rate.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/dom/track-playback-rate.js +37 -0
- package/dist/dev/playback/behaviors/dom/track-playback-rate.js.map +1 -0
- package/dist/dev/playback/behaviors/dom/update-mediasource-duration.js +90 -0
- package/dist/dev/playback/behaviors/dom/update-mediasource-duration.js.map +1 -0
- package/dist/dev/playback/behaviors/quality-switching.js +96 -0
- package/dist/dev/playback/behaviors/quality-switching.js.map +1 -0
- package/dist/dev/playback/behaviors/resolve-presentation.d.ts +7 -0
- package/dist/dev/playback/behaviors/resolve-presentation.d.ts.map +1 -0
- package/dist/dev/playback/behaviors/resolve-presentation.js +85 -0
- package/dist/dev/playback/behaviors/resolve-presentation.js.map +1 -0
- package/dist/dev/playback/behaviors/resolve-track.js +97 -0
- package/dist/dev/playback/behaviors/resolve-track.js.map +1 -0
- package/dist/dev/playback/behaviors/select-tracks.js +132 -0
- package/dist/dev/playback/behaviors/select-tracks.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-types.js +61 -0
- package/dist/dev/playback/behaviors/track-types.js.map +1 -0
- package/dist/dev/{dom/playback-engine → playback/engines/hls}/adapter.d.ts +14 -10
- package/dist/dev/playback/engines/hls/adapter.d.ts.map +1 -0
- package/dist/dev/{dom/playback-engine → playback/engines/hls}/adapter.js +36 -25
- package/dist/dev/playback/engines/hls/adapter.js.map +1 -0
- package/dist/dev/playback/engines/hls/engine.d.ts +177 -0
- package/dist/dev/playback/engines/hls/engine.d.ts.map +1 -0
- package/dist/dev/playback/engines/hls/engine.js +102 -0
- package/dist/dev/playback/engines/hls/engine.js.map +1 -0
- package/package.json +8 -9
- package/dist/default/core/abr/bandwidth-estimator.js.map +0 -1
- package/dist/default/core/abr/ewma.js.map +0 -1
- package/dist/default/core/abr/quality-selection.js +0 -53
- package/dist/default/core/abr/quality-selection.js.map +0 -1
- package/dist/default/core/buffer/back-buffer.js.map +0 -1
- package/dist/default/core/buffer/forward-buffer.js.map +0 -1
- package/dist/default/core/create-machine-actor.js.map +0 -1
- package/dist/default/core/create-machine-reactor.js.map +0 -1
- package/dist/default/core/create-transition-actor.js.map +0 -1
- package/dist/default/core/features/calculate-presentation-duration.js +0 -53
- package/dist/default/core/features/calculate-presentation-duration.js.map +0 -1
- package/dist/default/core/features/quality-switching.js +0 -69
- package/dist/default/core/features/quality-switching.js.map +0 -1
- package/dist/default/core/features/resolve-presentation.js +0 -73
- package/dist/default/core/features/resolve-presentation.js.map +0 -1
- package/dist/default/core/features/resolve-track.js +0 -66
- package/dist/default/core/features/resolve-track.js.map +0 -1
- package/dist/default/core/features/select-tracks.js +0 -130
- package/dist/default/core/features/select-tracks.js.map +0 -1
- package/dist/default/core/features/sync-preload-attribute.js +0 -26
- package/dist/default/core/features/sync-preload-attribute.js.map +0 -1
- package/dist/default/core/hls/parse-attributes.js.map +0 -1
- package/dist/default/core/hls/parse-media-playlist.js.map +0 -1
- package/dist/default/core/hls/parse-multivariant.js.map +0 -1
- package/dist/default/core/hls/resolve-url.js.map +0 -1
- package/dist/default/core/task.js.map +0 -1
- package/dist/default/core/types/index.js +0 -15
- package/dist/default/core/types/index.js.map +0 -1
- package/dist/default/core/utils/generate-id.js +0 -21
- package/dist/default/core/utils/generate-id.js.map +0 -1
- package/dist/default/core/utils/track-selection.js +0 -39
- package/dist/default/core/utils/track-selection.js.map +0 -1
- package/dist/default/dom/features/end-of-stream.js +0 -145
- package/dist/default/dom/features/end-of-stream.js.map +0 -1
- package/dist/default/dom/features/load-segments.js +0 -192
- package/dist/default/dom/features/load-segments.js.map +0 -1
- package/dist/default/dom/features/load-text-track-cues.js +0 -104
- package/dist/default/dom/features/load-text-track-cues.js.map +0 -1
- package/dist/default/dom/features/segment-loader-actor.js.map +0 -1
- package/dist/default/dom/features/setup-mediasource.js +0 -48
- package/dist/default/dom/features/setup-mediasource.js.map +0 -1
- package/dist/default/dom/features/setup-sourcebuffer.js +0 -78
- package/dist/default/dom/features/setup-sourcebuffer.js.map +0 -1
- package/dist/default/dom/features/sync-text-tracks.js +0 -95
- package/dist/default/dom/features/sync-text-tracks.js.map +0 -1
- package/dist/default/dom/features/text-track-segment-loader-actor.js +0 -55
- package/dist/default/dom/features/text-track-segment-loader-actor.js.map +0 -1
- package/dist/default/dom/features/text-tracks-actor.js.map +0 -1
- package/dist/default/dom/features/track-current-time.js +0 -49
- package/dist/default/dom/features/track-current-time.js.map +0 -1
- package/dist/default/dom/features/track-playback-initiated.js +0 -66
- package/dist/default/dom/features/track-playback-initiated.js.map +0 -1
- package/dist/default/dom/features/track-playback-rate.js +0 -32
- package/dist/default/dom/features/track-playback-rate.js.map +0 -1
- package/dist/default/dom/features/update-duration.js +0 -78
- package/dist/default/dom/features/update-duration.js.map +0 -1
- package/dist/default/dom/media/append-segment.js.map +0 -1
- package/dist/default/dom/media/buffer-flusher.js.map +0 -1
- package/dist/default/dom/media/mediasource-setup.js.map +0 -1
- package/dist/default/dom/media/source-buffer-actor.js.map +0 -1
- package/dist/default/dom/network/chunked-stream-iterable.js.map +0 -1
- package/dist/default/dom/network/fetch.js +0 -54
- package/dist/default/dom/network/fetch.js.map +0 -1
- package/dist/default/dom/playback-engine/adapter.js.map +0 -1
- package/dist/default/dom/playback-engine/engine.js +0 -142
- package/dist/default/dom/playback-engine/engine.js.map +0 -1
- package/dist/default/dom/playback-engine.js +0 -4
- package/dist/default/dom/text/parse-vtt-segment.js.map +0 -1
- package/dist/dev/core/abr/bandwidth-estimator.d.ts.map +0 -1
- package/dist/dev/core/abr/bandwidth-estimator.js.map +0 -1
- package/dist/dev/core/abr/ewma.js.map +0 -1
- package/dist/dev/core/abr/quality-selection.js +0 -53
- package/dist/dev/core/abr/quality-selection.js.map +0 -1
- package/dist/dev/core/actor.d.ts.map +0 -1
- package/dist/dev/core/buffer/back-buffer.js.map +0 -1
- package/dist/dev/core/buffer/forward-buffer.js.map +0 -1
- package/dist/dev/core/create-machine-actor.d.ts +0 -12
- package/dist/dev/core/create-machine-actor.d.ts.map +0 -1
- package/dist/dev/core/create-machine-actor.js.map +0 -1
- package/dist/dev/core/create-machine-reactor.d.ts +0 -8
- package/dist/dev/core/create-machine-reactor.d.ts.map +0 -1
- package/dist/dev/core/create-machine-reactor.js.map +0 -1
- package/dist/dev/core/create-transition-actor.d.ts +0 -23
- package/dist/dev/core/create-transition-actor.d.ts.map +0 -1
- package/dist/dev/core/create-transition-actor.js.map +0 -1
- package/dist/dev/core/features/calculate-presentation-duration.js +0 -53
- package/dist/dev/core/features/calculate-presentation-duration.js.map +0 -1
- package/dist/dev/core/features/quality-switching.js +0 -69
- package/dist/dev/core/features/quality-switching.js.map +0 -1
- package/dist/dev/core/features/resolve-presentation.js +0 -73
- package/dist/dev/core/features/resolve-presentation.js.map +0 -1
- package/dist/dev/core/features/resolve-track.js +0 -66
- package/dist/dev/core/features/resolve-track.js.map +0 -1
- package/dist/dev/core/features/select-tracks.js +0 -130
- package/dist/dev/core/features/select-tracks.js.map +0 -1
- package/dist/dev/core/features/sync-preload-attribute.js +0 -26
- package/dist/dev/core/features/sync-preload-attribute.js.map +0 -1
- package/dist/dev/core/hls/parse-attributes.js.map +0 -1
- package/dist/dev/core/hls/parse-media-playlist.js.map +0 -1
- package/dist/dev/core/hls/parse-multivariant.js.map +0 -1
- package/dist/dev/core/hls/resolve-url.js.map +0 -1
- package/dist/dev/core/task.js.map +0 -1
- package/dist/dev/core/types/index.d.ts.map +0 -1
- package/dist/dev/core/types/index.js +0 -15
- package/dist/dev/core/types/index.js.map +0 -1
- package/dist/dev/core/utils/generate-id.js +0 -21
- package/dist/dev/core/utils/generate-id.js.map +0 -1
- package/dist/dev/core/utils/track-selection.d.ts +0 -16
- package/dist/dev/core/utils/track-selection.d.ts.map +0 -1
- package/dist/dev/core/utils/track-selection.js +0 -39
- package/dist/dev/core/utils/track-selection.js.map +0 -1
- package/dist/dev/dom/features/end-of-stream.js +0 -145
- package/dist/dev/dom/features/end-of-stream.js.map +0 -1
- package/dist/dev/dom/features/load-segments.d.ts +0 -72
- package/dist/dev/dom/features/load-segments.d.ts.map +0 -1
- package/dist/dev/dom/features/load-segments.js +0 -192
- package/dist/dev/dom/features/load-segments.js.map +0 -1
- package/dist/dev/dom/features/load-text-track-cues.d.ts +0 -85
- package/dist/dev/dom/features/load-text-track-cues.d.ts.map +0 -1
- package/dist/dev/dom/features/load-text-track-cues.js +0 -104
- package/dist/dev/dom/features/load-text-track-cues.js.map +0 -1
- package/dist/dev/dom/features/segment-loader-actor.d.ts +0 -1
- package/dist/dev/dom/features/segment-loader-actor.js.map +0 -1
- package/dist/dev/dom/features/setup-mediasource.js +0 -48
- package/dist/dev/dom/features/setup-mediasource.js.map +0 -1
- package/dist/dev/dom/features/setup-sourcebuffer.d.ts +0 -9
- package/dist/dev/dom/features/setup-sourcebuffer.d.ts.map +0 -1
- package/dist/dev/dom/features/setup-sourcebuffer.js +0 -78
- package/dist/dev/dom/features/setup-sourcebuffer.js.map +0 -1
- package/dist/dev/dom/features/sync-text-tracks.js +0 -95
- package/dist/dev/dom/features/sync-text-tracks.js.map +0 -1
- package/dist/dev/dom/features/text-track-segment-loader-actor.d.ts +0 -12
- package/dist/dev/dom/features/text-track-segment-loader-actor.d.ts.map +0 -1
- package/dist/dev/dom/features/text-track-segment-loader-actor.js +0 -55
- package/dist/dev/dom/features/text-track-segment-loader-actor.js.map +0 -1
- package/dist/dev/dom/features/text-tracks-actor.d.ts +0 -31
- package/dist/dev/dom/features/text-tracks-actor.d.ts.map +0 -1
- package/dist/dev/dom/features/text-tracks-actor.js.map +0 -1
- package/dist/dev/dom/features/track-current-time.d.ts +0 -40
- package/dist/dev/dom/features/track-current-time.d.ts.map +0 -1
- package/dist/dev/dom/features/track-current-time.js +0 -49
- package/dist/dev/dom/features/track-current-time.js.map +0 -1
- package/dist/dev/dom/features/track-playback-initiated.d.ts +0 -46
- package/dist/dev/dom/features/track-playback-initiated.d.ts.map +0 -1
- package/dist/dev/dom/features/track-playback-initiated.js +0 -66
- package/dist/dev/dom/features/track-playback-initiated.js.map +0 -1
- package/dist/dev/dom/features/track-playback-rate.d.ts +0 -34
- package/dist/dev/dom/features/track-playback-rate.d.ts.map +0 -1
- package/dist/dev/dom/features/track-playback-rate.js +0 -32
- package/dist/dev/dom/features/track-playback-rate.js.map +0 -1
- package/dist/dev/dom/features/update-duration.js +0 -78
- package/dist/dev/dom/features/update-duration.js.map +0 -1
- package/dist/dev/dom/media/append-segment.d.ts.map +0 -1
- package/dist/dev/dom/media/append-segment.js.map +0 -1
- package/dist/dev/dom/media/buffer-flusher.d.ts.map +0 -1
- package/dist/dev/dom/media/buffer-flusher.js.map +0 -1
- package/dist/dev/dom/media/mediasource-setup.js.map +0 -1
- package/dist/dev/dom/media/source-buffer-actor.d.ts.map +0 -1
- package/dist/dev/dom/media/source-buffer-actor.js.map +0 -1
- package/dist/dev/dom/network/chunked-stream-iterable.js.map +0 -1
- package/dist/dev/dom/network/fetch.js +0 -54
- package/dist/dev/dom/network/fetch.js.map +0 -1
- package/dist/dev/dom/playback-engine/adapter.d.ts.map +0 -1
- package/dist/dev/dom/playback-engine/adapter.js.map +0 -1
- package/dist/dev/dom/playback-engine/engine.d.ts +0 -124
- package/dist/dev/dom/playback-engine/engine.d.ts.map +0 -1
- package/dist/dev/dom/playback-engine/engine.js +0 -142
- package/dist/dev/dom/playback-engine/engine.js.map +0 -1
- package/dist/dev/dom/playback-engine.d.ts +0 -4
- package/dist/dev/dom/playback-engine.js +0 -4
- package/dist/dev/dom/text/parse-vtt-segment.d.ts +0 -12
- package/dist/dev/dom/text/parse-vtt-segment.d.ts.map +0 -1
- package/dist/dev/dom/text/parse-vtt-segment.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-segments.js","names":[],"sources":["../../../../../src/playback/behaviors/dom/load-segments.ts"],"sourcesContent":["/**\n * **Per-type segment loading dispatch.** Per available track type (video /\n * audio / text), reads the per-type segment-loader actor from context and\n * sends typed `'load'` messages whenever a meaningful loading condition\n * changes (selected track, current time crossing a segment boundary).\n *\n * Loader-actor lifecycle is owned upstream:\n * - Video: `setupVideoBufferActors`\n * - Audio: `setupAudioBufferActors`\n * - Text: `setupTextTrackActors`\n *\n * This behavior is pure-consumer: it reads `context[loaderKey]` and\n * dispatches typed messages via the variant's per-type `findResolvedTrack`\n * resolver.\n *\n * # Load modes as reactor states\n *\n * Four states encode the load-gating policy directly:\n *\n * - `'preconditions-unmet'` — no loader actor in context, or the selected\n * track hasn't resolved.\n * - `'dormant'` — `preload === 'none' && !loadActivated`. Nothing fires.\n * - `'metadata-only'` — `!loadActivated && preload !== 'auto' && preload !== 'none'`.\n * Fires an init-segment-only `load` message **once on entry**. The\n * variant's loader actor decides what to do — v/a's actor fetches the\n * init segment; text's actor no-ops (no init concept).\n * - `'full-range'` — `loadActivated || preload === 'auto'`. Effect re-fires\n * on selected-track change and on segment-boundary crossing.\n *\n * # Per-type parameterization (inference-driven)\n *\n * The helper is generic over `Track` — the resolved-track type. Each\n * variant supplies its own `findResolvedTrack` resolver via config; TS\n * infers `Track` from the resolver's return type. The loader signal's\n * value type is constrained to `SegmentLoaderLike<Track>` — anything with\n * a `send` method accepting the `Track`-parameterized message. Concrete\n * actor types (`SegmentLoaderActor`, `TextTrackSegmentLoaderActor`)\n * satisfy this via function-parameter contravariance: an actor whose\n * `.send` accepts a wider track type is assignable to a slot expecting a\n * narrower track type.\n *\n * No widening of actor message types is needed; no casts inside the\n * helper. Per-variant wiring (right loader paired with right resolver)\n * is enforced at the variant call site.\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, peek, type ReadonlySignal } from '../../../core/signals/primitives';\nimport {\n DEFAULT_FORWARD_BUFFER_CONFIG,\n type ForwardBufferConfig,\n segmentStartForTime,\n} from '../../../media/buffer/forward-buffer';\nimport type { MaybeResolvedPresentation, Segment } from '../../../media/types';\nimport { findResolvedAudioTrack, findResolvedTextTrack, findResolvedVideoTrack } from '../../../media/utils/tracks';\nimport type { BufferState, SegmentLoaderActor, SourceBufferState } from '../../actors/dom/segment-loader';\nimport type { TextTrackSegmentLoaderActor } from '../../actors/text-track-segment-loader';\nimport { AUDIO_TYPE_CONFIG, TEXT_TYPE_CONFIG, VIDEO_TYPE_CONFIG } from '../track-types';\n\n// Re-export buffer state types for consumers that import them from this module.\nexport type { BufferState, SourceBufferState };\n\n// ============================================================================\n// STATE & CONTEXT\n// ============================================================================\n\n/** State shape for segment loading. */\nexport interface SegmentLoadingState {\n presentation?: MaybeResolvedPresentation;\n preload?: string;\n /** Current playback position in seconds. Defaults to 0 when undefined. */\n currentTime?: number;\n /** True once a preload-overriding event has fired for the current source. */\n loadActivated?: boolean;\n selectedVideoTrackId?: string;\n selectedAudioTrackId?: string;\n selectedTextTrackId?: string;\n}\n\n/** Context shape for segment loading. Each variant only consumes its own type's loader actor. */\nexport interface SegmentLoadingContext {\n videoSegmentLoaderActor?: SegmentLoaderActor;\n audioSegmentLoaderActor?: SegmentLoaderActor;\n textTrackSegmentLoaderActor?: TextTrackSegmentLoaderActor;\n}\n\n// ============================================================================\n// REACTOR\n// ============================================================================\n\ntype SegmentLoadingFsmState = 'preconditions-unmet' | 'dormant' | 'metadata-only' | 'full-range';\n\ntype SelectedTrackKey = 'selectedVideoTrackId' | 'selectedAudioTrackId' | 'selectedTextTrackId';\ntype SegmentLoaderActorKey = 'videoSegmentLoaderActor' | 'audioSegmentLoaderActor' | 'textTrackSegmentLoaderActor';\n\ntype SegmentLoadingStateMap<K extends SelectedTrackKey> = {\n presentation: ReadonlySignal<SegmentLoadingState['presentation']>;\n preload: ReadonlySignal<SegmentLoadingState['preload']>;\n currentTime: ReadonlySignal<SegmentLoadingState['currentTime']>;\n loadActivated: ReadonlySignal<SegmentLoadingState['loadActivated']>;\n} & { [P in K]: ReadonlySignal<SegmentLoadingState[P]> };\n\n/** Shared `'load'` message shape parameterized over the resolved track type. */\ninterface LoadMessage<Track> {\n type: 'load';\n track: Track;\n range?: { start: number; end: number };\n}\n\n/** Structural constraint for any segment-loader-style actor. */\ninterface SegmentLoaderLike<Track> {\n send: (message: LoadMessage<Track>) => void;\n}\n\n/**\n * Specialization helper. Generic over `Track` (inferred from\n * `findResolvedTrack`'s return type). The loader value type is\n * constrained to `SegmentLoaderLike<Track>` — concrete actor types\n * (whose `.send` accepts a wider track union) satisfy this via\n * function-parameter contravariance.\n *\n * Tracks that the helper handles must have a `segments` field — used by\n * `segmentBoundarySignal` to compute the load-anchor boundary. Each\n * variant's resolver narrows to the right resolved-track shape.\n */\nfunction setupSegmentLoading<\n K extends SelectedTrackKey,\n L extends SegmentLoaderActorKey,\n Track extends { segments: readonly Segment[] },\n>({\n state,\n context,\n config,\n}: {\n state: SegmentLoadingStateMap<K>;\n context: { [P in L]: ReadonlySignal<SegmentLoaderLike<Track> | undefined> };\n config: {\n selectedKey: K;\n loaderKey: L;\n findResolvedTrack: (\n presentation: MaybeResolvedPresentation | undefined,\n trackId: string | undefined\n ) => Track | undefined;\n forwardBuffer?: Partial<ForwardBufferConfig>;\n };\n}): Reactor<SegmentLoadingFsmState | 'destroying' | 'destroyed'> {\n const { selectedKey, loaderKey, findResolvedTrack } = config;\n const bufferDuration = config.forwardBuffer?.bufferDuration ?? DEFAULT_FORWARD_BUFFER_CONFIG.bufferDuration;\n\n const selectedTrack = computed<Track | undefined>(() =>\n findResolvedTrack(state.presentation.get(), state[selectedKey].get())\n );\n\n // Segment-boundary signal — `segmentStartForTime` returns the same number\n // while `currentTime` stays inside one segment, so signal-polyfill's\n // `Object.is` equality on this computed dedups within-segment ticks.\n const segmentBoundarySignal = computed(() => {\n const track = selectedTrack.get();\n if (!track) return undefined;\n return segmentStartForTime(state.currentTime.get() ?? 0, track.segments);\n });\n\n const derivedStateSignal = computed<SegmentLoadingFsmState>(() => {\n if (!context[loaderKey].get() || !selectedTrack.get()) return 'preconditions-unmet';\n if (state.loadActivated.get() || state.preload.get() === 'auto') return 'full-range';\n if (state.preload.get() === 'none') return 'dormant';\n return 'metadata-only';\n });\n\n return createMachineReactor<SegmentLoadingFsmState>({\n initial: 'preconditions-unmet',\n monitor: () => derivedStateSignal.get(),\n states: {\n 'preconditions-unmet': {},\n dormant: {},\n 'metadata-only': {\n // Fires once on entry. Matches HTMLMediaElement's preload='metadata'\n // semantics — load enough to surface metadata for the entry-time\n // selection. Each variant's loader decides what to do: v/a's actor\n // fetches the init segment; text's actor treats no-range as a\n // no-op. Selection changes while still in `'metadata-only'` are\n // intentionally not followed.\n entry: () => {\n const track = selectedTrack.get()!;\n context[loaderKey].get()!.send({ type: 'load', track });\n },\n },\n 'full-range': {\n // Re-fires on selected-track changes and on segment-boundary\n // crossings. The loader and `currentTime` are peeked — the\n // boundary-dedup signal already handles re-firing policy.\n effects: () => {\n const track = selectedTrack.get()!;\n segmentBoundarySignal.get();\n const currentTime = peek(state.currentTime) ?? 0;\n peek(context[loaderKey])!.send({\n type: 'load',\n track,\n range: { start: currentTime, end: currentTime + bufferDuration },\n });\n },\n },\n },\n });\n}\n\n// ============================================================================\n// Per-helper-per-type configs — defaults that variants spread engine config over\n// ============================================================================\n\nconst VIDEO_SEGMENT_LOADING_CONFIG = {\n ...VIDEO_TYPE_CONFIG,\n findResolvedTrack: findResolvedVideoTrack,\n} as const;\n\nconst AUDIO_SEGMENT_LOADING_CONFIG = {\n ...AUDIO_TYPE_CONFIG,\n findResolvedTrack: findResolvedAudioTrack,\n} as const;\n\nconst TEXT_SEGMENT_LOADING_CONFIG = {\n ...TEXT_TYPE_CONFIG,\n findResolvedTrack: findResolvedTextTrack,\n} as const;\n\n// ============================================================================\n// Specialized exports — one per media type\n// ============================================================================\n\nexport const loadVideoSegments = defineBehavior({\n stateKeys: ['presentation', 'preload', 'currentTime', 'loadActivated', 'selectedVideoTrackId'],\n contextKeys: ['videoSegmentLoaderActor'],\n setup: ({\n state,\n context,\n config = {},\n }: {\n state: SegmentLoadingStateMap<'selectedVideoTrackId'>;\n context: {\n videoSegmentLoaderActor: ReadonlySignal<SegmentLoadingContext['videoSegmentLoaderActor']>;\n };\n config?: object;\n }) =>\n setupSegmentLoading({\n state,\n context,\n config: { ...VIDEO_SEGMENT_LOADING_CONFIG, ...config },\n }),\n});\n\nexport const loadAudioSegments = defineBehavior({\n stateKeys: ['presentation', 'preload', 'currentTime', 'loadActivated', 'selectedAudioTrackId'],\n contextKeys: ['audioSegmentLoaderActor'],\n setup: ({\n state,\n context,\n config = {},\n }: {\n state: SegmentLoadingStateMap<'selectedAudioTrackId'>;\n context: {\n audioSegmentLoaderActor: ReadonlySignal<SegmentLoadingContext['audioSegmentLoaderActor']>;\n };\n config?: object;\n }) =>\n setupSegmentLoading({\n state,\n context,\n config: { ...AUDIO_SEGMENT_LOADING_CONFIG, ...config },\n }),\n});\n\nexport const loadTextTrackSegments = defineBehavior({\n stateKeys: ['presentation', 'preload', 'currentTime', 'loadActivated', 'selectedTextTrackId'],\n contextKeys: ['textTrackSegmentLoaderActor'],\n setup: ({\n state,\n context,\n config = {},\n }: {\n state: SegmentLoadingStateMap<'selectedTextTrackId'>;\n context: {\n textTrackSegmentLoaderActor: ReadonlySignal<SegmentLoadingContext['textTrackSegmentLoaderActor']>;\n };\n config?: object;\n }) =>\n setupSegmentLoading({\n state,\n context,\n config: { ...TEXT_SEGMENT_LOADING_CONFIG, ...config },\n }),\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8HA,SAAS,oBAIP,EACA,OACA,SACA,UAa+D;CAC/D,MAAM,EAAE,aAAa,WAAW,sBAAsB;CACtD,MAAM,iBAAiB,OAAO,eAAe,kBAAkB,8BAA8B;CAE7F,MAAM,gBAAgB,eACpB,kBAAkB,MAAM,aAAa,KAAK,EAAE,MAAM,aAAa,KAAK,CAAC,CACtE;CAKD,MAAM,wBAAwB,eAAe;EAC3C,MAAM,QAAQ,cAAc,KAAK;AACjC,MAAI,CAAC,MAAO,QAAO,KAAA;AACnB,SAAO,oBAAoB,MAAM,YAAY,KAAK,IAAI,GAAG,MAAM,SAAS;GACxE;CAEF,MAAM,qBAAqB,eAAuC;AAChE,MAAI,CAAC,QAAQ,WAAW,KAAK,IAAI,CAAC,cAAc,KAAK,CAAE,QAAO;AAC9D,MAAI,MAAM,cAAc,KAAK,IAAI,MAAM,QAAQ,KAAK,KAAK,OAAQ,QAAO;AACxE,MAAI,MAAM,QAAQ,KAAK,KAAK,OAAQ,QAAO;AAC3C,SAAO;GACP;AAEF,QAAO,qBAA6C;EAClD,SAAS;EACT,eAAe,mBAAmB,KAAK;EACvC,QAAQ;GACN,uBAAuB,EAAE;GACzB,SAAS,EAAE;GACX,iBAAiB,EAOf,aAAa;IACX,MAAM,QAAQ,cAAc,KAAK;AACjC,YAAQ,WAAW,KAAK,CAAE,KAAK;KAAE,MAAM;KAAQ;KAAO,CAAC;MAE1D;GACD,cAAc,EAIZ,eAAe;IACb,MAAM,QAAQ,cAAc,KAAK;AACjC,0BAAsB,KAAK;IAC3B,MAAM,cAAc,KAAK,MAAM,YAAY,IAAI;AAC/C,SAAK,QAAQ,WAAW,CAAE,KAAK;KAC7B,MAAM;KACN;KACA,OAAO;MAAE,OAAO;MAAa,KAAK,cAAc;MAAgB;KACjE,CAAC;MAEL;GACF;EACF,CAAC;;AAOJ,MAAM,+BAA+B;CACnC,GAAG;CACH,mBAAmB;CACpB;AAED,MAAM,+BAA+B;CACnC,GAAG;CACH,mBAAmB;CACpB;AAED,MAAM,8BAA8B;CAClC,GAAG;CACH,mBAAmB;CACpB;AAMD,MAAa,oBAAoB,eAAe;CAC9C,WAAW;EAAC;EAAgB;EAAW;EAAe;EAAiB;EAAuB;CAC9F,aAAa,CAAC,0BAA0B;CACxC,QAAQ,EACN,OACA,SACA,SAAS,EAAE,OAQX,oBAAoB;EAClB;EACA;EACA,QAAQ;GAAE,GAAG;GAA8B,GAAG;GAAQ;EACvD,CAAC;CACL,CAAC;AAEF,MAAa,oBAAoB,eAAe;CAC9C,WAAW;EAAC;EAAgB;EAAW;EAAe;EAAiB;EAAuB;CAC9F,aAAa,CAAC,0BAA0B;CACxC,QAAQ,EACN,OACA,SACA,SAAS,EAAE,OAQX,oBAAoB;EAClB;EACA;EACA,QAAQ;GAAE,GAAG;GAA8B,GAAG;GAAQ;EACvD,CAAC;CACL,CAAC;AAEF,MAAa,wBAAwB,eAAe;CAClD,WAAW;EAAC;EAAgB;EAAW;EAAe;EAAiB;EAAsB;CAC7F,aAAa,CAAC,8BAA8B;CAC5C,QAAQ,EACN,OACA,SACA,SAAS,EAAE,OAQX,oBAAoB;EAClB;EACA;EACA,QAAQ;GAAE,GAAG;GAA6B,GAAG;GAAQ;EACtD,CAAC;CACL,CAAC"}
|
|
@@ -0,0 +1,173 @@
|
|
|
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 { hasCodecs } from "../../../media/utils/tracks.js";
|
|
5
|
+
import { AUDIO_TYPE_CONFIG, VIDEO_TYPE_CONFIG } from "../track-types.js";
|
|
6
|
+
import { getSelectedTrack } from "../../../media/utils/track-selection.js";
|
|
7
|
+
import { buildMimeCodec, createSourceBuffer } from "../../../media/dom/mse/mediasource-setup.js";
|
|
8
|
+
import { createTrackedFetch, fetchStream } from "../../../network/fetch.js";
|
|
9
|
+
import { createSegmentLoaderActor } from "../../actors/dom/segment-loader.js";
|
|
10
|
+
import { createSourceBufferActor } from "../../actors/dom/source-buffer.js";
|
|
11
|
+
//#region src/playback/behaviors/dom/setup-buffer-actors.ts
|
|
12
|
+
/**
|
|
13
|
+
* **Per-type buffer + segment-loader actor setup.** Per available track
|
|
14
|
+
* type (video / audio), when `mediaSource` is attached and the selected
|
|
15
|
+
* track of that type is present in the presentation with codecs (partial
|
|
16
|
+
* resolution from the multivariant playlist is enough — codecs live on
|
|
17
|
+
* the `EXT-X-STREAM-INF` line, not in the per-type media playlist),
|
|
18
|
+
* creates a `SourceBuffer`, a `SourceBufferActor`, and a
|
|
19
|
+
* `SegmentLoaderActor` bound to that buffer-actor; publishes the per-type
|
|
20
|
+
* actor slots. On `mediaSource` detach or behavior destroy, destroys both
|
|
21
|
+
* actors in reverse order and clears the per-type slots so the next
|
|
22
|
+
* source starts fresh.
|
|
23
|
+
*
|
|
24
|
+
* Each per-type variant (`setupVideoBufferActors` /
|
|
25
|
+
* `setupAudioBufferActors`) is a single-positive-state reactor
|
|
26
|
+
* (`'preconditions-unmet'` ↔ `'buffer-ready'`) gating only on its own
|
|
27
|
+
* type. No cross-type coupling in `stateKeys` —
|
|
28
|
+
* `setupVideoBufferActors` carries only `selectedVideoTrackId` (plus
|
|
29
|
+
* `bandwidthState`, written by its trackedFetch), and audio mirrors.
|
|
30
|
+
*
|
|
31
|
+
* # Firefox `mozHasAudio` invariant
|
|
32
|
+
*
|
|
33
|
+
* Appending to a video `SourceBuffer` before the audio `SourceBuffer`
|
|
34
|
+
* exists causes `mozHasAudio` to be permanently false in Firefox. With
|
|
35
|
+
* the two per-type variants decoupled, the invariant is no longer
|
|
36
|
+
* structural to a single `entry` body (as it was when both buffers were
|
|
37
|
+
* created in one synchronous block inside a merged behavior). It's now
|
|
38
|
+
* preserved by a chain of assumptions about how this behavior composes
|
|
39
|
+
* with its upstream and downstream siblings:
|
|
40
|
+
*
|
|
41
|
+
* 1. **Upstream — default selections land in one `runPending`.**
|
|
42
|
+
* `selectAudioTrack` (default audio) and `switchVideoQuality`
|
|
43
|
+
* (default video) both subscribe to `state.presentation` flipping to
|
|
44
|
+
* resolved; their effects run in the same `runPending` iteration and
|
|
45
|
+
* write `selectedAudioTrackId` + `selectedVideoTrackId` within it.
|
|
46
|
+
* 2. **Self — both per-type monitors flip in one `runPending`.**
|
|
47
|
+
* After (1), both monitors re-evaluate and flip to `'buffer-ready'`
|
|
48
|
+
* in the next `runPending`. Both `entry` bodies run synchronously
|
|
49
|
+
* within that iteration — both `addSourceBuffer` calls land before
|
|
50
|
+
* the iteration ends.
|
|
51
|
+
* 3. **Downstream — `appendBuffer` is async.** `loadVideoSegments` /
|
|
52
|
+
* `loadAudioSegments` read the per-type `xSegmentLoaderActor` slots;
|
|
53
|
+
* their effects fire in the *next* `runPending` and the actual
|
|
54
|
+
* `appendBuffer` requires a network round-trip via the
|
|
55
|
+
* `SegmentLoaderActor` — many microtasks past both `addSourceBuffer`
|
|
56
|
+
* calls.
|
|
57
|
+
*
|
|
58
|
+
* The cross-tick failure mode — a user-initiated audio track switch
|
|
59
|
+
* *after* video segments have begun appending — is out of scope for
|
|
60
|
+
* this behavior and would be addressed in the buffer/segment-loading
|
|
61
|
+
* path via `changeType`-aware logic.
|
|
62
|
+
*
|
|
63
|
+
* # Sole writer
|
|
64
|
+
*
|
|
65
|
+
* `setupVideoBufferActors` is sole writer of `videoBufferActor` +
|
|
66
|
+
* `videoSegmentLoaderActor` (and `bandwidthState` via its
|
|
67
|
+
* trackedFetch); `setupAudioBufferActors` is sole writer of
|
|
68
|
+
* `audioBufferActor` + `audioSegmentLoaderActor`. Both read
|
|
69
|
+
* `mediaSource` from `setupMediaSource`. Downstream MSE behaviors
|
|
70
|
+
* (`loadVideoSegments`, `loadAudioSegments`, `endOfStream`,
|
|
71
|
+
* `updateMediaSourceDuration`) only read these slots.
|
|
72
|
+
*/
|
|
73
|
+
function setupBufferActors({ state, context, config }) {
|
|
74
|
+
const { type, selectedKey, actorKey, loaderKey, fetch, forwardBuffer, backBuffer } = config;
|
|
75
|
+
const derivedStateSignal = computed(() => {
|
|
76
|
+
if (!context.mediaSource.get()) return "preconditions-unmet";
|
|
77
|
+
return hasCodecs(getSelectedTrack({
|
|
78
|
+
presentation: state.presentation.get(),
|
|
79
|
+
[selectedKey]: state[selectedKey].get()
|
|
80
|
+
}, type)) ? "buffer-ready" : "preconditions-unmet";
|
|
81
|
+
});
|
|
82
|
+
return createMachineReactor({
|
|
83
|
+
initial: "preconditions-unmet",
|
|
84
|
+
monitor: () => derivedStateSignal.get(),
|
|
85
|
+
states: {
|
|
86
|
+
"preconditions-unmet": {},
|
|
87
|
+
"buffer-ready": { entry: () => {
|
|
88
|
+
const bufferActor = createSourceBufferActor(createSourceBuffer(context.mediaSource.get(), buildMimeCodec(getSelectedTrack({
|
|
89
|
+
presentation: state.presentation.get(),
|
|
90
|
+
[selectedKey]: state[selectedKey].get()
|
|
91
|
+
}, type))));
|
|
92
|
+
const segmentLoader = createSegmentLoaderActor(bufferActor, fetch, {
|
|
93
|
+
forwardBuffer,
|
|
94
|
+
backBuffer
|
|
95
|
+
});
|
|
96
|
+
context[actorKey].set(bufferActor);
|
|
97
|
+
context[loaderKey].set(segmentLoader);
|
|
98
|
+
return () => {
|
|
99
|
+
segmentLoader.destroy();
|
|
100
|
+
bufferActor.destroy();
|
|
101
|
+
context[loaderKey].set(void 0);
|
|
102
|
+
context[actorKey].set(void 0);
|
|
103
|
+
};
|
|
104
|
+
} }
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Set up the video `SourceBufferActor` + `SegmentLoaderActor`. Fires
|
|
110
|
+
* when `mediaSource` is attached and the selected video track is
|
|
111
|
+
* present in the presentation with codecs. Gates only on video state —
|
|
112
|
+
* no cross-type coupling. Owns a bandwidth-sampling `trackedFetch` and
|
|
113
|
+
* is sole writer of `state.bandwidthState`.
|
|
114
|
+
*/
|
|
115
|
+
const setupVideoBufferActors = defineBehavior({
|
|
116
|
+
stateKeys: [
|
|
117
|
+
"presentation",
|
|
118
|
+
"selectedVideoTrackId",
|
|
119
|
+
"bandwidthState"
|
|
120
|
+
],
|
|
121
|
+
contextKeys: [
|
|
122
|
+
"mediaSource",
|
|
123
|
+
"videoBufferActor",
|
|
124
|
+
"videoSegmentLoaderActor"
|
|
125
|
+
],
|
|
126
|
+
setup: ({ state, context, config = {} }) => {
|
|
127
|
+
const trackedFetch = createTrackedFetch(state.bandwidthState.get() ?? {
|
|
128
|
+
fastEstimate: 0,
|
|
129
|
+
fastTotalWeight: 0,
|
|
130
|
+
slowEstimate: 0,
|
|
131
|
+
slowTotalWeight: 0,
|
|
132
|
+
bytesSampled: 0
|
|
133
|
+
}, (next) => state.bandwidthState.set(next));
|
|
134
|
+
return setupBufferActors({
|
|
135
|
+
state,
|
|
136
|
+
context,
|
|
137
|
+
config: {
|
|
138
|
+
...VIDEO_TYPE_CONFIG,
|
|
139
|
+
fetch: trackedFetch,
|
|
140
|
+
...config
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
/**
|
|
146
|
+
* Set up the audio `SourceBufferActor` + `SegmentLoaderActor`. Same
|
|
147
|
+
* shape as `setupVideoBufferActors`, narrowed to audio. Today supplies
|
|
148
|
+
* a non-sampling `fetchStream` (no audio ABR); adding audio ABR is a
|
|
149
|
+
* localized change to this setup body (swap `fetchStream` for a
|
|
150
|
+
* `createTrackedFetch` call + declare `bandwidthState` writable here)
|
|
151
|
+
* without touching the shared helper.
|
|
152
|
+
*/
|
|
153
|
+
const setupAudioBufferActors = defineBehavior({
|
|
154
|
+
stateKeys: ["presentation", "selectedAudioTrackId"],
|
|
155
|
+
contextKeys: [
|
|
156
|
+
"mediaSource",
|
|
157
|
+
"audioBufferActor",
|
|
158
|
+
"audioSegmentLoaderActor"
|
|
159
|
+
],
|
|
160
|
+
setup: ({ state, context, config = {} }) => setupBufferActors({
|
|
161
|
+
state,
|
|
162
|
+
context,
|
|
163
|
+
config: {
|
|
164
|
+
...AUDIO_TYPE_CONFIG,
|
|
165
|
+
fetch: fetchStream,
|
|
166
|
+
...config
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
});
|
|
170
|
+
//#endregion
|
|
171
|
+
export { setupAudioBufferActors, setupVideoBufferActors };
|
|
172
|
+
|
|
173
|
+
//# sourceMappingURL=setup-buffer-actors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-buffer-actors.js","names":[],"sources":["../../../../../src/playback/behaviors/dom/setup-buffer-actors.ts"],"sourcesContent":["/**\n * **Per-type buffer + segment-loader actor setup.** Per available track\n * type (video / audio), when `mediaSource` is attached and the selected\n * track of that type is present in the presentation with codecs (partial\n * resolution from the multivariant playlist is enough — codecs live on\n * the `EXT-X-STREAM-INF` line, not in the per-type media playlist),\n * creates a `SourceBuffer`, a `SourceBufferActor`, and a\n * `SegmentLoaderActor` bound to that buffer-actor; publishes the per-type\n * actor slots. On `mediaSource` detach or behavior destroy, destroys both\n * actors in reverse order and clears the per-type slots so the next\n * source starts fresh.\n *\n * Each per-type variant (`setupVideoBufferActors` /\n * `setupAudioBufferActors`) is a single-positive-state reactor\n * (`'preconditions-unmet'` ↔ `'buffer-ready'`) gating only on its own\n * type. No cross-type coupling in `stateKeys` —\n * `setupVideoBufferActors` carries only `selectedVideoTrackId` (plus\n * `bandwidthState`, written by its trackedFetch), and audio mirrors.\n *\n * # Firefox `mozHasAudio` invariant\n *\n * Appending to a video `SourceBuffer` before the audio `SourceBuffer`\n * exists causes `mozHasAudio` to be permanently false in Firefox. With\n * the two per-type variants decoupled, the invariant is no longer\n * structural to a single `entry` body (as it was when both buffers were\n * created in one synchronous block inside a merged behavior). It's now\n * preserved by a chain of assumptions about how this behavior composes\n * with its upstream and downstream siblings:\n *\n * 1. **Upstream — default selections land in one `runPending`.**\n * `selectAudioTrack` (default audio) and `switchVideoQuality`\n * (default video) both subscribe to `state.presentation` flipping to\n * resolved; their effects run in the same `runPending` iteration and\n * write `selectedAudioTrackId` + `selectedVideoTrackId` within it.\n * 2. **Self — both per-type monitors flip in one `runPending`.**\n * After (1), both monitors re-evaluate and flip to `'buffer-ready'`\n * in the next `runPending`. Both `entry` bodies run synchronously\n * within that iteration — both `addSourceBuffer` calls land before\n * the iteration ends.\n * 3. **Downstream — `appendBuffer` is async.** `loadVideoSegments` /\n * `loadAudioSegments` read the per-type `xSegmentLoaderActor` slots;\n * their effects fire in the *next* `runPending` and the actual\n * `appendBuffer` requires a network round-trip via the\n * `SegmentLoaderActor` — many microtasks past both `addSourceBuffer`\n * calls.\n *\n * The cross-tick failure mode — a user-initiated audio track switch\n * *after* video segments have begun appending — is out of scope for\n * this behavior and would be addressed in the buffer/segment-loading\n * path via `changeType`-aware logic.\n *\n * # Sole writer\n *\n * `setupVideoBufferActors` is sole writer of `videoBufferActor` +\n * `videoSegmentLoaderActor` (and `bandwidthState` via its\n * trackedFetch); `setupAudioBufferActors` is sole writer of\n * `audioBufferActor` + `audioSegmentLoaderActor`. Both read\n * `mediaSource` from `setupMediaSource`. Downstream MSE behaviors\n * (`loadVideoSegments`, `loadAudioSegments`, `endOfStream`,\n * `updateMediaSourceDuration`) only read these slots.\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 { buildMimeCodec, createSourceBuffer } from '../../../media/dom/mse/mediasource-setup';\nimport type { MaybeResolvedPresentation, PartiallyResolvedTrack } from '../../../media/types';\nimport { getSelectedTrack, type TrackSelectionState } from '../../../media/utils/track-selection';\nimport { hasCodecs } from '../../../media/utils/tracks';\nimport type { BandwidthState } from '../../../network/bandwidth-estimator';\nimport { createTrackedFetch, type FetchBytes, fetchStream } from '../../../network/fetch';\nimport {\n createSegmentLoaderActor,\n type SegmentLoaderActor,\n type SegmentLoaderActorConfig,\n} from '../../actors/dom/segment-loader';\nimport { createSourceBufferActor, type SourceBufferActor } from '../../actors/dom/source-buffer';\nimport { AUDIO_TYPE_CONFIG, VIDEO_TYPE_CONFIG } from '../track-types';\n\n/**\n * Media track type for MSE buffer setup.\n * Text tracks are excluded as they don't use MSE SourceBuffers.\n */\nexport type MediaTrackType = 'video' | 'audio';\n\nexport interface BufferActorsState {\n presentation?: MaybeResolvedPresentation;\n selectedVideoTrackId?: string;\n selectedAudioTrackId?: string;\n bandwidthState?: BandwidthState;\n}\n\nexport interface BufferActorsContext {\n mediaSource?: MediaSource;\n videoBufferActor?: SourceBufferActor;\n audioBufferActor?: SourceBufferActor;\n videoSegmentLoaderActor?: SegmentLoaderActor;\n audioSegmentLoaderActor?: SegmentLoaderActor;\n}\n\ntype BufferActorsFsmState = 'preconditions-unmet' | 'buffer-ready';\n\ntype SelectedTrackKey = 'selectedVideoTrackId' | 'selectedAudioTrackId';\ntype BufferActorKey = 'videoBufferActor' | 'audioBufferActor';\ntype SegmentLoaderActorKey = 'videoSegmentLoaderActor' | 'audioSegmentLoaderActor';\n\ntype BufferActorsStateMap<K extends SelectedTrackKey> = {\n presentation: ReadonlySignal<BufferActorsState['presentation']>;\n} & { [P in K]: ReadonlySignal<BufferActorsState[P]> };\n\ntype BufferActorsContextMap<A extends BufferActorKey, L extends SegmentLoaderActorKey> = {\n mediaSource: ReadonlySignal<BufferActorsContext['mediaSource']>;\n} & { [P in A]: Signal<SourceBufferActor | undefined> } & {\n [P in L]: Signal<SegmentLoaderActor | undefined>;\n};\n\n// ============================================================================\n// Specialization helper\n//\n// `setupBufferActors` has the same shape as a Behavior `setup` function:\n// `({ state, context, config }) => reactor`. Each `setupXBufferActors`\n// export below calls it from inside its own `defineBehavior` setup,\n// passing its narrowed `state` / `context` through directly and supplying\n// the per-type `selectedKey`, `actorKey`, `loaderKey`, `type` discriminator,\n// and `fetch` inline.\n//\n// Gating is per-type only: no cross-type coupling. See the file-level\n// JSDoc for how the Firefox `mozHasAudio` invariant survives the split\n// via SPF's effect coalescing.\n// ============================================================================\n\nfunction setupBufferActors<K extends SelectedTrackKey, A extends BufferActorKey, L extends SegmentLoaderActorKey>({\n state,\n context,\n config,\n}: {\n state: BufferActorsStateMap<K>;\n context: BufferActorsContextMap<A, L>;\n config: {\n type: MediaTrackType;\n selectedKey: K;\n actorKey: A;\n loaderKey: L;\n fetch: FetchBytes;\n } & SegmentLoaderActorConfig;\n}): Reactor<BufferActorsFsmState | 'destroying' | 'destroyed'> {\n const { type, selectedKey, actorKey, loaderKey, fetch, forwardBuffer, backBuffer } = config;\n const derivedStateSignal = computed<BufferActorsFsmState>(() => {\n if (!context.mediaSource.get()) return 'preconditions-unmet';\n const selection: TrackSelectionState = {\n presentation: state.presentation.get(),\n [selectedKey]: state[selectedKey].get(),\n };\n return hasCodecs(getSelectedTrack(selection, type)) ? 'buffer-ready' : 'preconditions-unmet';\n });\n\n return createMachineReactor<BufferActorsFsmState>({\n initial: 'preconditions-unmet',\n monitor: () => derivedStateSignal.get(),\n states: {\n 'preconditions-unmet': {},\n\n 'buffer-ready': {\n entry: () => {\n const mediaSource = context.mediaSource.get()!;\n const selection: TrackSelectionState = {\n presentation: state.presentation.get(),\n [selectedKey]: state[selectedKey].get(),\n };\n const track = getSelectedTrack(selection, type) as PartiallyResolvedTrack;\n const buffer = createSourceBuffer(mediaSource, buildMimeCodec(track));\n const bufferActor = createSourceBufferActor(buffer);\n const segmentLoader = createSegmentLoaderActor(bufferActor, fetch, { forwardBuffer, backBuffer });\n\n // Synchronous slot writes — load-bearing for the Firefox\n // `mozHasAudio` invariant (see file-level JSDoc). Both per-type\n // entries' `addSourceBuffer` calls must land in the same\n // `runPending` iteration; synchronous writes keep the contiguous\n // JS frame. Downstream `loadXSegments` effects fire in the\n // *next* `runPending`.\n context[actorKey].set(bufferActor);\n context[loaderKey].set(segmentLoader);\n\n // State-exit cleanup — fires when `mediaSource` detaches, the\n // selection unsets, or the behavior is destroyed. Destroy the\n // loader before its upstream buffer-actor so any in-flight\n // `appendBuffer` is aborted before the buffer-actor's own\n // teardown.\n return () => {\n segmentLoader.destroy();\n bufferActor.destroy();\n context[loaderKey].set(undefined);\n context[actorKey].set(undefined);\n };\n },\n },\n },\n });\n}\n\n// ============================================================================\n// Specialized exports — one per media type\n// ============================================================================\n\n/**\n * Set up the video `SourceBufferActor` + `SegmentLoaderActor`. Fires\n * when `mediaSource` is attached and the selected video track is\n * present in the presentation with codecs. Gates only on video state —\n * no cross-type coupling. Owns a bandwidth-sampling `trackedFetch` and\n * is sole writer of `state.bandwidthState`.\n */\nexport const setupVideoBufferActors = defineBehavior({\n stateKeys: ['presentation', 'selectedVideoTrackId', 'bandwidthState'] as const,\n contextKeys: ['mediaSource', 'videoBufferActor', 'videoSegmentLoaderActor'] as const,\n setup: ({\n state,\n context,\n config = {},\n }: {\n state: BufferActorsStateMap<'selectedVideoTrackId'> & {\n bandwidthState: Signal<BufferActorsState['bandwidthState']>;\n };\n context: BufferActorsContextMap<'videoBufferActor', 'videoSegmentLoaderActor'>;\n config?: object;\n }) => {\n // Bandwidth-sampling fetch. The factory accumulates EWMA state\n // internally; the callback bridges samples to engine state for ABR.\n // Created once at behavior setup time so the EWMA accumulates across\n // source resets (each per-source loader-actor receives the same\n // tracked fetch when reconstructed in `buffer-ready` entry).\n const trackedFetch = createTrackedFetch(\n state.bandwidthState.get() ?? {\n fastEstimate: 0,\n fastTotalWeight: 0,\n slowEstimate: 0,\n slowTotalWeight: 0,\n bytesSampled: 0,\n },\n (next) => state.bandwidthState.set(next)\n );\n return setupBufferActors({\n state,\n context,\n config: { ...VIDEO_TYPE_CONFIG, fetch: trackedFetch, ...config },\n });\n },\n});\n\n/**\n * Set up the audio `SourceBufferActor` + `SegmentLoaderActor`. Same\n * shape as `setupVideoBufferActors`, narrowed to audio. Today supplies\n * a non-sampling `fetchStream` (no audio ABR); adding audio ABR is a\n * localized change to this setup body (swap `fetchStream` for a\n * `createTrackedFetch` call + declare `bandwidthState` writable here)\n * without touching the shared helper.\n */\nexport const setupAudioBufferActors = defineBehavior({\n stateKeys: ['presentation', 'selectedAudioTrackId'] as const,\n contextKeys: ['mediaSource', 'audioBufferActor', 'audioSegmentLoaderActor'] as const,\n setup: ({\n state,\n context,\n config = {},\n }: {\n state: BufferActorsStateMap<'selectedAudioTrackId'>;\n context: BufferActorsContextMap<'audioBufferActor', 'audioSegmentLoaderActor'>;\n config?: object;\n }) =>\n setupBufferActors({\n state,\n context,\n config: { ...AUDIO_TYPE_CONFIG, fetch: fetchStream, ...config },\n }),\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmIA,SAAS,kBAAyG,EAChH,OACA,SACA,UAW6D;CAC7D,MAAM,EAAE,MAAM,aAAa,UAAU,WAAW,OAAO,eAAe,eAAe;CACrF,MAAM,qBAAqB,eAAqC;AAC9D,MAAI,CAAC,QAAQ,YAAY,KAAK,CAAE,QAAO;AAKvC,SAAO,UAAU,iBAJsB;GACrC,cAAc,MAAM,aAAa,KAAK;IACrC,cAAc,MAAM,aAAa,KAAK;GACxC,EAC4C,KAAK,CAAC,GAAG,iBAAiB;GACvE;AAEF,QAAO,qBAA2C;EAChD,SAAS;EACT,eAAe,mBAAmB,KAAK;EACvC,QAAQ;GACN,uBAAuB,EAAE;GAEzB,gBAAgB,EACd,aAAa;IAQX,MAAM,cAAc,wBADL,mBANK,QAAQ,YAAY,KAAK,EAME,eADjC,iBAJyB;KACrC,cAAc,MAAM,aAAa,KAAK;MACrC,cAAc,MAAM,aAAa,KAAK;KACxC,EACyC,KAAK,CACqB,CAAC,CAClB;IACnD,MAAM,gBAAgB,yBAAyB,aAAa,OAAO;KAAE;KAAe;KAAY,CAAC;AAQjG,YAAQ,UAAU,IAAI,YAAY;AAClC,YAAQ,WAAW,IAAI,cAAc;AAOrC,iBAAa;AACX,mBAAc,SAAS;AACvB,iBAAY,SAAS;AACrB,aAAQ,WAAW,IAAI,KAAA,EAAU;AACjC,aAAQ,UAAU,IAAI,KAAA,EAAU;;MAGrC;GACF;EACF,CAAC;;;;;;;;;AAcJ,MAAa,yBAAyB,eAAe;CACnD,WAAW;EAAC;EAAgB;EAAwB;EAAiB;CACrE,aAAa;EAAC;EAAe;EAAoB;EAA0B;CAC3E,QAAQ,EACN,OACA,SACA,SAAS,EAAE,OAOP;EAMJ,MAAM,eAAe,mBACnB,MAAM,eAAe,KAAK,IAAI;GAC5B,cAAc;GACd,iBAAiB;GACjB,cAAc;GACd,iBAAiB;GACjB,cAAc;GACf,GACA,SAAS,MAAM,eAAe,IAAI,KAAK,CACzC;AACD,SAAO,kBAAkB;GACvB;GACA;GACA,QAAQ;IAAE,GAAG;IAAmB,OAAO;IAAc,GAAG;IAAQ;GACjE,CAAC;;CAEL,CAAC;;;;;;;;;AAUF,MAAa,yBAAyB,eAAe;CACnD,WAAW,CAAC,gBAAgB,uBAAuB;CACnD,aAAa;EAAC;EAAe;EAAoB;EAA0B;CAC3E,QAAQ,EACN,OACA,SACA,SAAS,EAAE,OAMX,kBAAkB;EAChB;EACA;EACA,QAAQ;GAAE,GAAG;GAAmB,OAAO;GAAa,GAAG;GAAQ;EAChE,CAAC;CACL,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
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 { attachMediaSource, createMediaSource, waitForMediaSourceOpen } from "../../../media/dom/mse/mediasource-setup.js";
|
|
6
|
+
//#region src/playback/behaviors/dom/setup-mediasource.ts
|
|
7
|
+
/**
|
|
8
|
+
* **Own the MediaSource lifecycle for the current source.** When a resolved
|
|
9
|
+
* presentation and a mediaElement are both in scope, creates a MediaSource,
|
|
10
|
+
* attaches it to the element, waits for `'open'`, and publishes it on
|
|
11
|
+
* `context.mediaSource`. On source change or behavior destroy, detaches the
|
|
12
|
+
* MediaSource and clears the slot so the next source starts fresh.
|
|
13
|
+
*
|
|
14
|
+
* Single-positive-state reactor (`'preconditions-unmet'` ↔ `'mediasource-attached'`):
|
|
15
|
+
* state derivation gates on `mediaElement + isResolvedPresentation`. Riding the
|
|
16
|
+
* resolver's resolved/unresolved lifecycle makes direct URL replacement
|
|
17
|
+
* structural — `resolvePresentation` routes the presentation back through
|
|
18
|
+
* unresolved on URL change, which drives this reactor through
|
|
19
|
+
* `'preconditions-unmet'` so the entry's state-exit cleanup detaches the old
|
|
20
|
+
* MediaSource before the new one is built.
|
|
21
|
+
*
|
|
22
|
+
* The entry resolves preconditions in sequence before publishing:
|
|
23
|
+
*
|
|
24
|
+
* 1. **Create + attach** — `createMediaSource` + `attachMediaSource` run
|
|
25
|
+
* synchronously on entry. The `detach` closure returned by
|
|
26
|
+
* `attachMediaSource` is captured for state-exit cleanup, so the cleanup
|
|
27
|
+
* is always bound to its setup even if the wait below is aborted.
|
|
28
|
+
* 2. **Wait for `'open'`** — `waitForMediaSourceOpen` defers until the first
|
|
29
|
+
* `sourceopen` event (or any readyState transition out of `'closed'`).
|
|
30
|
+
* 3. **Publish on `'open'`** — re-check `readyState === 'open'` after the
|
|
31
|
+
* await (covers `'ended'` / `'closed'` race) before writing to
|
|
32
|
+
* `context.mediaSource`. Downstream `setupVideoBufferActors` /
|
|
33
|
+
* `setupAudioBufferActors` call `addSourceBuffer` directly, which
|
|
34
|
+
* throws on non-open, so publish-only-when-open is the load-bearing
|
|
35
|
+
* contract.
|
|
36
|
+
*
|
|
37
|
+
* State-exit cleanup aborts the in-flight wait, detaches the MediaSource,
|
|
38
|
+
* and clears `context.mediaSource`. Order: abort first (prevents a late
|
|
39
|
+
* publish racing the slot clear), then detach, then clear.
|
|
40
|
+
*
|
|
41
|
+
* Sole writer of `context.mediaSource`; other MSE behaviors
|
|
42
|
+
* (`setupVideoBufferActors`, `setupAudioBufferActors`,
|
|
43
|
+
* `updateMediaSourceDuration`, `endOfStream`, `loadVideoSegments`) only
|
|
44
|
+
* read.
|
|
45
|
+
*/
|
|
46
|
+
function deriveState(presentation, mediaElement) {
|
|
47
|
+
if (!mediaElement || !isResolvedPresentation(presentation)) return "preconditions-unmet";
|
|
48
|
+
return "mediasource-attached";
|
|
49
|
+
}
|
|
50
|
+
function setupMediaSourceSetup({ state, context }) {
|
|
51
|
+
const derivedStateSignal = computed(() => deriveState(state.presentation.get(), context.mediaElement.get()));
|
|
52
|
+
return createMachineReactor({
|
|
53
|
+
initial: "preconditions-unmet",
|
|
54
|
+
monitor: () => derivedStateSignal.get(),
|
|
55
|
+
states: {
|
|
56
|
+
"preconditions-unmet": {},
|
|
57
|
+
"mediasource-attached": { entry: () => {
|
|
58
|
+
const mediaElement = context.mediaElement.get();
|
|
59
|
+
const controller = new AbortController();
|
|
60
|
+
const mediaSource = createMediaSource({ preferManaged: true });
|
|
61
|
+
const { detach } = attachMediaSource(mediaSource, mediaElement);
|
|
62
|
+
const publishWhenOpen = async () => {
|
|
63
|
+
await waitForMediaSourceOpen(mediaSource, controller.signal);
|
|
64
|
+
if (controller.signal.aborted) return;
|
|
65
|
+
if (mediaSource.readyState !== "open") {
|
|
66
|
+
console.warn(`[setupMediaSource] MediaSource transitioned to '${mediaSource.readyState}' before first 'sourceopen' — slot left unpublished; recoverable on next source reset.`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
context.mediaSource.set(mediaSource);
|
|
70
|
+
};
|
|
71
|
+
publishWhenOpen().catch((err) => console.error("[setupMediaSource] failed to publish MediaSource:", err));
|
|
72
|
+
return () => {
|
|
73
|
+
controller.abort();
|
|
74
|
+
detach();
|
|
75
|
+
context.mediaSource.set(void 0);
|
|
76
|
+
};
|
|
77
|
+
} }
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
const setupMediaSource = defineBehavior({
|
|
82
|
+
stateKeys: ["presentation"],
|
|
83
|
+
contextKeys: ["mediaElement", "mediaSource"],
|
|
84
|
+
setup: setupMediaSourceSetup
|
|
85
|
+
});
|
|
86
|
+
//#endregion
|
|
87
|
+
export { setupMediaSource };
|
|
88
|
+
|
|
89
|
+
//# sourceMappingURL=setup-mediasource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-mediasource.js","names":[],"sources":["../../../../../src/playback/behaviors/dom/setup-mediasource.ts"],"sourcesContent":["/**\n * **Own the MediaSource lifecycle for the current source.** When a resolved\n * presentation and a mediaElement are both in scope, creates a MediaSource,\n * attaches it to the element, waits for `'open'`, and publishes it on\n * `context.mediaSource`. On source change or behavior destroy, detaches the\n * MediaSource and clears the slot so the next source starts fresh.\n *\n * Single-positive-state reactor (`'preconditions-unmet'` ↔ `'mediasource-attached'`):\n * state derivation gates on `mediaElement + isResolvedPresentation`. Riding the\n * resolver's resolved/unresolved lifecycle makes direct URL replacement\n * structural — `resolvePresentation` routes the presentation back through\n * unresolved on URL change, which drives this reactor through\n * `'preconditions-unmet'` so the entry's state-exit cleanup detaches the old\n * MediaSource before the new one is built.\n *\n * The entry resolves preconditions in sequence before publishing:\n *\n * 1. **Create + attach** — `createMediaSource` + `attachMediaSource` run\n * synchronously on entry. The `detach` closure returned by\n * `attachMediaSource` is captured for state-exit cleanup, so the cleanup\n * is always bound to its setup even if the wait below is aborted.\n * 2. **Wait for `'open'`** — `waitForMediaSourceOpen` defers until the first\n * `sourceopen` event (or any readyState transition out of `'closed'`).\n * 3. **Publish on `'open'`** — re-check `readyState === 'open'` after the\n * await (covers `'ended'` / `'closed'` race) before writing to\n * `context.mediaSource`. Downstream `setupVideoBufferActors` /\n * `setupAudioBufferActors` call `addSourceBuffer` directly, which\n * throws on non-open, so publish-only-when-open is the load-bearing\n * contract.\n *\n * State-exit cleanup aborts the in-flight wait, detaches the MediaSource,\n * and clears `context.mediaSource`. Order: abort first (prevents a late\n * publish racing the slot clear), then detach, then clear.\n *\n * Sole writer of `context.mediaSource`; other MSE behaviors\n * (`setupVideoBufferActors`, `setupAudioBufferActors`,\n * `updateMediaSourceDuration`, `endOfStream`, `loadVideoSegments`) only\n * read.\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 { attachMediaSource, createMediaSource, waitForMediaSourceOpen } from '../../../media/dom/mse/mediasource-setup';\nimport { isResolvedPresentation, type MaybeResolvedPresentation } from '../../../media/types';\n\n/**\n * State shape required for MediaSource setup.\n */\nexport interface MediaSourceState {\n presentation?: MaybeResolvedPresentation;\n}\n\n/**\n * Context shape for MediaSource setup.\n */\nexport interface MediaSourceContext {\n mediaElement?: HTMLMediaElement | undefined;\n mediaSource?: MediaSource;\n}\n\ntype MediaSourceFsmState = 'preconditions-unmet' | 'mediasource-attached';\n\nfunction deriveState(\n presentation: MaybeResolvedPresentation | undefined,\n mediaElement: HTMLMediaElement | undefined\n): MediaSourceFsmState {\n if (!mediaElement || !isResolvedPresentation(presentation)) return 'preconditions-unmet';\n return 'mediasource-attached';\n}\n\nfunction setupMediaSourceSetup({\n state,\n context,\n}: {\n state: {\n presentation: ReadonlySignal<MediaSourceState['presentation']>;\n };\n context: {\n mediaElement: ReadonlySignal<MediaSourceContext['mediaElement']>;\n mediaSource: Signal<MediaSourceContext['mediaSource']>;\n };\n}): Reactor<MediaSourceFsmState | 'destroying' | 'destroyed'> {\n const derivedStateSignal = computed(() => deriveState(state.presentation.get(), context.mediaElement.get()));\n\n return createMachineReactor<MediaSourceFsmState>({\n initial: 'preconditions-unmet',\n monitor: () => derivedStateSignal.get(),\n states: {\n 'preconditions-unmet': {},\n\n 'mediasource-attached': {\n // entry body is auto-untracked. deriveState handles source resets via\n // the resolver's resolved/unresolved transitions; this entry creates\n // and attaches the MediaSource, awaits `'open'`, publishes on\n // context, and binds detach + slot clear to state exit + destroy.\n entry: () => {\n const mediaElement = context.mediaElement.get()!;\n const controller = new AbortController();\n\n const mediaSource = createMediaSource({ preferManaged: true });\n // Sync attach: the returned `detach` closes over the element +\n // object-URL captured at this moment, so state-exit cleanup tears\n // down exactly this attachment regardless of how the wait below\n // resolves.\n const { detach } = attachMediaSource(mediaSource, mediaElement);\n\n const publishWhenOpen = async () => {\n await waitForMediaSourceOpen(mediaSource, controller.signal);\n if (controller.signal.aborted) return;\n // `waitForMediaSourceOpen` resolves on any readyState transition\n // out of `'closed'`; if we landed in `'ended'` / `'closed'`\n // instead of `'open'`, the attach window is gone and we leave\n // the slot unpublished. The session is dead within this source\n // either way — publishing wouldn't help because\n // `setupVideoBufferActors` / `setupAudioBufferActors` calls\n // `addSourceBuffer` which throws on non-open. The next\n // source-reset re-enters this state with a fresh MediaSource\n // and recovers. Warn so the case is at least diagnosable; in\n // practice it requires the MediaSource to close/end before its\n // very first `sourceopen`, which a freshly attached MS\n // shouldn't do.\n if (mediaSource.readyState !== 'open') {\n console.warn(\n `[setupMediaSource] MediaSource transitioned to '${mediaSource.readyState}' before first 'sourceopen' — slot left unpublished; recoverable on next source reset.`\n );\n return;\n }\n context.mediaSource.set(mediaSource);\n };\n\n publishWhenOpen().catch((err) => console.error('[setupMediaSource] failed to publish MediaSource:', err));\n\n return () => {\n // Order matters: abort the wait first so a late publish can't\n // race the slot clear; then detach to release the element; then\n // clear the slot so downstream behaviors see no MediaSource.\n controller.abort();\n detach();\n context.mediaSource.set(undefined);\n };\n },\n },\n },\n });\n}\n\nexport const setupMediaSource = defineBehavior({\n stateKeys: ['presentation'],\n contextKeys: ['mediaElement', 'mediaSource'],\n setup: setupMediaSourceSetup,\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DA,SAAS,YACP,cACA,cACqB;AACrB,KAAI,CAAC,gBAAgB,CAAC,uBAAuB,aAAa,CAAE,QAAO;AACnE,QAAO;;AAGT,SAAS,sBAAsB,EAC7B,OACA,WAS4D;CAC5D,MAAM,qBAAqB,eAAe,YAAY,MAAM,aAAa,KAAK,EAAE,QAAQ,aAAa,KAAK,CAAC,CAAC;AAE5G,QAAO,qBAA0C;EAC/C,SAAS;EACT,eAAe,mBAAmB,KAAK;EACvC,QAAQ;GACN,uBAAuB,EAAE;GAEzB,wBAAwB,EAKtB,aAAa;IACX,MAAM,eAAe,QAAQ,aAAa,KAAK;IAC/C,MAAM,aAAa,IAAI,iBAAiB;IAExC,MAAM,cAAc,kBAAkB,EAAE,eAAe,MAAM,CAAC;IAK9D,MAAM,EAAE,WAAW,kBAAkB,aAAa,aAAa;IAE/D,MAAM,kBAAkB,YAAY;AAClC,WAAM,uBAAuB,aAAa,WAAW,OAAO;AAC5D,SAAI,WAAW,OAAO,QAAS;AAa/B,SAAI,YAAY,eAAe,QAAQ;AACrC,cAAQ,KACN,mDAAmD,YAAY,WAAW,wFAC3E;AACD;;AAEF,aAAQ,YAAY,IAAI,YAAY;;AAGtC,qBAAiB,CAAC,OAAO,QAAQ,QAAQ,MAAM,qDAAqD,IAAI,CAAC;AAEzG,iBAAa;AAIX,gBAAW,OAAO;AAClB,aAAQ;AACR,aAAQ,YAAY,IAAI,KAAA,EAAU;;MAGvC;GACF;EACF,CAAC;;AAGJ,MAAa,mBAAmB,eAAe;CAC7C,WAAW,CAAC,eAAe;CAC3B,aAAa,CAAC,gBAAgB,cAAc;CAC5C,OAAO;CACR,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ReadonlySignal, Signal } from "../../../core/signals/primitives.js";
|
|
2
|
+
import { TextTracksActor } from "../../actors/text-tracks.js";
|
|
3
|
+
import { TextTrackSegmentLoaderActor, TextTrackSegmentLoaderActorConfig, TextTrackSegmentResolver } from "../../actors/text-track-segment-loader.js";
|
|
4
|
+
|
|
5
|
+
//#region src/playback/behaviors/dom/setup-text-track-actors.d.ts
|
|
6
|
+
interface TextTrackActorsContext {
|
|
7
|
+
mediaElement?: HTMLMediaElement | undefined;
|
|
8
|
+
textTracksActor?: TextTracksActor<VTTCue> | undefined;
|
|
9
|
+
textTrackSegmentLoaderActor?: TextTrackSegmentLoaderActor | undefined;
|
|
10
|
+
}
|
|
11
|
+
interface TextTrackActorsConfig extends TextTrackSegmentLoaderActorConfig {
|
|
12
|
+
resolveTextTrackSegment: TextTrackSegmentResolver<VTTCue>;
|
|
13
|
+
}
|
|
14
|
+
declare const setupTextTrackActors: {
|
|
15
|
+
stateKeys: readonly [];
|
|
16
|
+
contextKeys: readonly ["mediaElement", "textTracksActor", "textTrackSegmentLoaderActor"];
|
|
17
|
+
setup: (deps: {
|
|
18
|
+
state?: {};
|
|
19
|
+
} & {
|
|
20
|
+
context: {
|
|
21
|
+
mediaElement: ReadonlySignal<TextTrackActorsContext['mediaElement']>;
|
|
22
|
+
textTracksActor: Signal<TextTrackActorsContext['textTracksActor']>;
|
|
23
|
+
textTrackSegmentLoaderActor: Signal<TextTrackActorsContext['textTrackSegmentLoaderActor']>;
|
|
24
|
+
};
|
|
25
|
+
} & {
|
|
26
|
+
config: TextTrackActorsConfig;
|
|
27
|
+
}) => () => void;
|
|
28
|
+
};
|
|
29
|
+
//#endregion
|
|
30
|
+
export { setupTextTrackActors };
|
|
31
|
+
//# sourceMappingURL=setup-text-track-actors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-text-track-actors.d.ts","names":[],"sources":["../../../../../src/playback/behaviors/dom/setup-text-track-actors.ts"],"mappings":";;;;;UAgCiB,sBAAA;EACf,YAAA,GAAe,gBAAA;EACf,eAAA,GAAkB,eAAA,CAAgB,MAAA;EAClC,2BAAA,GAA8B,2BAAA;AAAA;AAAA,UAGf,qBAAA,SAA8B,iCAAA;EAC7C,uBAAA,EAAyB,wBAAA,CAAyB,MAAA;AAAA;AAAA,cAoCvC,oBAAA;;;;;;;oBA5BK,cAAA,CAAe,sBAAA;uBACZ,MAAA,CAAO,sBAAA;mCACK,MAAA,CAAO,sBAAA;IAAA;EAAA"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { defineBehavior } from "../../../core/composition/create-composition.js";
|
|
2
|
+
import { effect } from "../../../core/signals/effect.js";
|
|
3
|
+
import { createTextTracksActor } from "../../actors/dom/text-tracks.js";
|
|
4
|
+
import { createTextTrackSegmentLoaderActor } from "../../actors/text-track-segment-loader.js";
|
|
5
|
+
//#region src/playback/behaviors/dom/setup-text-track-actors.ts
|
|
6
|
+
/**
|
|
7
|
+
* **Own the TextTracks actor pair for the current `mediaElement`.** When a
|
|
8
|
+
* `mediaElement` is in scope, creates the `TextTracksActor` (bound to the
|
|
9
|
+
* element's `textTracks`) and the `TextTrackSegmentLoaderActor` (bound to
|
|
10
|
+
* that actor + the injected cue resolver), and publishes both on
|
|
11
|
+
* `context`. On element identity change or behavior destroy, destroys both
|
|
12
|
+
* actors and clears the slots.
|
|
13
|
+
*
|
|
14
|
+
* Single-resource synchronous create/destroy driven by one signal — the
|
|
15
|
+
* simple-effect form is the right shape (per `behaviors.md` → "Where both
|
|
16
|
+
* shapes are legitimate": criterion 4b applies; sole writer of
|
|
17
|
+
* `textTracksActor` / `textTrackSegmentLoaderActor`, the effect's cleanup
|
|
18
|
+
* return handles destroy + slot clear structurally).
|
|
19
|
+
*
|
|
20
|
+
* Pairs with the `loadTextTrackSegments` behavior (a per-type variant of
|
|
21
|
+
* `setupSegmentLoading` in `load-segments.ts`), which only reads
|
|
22
|
+
* `textTrackSegmentLoaderActor`. The cue resolver is injected via
|
|
23
|
+
* `config` so this behavior owns the DOM-bound part of the text-track
|
|
24
|
+
* pipeline.
|
|
25
|
+
*/
|
|
26
|
+
function setupTextTrackActorsSetup({ context, config }) {
|
|
27
|
+
return effect(() => {
|
|
28
|
+
const mediaElement = context.mediaElement.get();
|
|
29
|
+
if (!mediaElement) return;
|
|
30
|
+
const textTracksActor = createTextTracksActor(mediaElement);
|
|
31
|
+
const textTrackSegmentLoaderActor = createTextTrackSegmentLoaderActor(textTracksActor, config.resolveTextTrackSegment, { forwardBuffer: config.forwardBuffer });
|
|
32
|
+
context.textTracksActor.set(textTracksActor);
|
|
33
|
+
context.textTrackSegmentLoaderActor.set(textTrackSegmentLoaderActor);
|
|
34
|
+
return () => {
|
|
35
|
+
textTracksActor.destroy();
|
|
36
|
+
textTrackSegmentLoaderActor.destroy();
|
|
37
|
+
context.textTracksActor.set(void 0);
|
|
38
|
+
context.textTrackSegmentLoaderActor.set(void 0);
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const setupTextTrackActors = defineBehavior({
|
|
43
|
+
stateKeys: [],
|
|
44
|
+
contextKeys: [
|
|
45
|
+
"mediaElement",
|
|
46
|
+
"textTracksActor",
|
|
47
|
+
"textTrackSegmentLoaderActor"
|
|
48
|
+
],
|
|
49
|
+
setup: setupTextTrackActorsSetup
|
|
50
|
+
});
|
|
51
|
+
//#endregion
|
|
52
|
+
export { setupTextTrackActors };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=setup-text-track-actors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-text-track-actors.js","names":[],"sources":["../../../../../src/playback/behaviors/dom/setup-text-track-actors.ts"],"sourcesContent":["/**\n * **Own the TextTracks actor pair for the current `mediaElement`.** When a\n * `mediaElement` is in scope, creates the `TextTracksActor` (bound to the\n * element's `textTracks`) and the `TextTrackSegmentLoaderActor` (bound to\n * that actor + the injected cue resolver), and publishes both on\n * `context`. On element identity change or behavior destroy, destroys both\n * actors and clears the slots.\n *\n * Single-resource synchronous create/destroy driven by one signal — the\n * simple-effect form is the right shape (per `behaviors.md` → \"Where both\n * shapes are legitimate\": criterion 4b applies; sole writer of\n * `textTracksActor` / `textTrackSegmentLoaderActor`, the effect's cleanup\n * return handles destroy + slot clear structurally).\n *\n * Pairs with the `loadTextTrackSegments` behavior (a per-type variant of\n * `setupSegmentLoading` in `load-segments.ts`), which only reads\n * `textTrackSegmentLoaderActor`. The cue resolver is injected via\n * `config` so this behavior owns the DOM-bound part of the text-track\n * pipeline.\n */\nimport { defineBehavior } from '../../../core/composition/create-composition';\nimport { effect } from '../../../core/signals/effect';\nimport type { ReadonlySignal, Signal } from '../../../core/signals/primitives';\nimport { createTextTracksActor } from '../../actors/dom/text-tracks';\nimport {\n createTextTrackSegmentLoaderActor,\n type TextTrackSegmentLoaderActor,\n type TextTrackSegmentLoaderActorConfig,\n type TextTrackSegmentResolver,\n} from '../../actors/text-track-segment-loader';\nimport type { TextTracksActor } from '../../actors/text-tracks';\n\nexport interface TextTrackActorsContext {\n mediaElement?: HTMLMediaElement | undefined;\n textTracksActor?: TextTracksActor<VTTCue> | undefined;\n textTrackSegmentLoaderActor?: TextTrackSegmentLoaderActor | undefined;\n}\n\nexport interface TextTrackActorsConfig extends TextTrackSegmentLoaderActorConfig {\n resolveTextTrackSegment: TextTrackSegmentResolver<VTTCue>;\n}\n\nfunction setupTextTrackActorsSetup({\n context,\n config,\n}: {\n context: {\n mediaElement: ReadonlySignal<TextTrackActorsContext['mediaElement']>;\n textTracksActor: Signal<TextTrackActorsContext['textTracksActor']>;\n textTrackSegmentLoaderActor: Signal<TextTrackActorsContext['textTrackSegmentLoaderActor']>;\n };\n config: TextTrackActorsConfig;\n}): () => void {\n return effect(() => {\n const mediaElement = context.mediaElement.get();\n if (!mediaElement) return;\n\n const textTracksActor = createTextTracksActor(mediaElement);\n const textTrackSegmentLoaderActor = createTextTrackSegmentLoaderActor(\n textTracksActor,\n config.resolveTextTrackSegment,\n { forwardBuffer: config.forwardBuffer }\n );\n context.textTracksActor.set(textTracksActor);\n context.textTrackSegmentLoaderActor.set(textTrackSegmentLoaderActor);\n\n return () => {\n textTracksActor.destroy();\n textTrackSegmentLoaderActor.destroy();\n context.textTracksActor.set(undefined);\n context.textTrackSegmentLoaderActor.set(undefined);\n };\n });\n}\n\nexport const setupTextTrackActors = defineBehavior({\n stateKeys: [],\n contextKeys: ['mediaElement', 'textTracksActor', 'textTrackSegmentLoaderActor'],\n setup: setupTextTrackActorsSetup,\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAS,0BAA0B,EACjC,SACA,UAQa;AACb,QAAO,aAAa;EAClB,MAAM,eAAe,QAAQ,aAAa,KAAK;AAC/C,MAAI,CAAC,aAAc;EAEnB,MAAM,kBAAkB,sBAAsB,aAAa;EAC3D,MAAM,8BAA8B,kCAClC,iBACA,OAAO,yBACP,EAAE,eAAe,OAAO,eAAe,CACxC;AACD,UAAQ,gBAAgB,IAAI,gBAAgB;AAC5C,UAAQ,4BAA4B,IAAI,4BAA4B;AAEpE,eAAa;AACX,mBAAgB,SAAS;AACzB,+BAA4B,SAAS;AACrC,WAAQ,gBAAgB,IAAI,KAAA,EAAU;AACtC,WAAQ,4BAA4B,IAAI,KAAA,EAAU;;GAEpD;;AAGJ,MAAa,uBAAuB,eAAe;CACjD,WAAW,EAAE;CACb,aAAa;EAAC;EAAgB;EAAmB;EAA8B;CAC/E,OAAO;CACR,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { computed, peek } 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 { getTracksByType } from "../../../media/utils/tracks.js";
|
|
5
|
+
import { syncTextTrackModes } from "../../../media/dom/text/text-track-slots.js";
|
|
6
|
+
import { listen } from "@videojs/utils/dom";
|
|
7
|
+
//#region src/playback/behaviors/dom/sync-text-tracks.ts
|
|
8
|
+
/**
|
|
9
|
+
* **Own the text-track slots on the host media element, mirroring the SPF
|
|
10
|
+
* model.** When a presentation is resolved and a media element is
|
|
11
|
+
* available, allocate one slot in `mediaElement.textTracks` per model text
|
|
12
|
+
* track — via creating `<track>` children, since that's the only spec
|
|
13
|
+
* mechanism for adding *and* removing entries to `textTracks` (no
|
|
14
|
+
* `removeTextTrack` API exists). Once slots are provisioned, mirror
|
|
15
|
+
* `selectedTextTrackId` into their `mode`s, and propagate user-initiated
|
|
16
|
+
* DOM `change` events back to `selectedTextTrackId` so non-SPF consumers
|
|
17
|
+
* (host-page captions buttons, browser native UI, video.js store) remain
|
|
18
|
+
* the canonical write path for selection.
|
|
19
|
+
*
|
|
20
|
+
* Single-positive-state reactor (`'preconditions-unmet'` ↔ `'sync-active'`):
|
|
21
|
+
* the entry allocates the slots, applies the initial selection, attaches
|
|
22
|
+
* the `change` listener, and opens a brief Chromium settling-window guard —
|
|
23
|
+
* all transition-driven, fire-once on state entry, with paired cleanup on
|
|
24
|
+
* state exit. A single `effects:` mirrors subsequent
|
|
25
|
+
* `selectedTextTrackId` changes into `mode`s; that's the only
|
|
26
|
+
* continuous-reactivity concern.
|
|
27
|
+
*
|
|
28
|
+
* State-exit cleanup also sends a `'clear'` message to the
|
|
29
|
+
* `TextTracksActor` so its cue+segment cache (keyed by trackId) is
|
|
30
|
+
* dropped alongside the DOM `<track>` slots. The actor itself is owned
|
|
31
|
+
* by `setupTextTrackActors` and bound to mediaElement, not presentation,
|
|
32
|
+
* so it survives source resets; clearing its context here keeps the
|
|
33
|
+
* cache consistent with the DOM. Without this, a subsequent
|
|
34
|
+
* presentation reusing a trackId would have `getSegmentsToLoad` treat
|
|
35
|
+
* its segments as already-buffered and skip loading them.
|
|
36
|
+
*
|
|
37
|
+
* Multi-writer with `selectTextTrack` is intentional and orthogonal:
|
|
38
|
+
* `selectTextTrack` owns the *default-on-load / clear-on-unload* contract
|
|
39
|
+
* for `selectedTextTrackId`; this behavior writes only from DOM `change`
|
|
40
|
+
* events. They reflect distinct decision-making domains (config-driven
|
|
41
|
+
* intent vs DOM-driven user action), so this behavior never clears the
|
|
42
|
+
* slot on source unload — that's `selectTextTrack`'s contract. (It *does*
|
|
43
|
+
* write `undefined` when a user disables all tracks via native UI, since
|
|
44
|
+
* that's a real user action that should round-trip into SPF state.)
|
|
45
|
+
*/
|
|
46
|
+
function deriveState(presentation, mediaElement) {
|
|
47
|
+
if (!mediaElement || !presentation) return "preconditions-unmet";
|
|
48
|
+
return getTracksByType(presentation, "text").length > 0 ? "sync-active" : "preconditions-unmet";
|
|
49
|
+
}
|
|
50
|
+
function syncTextTracksSetup({ state, context, config }) {
|
|
51
|
+
const { addSubtitlesTracksToMedia, getShowingSubtitlesTrackFromMedia, removeAllSubtitlesTracksFromMedia } = config;
|
|
52
|
+
const derivedStateSignal = computed(() => deriveState(state.presentation.get(), context.mediaElement.get()));
|
|
53
|
+
return createMachineReactor({
|
|
54
|
+
initial: "preconditions-unmet",
|
|
55
|
+
monitor: () => derivedStateSignal.get(),
|
|
56
|
+
states: {
|
|
57
|
+
"preconditions-unmet": {},
|
|
58
|
+
"sync-active": {
|
|
59
|
+
entry: () => {
|
|
60
|
+
const mediaElement = context.mediaElement.get();
|
|
61
|
+
addSubtitlesTracksToMedia(mediaElement, getTracksByType(state.presentation.get(), "text"));
|
|
62
|
+
syncTextTrackModes(mediaElement.textTracks, state.selectedTextTrackId.get());
|
|
63
|
+
let inSettlingWindow = true;
|
|
64
|
+
const settlingTimeout = setTimeout(() => {
|
|
65
|
+
inSettlingWindow = false;
|
|
66
|
+
}, 0);
|
|
67
|
+
const onChange = () => {
|
|
68
|
+
if (inSettlingWindow) {
|
|
69
|
+
syncTextTrackModes(mediaElement.textTracks, state.selectedTextTrackId.get());
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const nextId = getShowingSubtitlesTrackFromMedia(mediaElement)?.id || void 0;
|
|
73
|
+
if (nextId === state.selectedTextTrackId.get()) return;
|
|
74
|
+
state.selectedTextTrackId.set(nextId);
|
|
75
|
+
};
|
|
76
|
+
const unlisten = listen(mediaElement.textTracks, "change", onChange);
|
|
77
|
+
return () => {
|
|
78
|
+
unlisten();
|
|
79
|
+
clearTimeout(settlingTimeout);
|
|
80
|
+
removeAllSubtitlesTracksFromMedia(mediaElement);
|
|
81
|
+
peek(context.textTracksActor)?.send({ type: "clear" });
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
effects: () => {
|
|
85
|
+
syncTextTrackModes(peek(context.mediaElement).textTracks, state.selectedTextTrackId.get());
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
const syncTextTracks = defineBehavior({
|
|
92
|
+
stateKeys: ["presentation", "selectedTextTrackId"],
|
|
93
|
+
contextKeys: ["mediaElement", "textTracksActor"],
|
|
94
|
+
setup: syncTextTracksSetup
|
|
95
|
+
});
|
|
96
|
+
//#endregion
|
|
97
|
+
export { syncTextTracks };
|
|
98
|
+
|
|
99
|
+
//# sourceMappingURL=sync-text-tracks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-text-tracks.js","names":[],"sources":["../../../../../src/playback/behaviors/dom/sync-text-tracks.ts"],"sourcesContent":["/**\n * **Own the text-track slots on the host media element, mirroring the SPF\n * model.** When a presentation is resolved and a media element is\n * available, allocate one slot in `mediaElement.textTracks` per model text\n * track — via creating `<track>` children, since that's the only spec\n * mechanism for adding *and* removing entries to `textTracks` (no\n * `removeTextTrack` API exists). Once slots are provisioned, mirror\n * `selectedTextTrackId` into their `mode`s, and propagate user-initiated\n * DOM `change` events back to `selectedTextTrackId` so non-SPF consumers\n * (host-page captions buttons, browser native UI, video.js store) remain\n * the canonical write path for selection.\n *\n * Single-positive-state reactor (`'preconditions-unmet'` ↔ `'sync-active'`):\n * the entry allocates the slots, applies the initial selection, attaches\n * the `change` listener, and opens a brief Chromium settling-window guard —\n * all transition-driven, fire-once on state entry, with paired cleanup on\n * state exit. A single `effects:` mirrors subsequent\n * `selectedTextTrackId` changes into `mode`s; that's the only\n * continuous-reactivity concern.\n *\n * State-exit cleanup also sends a `'clear'` message to the\n * `TextTracksActor` so its cue+segment cache (keyed by trackId) is\n * dropped alongside the DOM `<track>` slots. The actor itself is owned\n * by `setupTextTrackActors` and bound to mediaElement, not presentation,\n * so it survives source resets; clearing its context here keeps the\n * cache consistent with the DOM. Without this, a subsequent\n * presentation reusing a trackId would have `getSegmentsToLoad` treat\n * its segments as already-buffered and skip loading them.\n *\n * Multi-writer with `selectTextTrack` is intentional and orthogonal:\n * `selectTextTrack` owns the *default-on-load / clear-on-unload* contract\n * for `selectedTextTrackId`; this behavior writes only from DOM `change`\n * events. They reflect distinct decision-making domains (config-driven\n * intent vs DOM-driven user action), so this behavior never clears the\n * slot on source unload — that's `selectTextTrack`'s contract. (It *does*\n * write `undefined` when a user disables all tracks via native UI, since\n * that's a real user action that should round-trip into SPF state.)\n */\n\nimport { listen } from '@videojs/utils/dom';\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, peek, type ReadonlySignal, type Signal } from '../../../core/signals/primitives';\nimport { syncTextTrackModes } from '../../../media/dom/text/text-track-slots';\nimport type { MaybeResolvedPresentation, PartiallyResolvedTextTrack, TextTrack } from '../../../media/types';\nimport { getTracksByType } from '../../../media/utils/tracks';\nimport type { TextTracksActor } from '../../actors/text-tracks';\n\ntype SyncTextTracksFsmState = 'preconditions-unmet' | 'sync-active';\n\nexport interface SyncTextTracksConfig {\n /**\n * Create and append SPF-owned `<track>` slots on `mediaElement`, one per\n * model text track. Implementation tags each element so the read/remove\n * helpers can scope to SPF-owned slots. **Required** — the behavior is\n * DOM-binding-neutral and the composing engine supplies the integration.\n */\n addSubtitlesTracksToMedia: (\n mediaElement: HTMLMediaElement,\n modelTextTracks: readonly (PartiallyResolvedTextTrack | TextTrack)[]\n ) => void;\n /**\n * Return the SPF-owned subtitle/caption `TextTrack` currently in `'showing'`\n * mode, or `undefined` if none. Used by the DOM `change` bridge to mirror\n * native-UI selection back into `selectedTextTrackId`.\n */\n getShowingSubtitlesTrackFromMedia: (mediaElement: HTMLMediaElement) => globalThis.TextTrack | undefined;\n /**\n * Remove every SPF-owned `<track>` child from `mediaElement`. Called on\n * state exit (source unload, behavior destroy) to evict slots.\n */\n removeAllSubtitlesTracksFromMedia: (mediaElement: HTMLMediaElement) => void;\n}\n\nfunction deriveState(\n presentation: MaybeResolvedPresentation | undefined,\n mediaElement: HTMLMediaElement | undefined\n): SyncTextTracksFsmState {\n if (!mediaElement || !presentation) return 'preconditions-unmet';\n return getTracksByType(presentation, 'text').length > 0 ? 'sync-active' : 'preconditions-unmet';\n}\n\nfunction syncTextTracksSetup({\n state,\n context,\n config,\n}: {\n state: {\n presentation: ReadonlySignal<MaybeResolvedPresentation | undefined>;\n selectedTextTrackId: Signal<string | undefined>;\n };\n context: {\n mediaElement: ReadonlySignal<HTMLMediaElement | undefined>;\n textTracksActor: ReadonlySignal<TextTracksActor<VTTCue> | undefined>;\n };\n config: SyncTextTracksConfig;\n}): Reactor<SyncTextTracksFsmState | 'destroying' | 'destroyed'> {\n const { addSubtitlesTracksToMedia, getShowingSubtitlesTrackFromMedia, removeAllSubtitlesTracksFromMedia } = config;\n\n const derivedStateSignal = computed(() => deriveState(state.presentation.get(), context.mediaElement.get()));\n\n return createMachineReactor<SyncTextTracksFsmState>({\n initial: 'preconditions-unmet',\n monitor: () => derivedStateSignal.get(),\n states: {\n 'preconditions-unmet': {},\n\n 'sync-active': {\n // Allocate slots, apply the initial selection, attach the change\n // listener, and open the settling window — all transition-driven\n // (fire once per state entry). Entry is auto-untracked, so `.get()`\n // here doesn't subscribe; the returned cleanup detaches and evicts\n // on state exit (src reset through 'preconditions-unmet') and on\n // destroy.\n entry: () => {\n const mediaElement = context.mediaElement.get()!;\n // `getTracksByType('text', ...)` returns text tracks only — the\n // selection-set filter inside the helper ensures that — but its\n // declared return is the wide track union. Mirror the cast\n // pattern used by `quality-switching` for the video branch.\n const modelTextTracks = getTracksByType(state.presentation.get()!, 'text') as readonly (\n | PartiallyResolvedTextTrack\n | TextTrack\n )[];\n\n addSubtitlesTracksToMedia(mediaElement, modelTextTracks);\n // Apply our selection synchronously so the change-event tasks\n // these mode writes queue land in the macrotask queue *before*\n // the settling-close `setTimeout(0)` queued below. This keeps\n // the settling window open long enough to swallow Chromium's\n // own auto-selection task (also scheduled in the next tick after\n // `<track>` insertion); if the order flipped, our handler would\n // treat Chromium's auto-pick as a user action. The `effects:`\n // block below handles subsequent `selectedTextTrackId` changes.\n syncTextTrackModes(mediaElement.textTracks, state.selectedTextTrackId.get());\n\n // Chromium re-applies its own selection across the next task tick\n // after `<track>` insertion (default-track auto-pick, language\n // preference). During this window, the `change` event may fire\n // with browser-chosen modes that don't reflect a real user action;\n // re-apply our modes silently rather than writing them back.\n let inSettlingWindow = true;\n const settlingTimeout = setTimeout(() => {\n inSettlingWindow = false;\n }, 0);\n\n const onChange = (): void => {\n if (inSettlingWindow) {\n syncTextTrackModes(mediaElement.textTracks, state.selectedTextTrackId.get());\n return;\n }\n const showingTrack = getShowingSubtitlesTrackFromMedia(mediaElement);\n // `showingTrack.id` matches the SPF id we set when the slot was\n // allocated. Empty-string ids fall through to `undefined`.\n const nextId = showingTrack?.id || undefined;\n if (nextId === state.selectedTextTrackId.get()) return;\n state.selectedTextTrackId.set(nextId);\n };\n\n const unlisten = listen(mediaElement.textTracks, 'change', onChange);\n\n return () => {\n unlisten();\n clearTimeout(settlingTimeout);\n removeAllSubtitlesTracksFromMedia(mediaElement);\n // Clear the TextTracksActor's cue+segment cache, which is\n // keyed by trackId. If we don't, a subsequent presentation\n // reusing a trackId would have `getSegmentsToLoad` treat its\n // segments as already-buffered. The DOM cleanup above\n // already evicted the live cues; this drops the cache that\n // tracked them. The actor itself is owned by\n // `setupTextTrackActors` (mediaElement-bound lifecycle), so\n // we send rather than destroy.\n peek(context.textTracksActor)?.send({ type: 'clear' });\n };\n },\n\n // Mirror selection changes into mode. The state machine handles\n // mediaElement/presentation changes via 'preconditions-unmet'\n // round-trips, so we peek mediaElement here.\n effects: () => {\n const mediaElement = peek(context.mediaElement)!;\n syncTextTrackModes(mediaElement.textTracks, state.selectedTextTrackId.get());\n },\n },\n },\n });\n}\n\nexport const syncTextTracks = defineBehavior({\n stateKeys: ['presentation', 'selectedTextTrackId'],\n contextKeys: ['mediaElement', 'textTracksActor'],\n setup: syncTextTracksSetup,\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2EA,SAAS,YACP,cACA,cACwB;AACxB,KAAI,CAAC,gBAAgB,CAAC,aAAc,QAAO;AAC3C,QAAO,gBAAgB,cAAc,OAAO,CAAC,SAAS,IAAI,gBAAgB;;AAG5E,SAAS,oBAAoB,EAC3B,OACA,SACA,UAW+D;CAC/D,MAAM,EAAE,2BAA2B,mCAAmC,sCAAsC;CAE5G,MAAM,qBAAqB,eAAe,YAAY,MAAM,aAAa,KAAK,EAAE,QAAQ,aAAa,KAAK,CAAC,CAAC;AAE5G,QAAO,qBAA6C;EAClD,SAAS;EACT,eAAe,mBAAmB,KAAK;EACvC,QAAQ;GACN,uBAAuB,EAAE;GAEzB,eAAe;IAOb,aAAa;KACX,MAAM,eAAe,QAAQ,aAAa,KAAK;AAU/C,+BAA0B,cALF,gBAAgB,MAAM,aAAa,KAAK,EAAG,OAAO,CAKlB;AASxD,wBAAmB,aAAa,YAAY,MAAM,oBAAoB,KAAK,CAAC;KAO5E,IAAI,mBAAmB;KACvB,MAAM,kBAAkB,iBAAiB;AACvC,yBAAmB;QAClB,EAAE;KAEL,MAAM,iBAAuB;AAC3B,UAAI,kBAAkB;AACpB,0BAAmB,aAAa,YAAY,MAAM,oBAAoB,KAAK,CAAC;AAC5E;;MAKF,MAAM,SAHe,kCAAkC,aAAa,EAGvC,MAAM,KAAA;AACnC,UAAI,WAAW,MAAM,oBAAoB,KAAK,CAAE;AAChD,YAAM,oBAAoB,IAAI,OAAO;;KAGvC,MAAM,WAAW,OAAO,aAAa,YAAY,UAAU,SAAS;AAEpE,kBAAa;AACX,gBAAU;AACV,mBAAa,gBAAgB;AAC7B,wCAAkC,aAAa;AAS/C,WAAK,QAAQ,gBAAgB,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;;;IAO1D,eAAe;AAEb,wBADqB,KAAK,QAAQ,aAAa,CACf,YAAY,MAAM,oBAAoB,KAAK,CAAC;;IAE/E;GACF;EACF,CAAC;;AAGJ,MAAa,iBAAiB,eAAe;CAC3C,WAAW,CAAC,gBAAgB,sBAAsB;CAClD,aAAa,CAAC,gBAAgB,kBAAkB;CAChD,OAAO;CACR,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ReadonlySignal, Signal } from "../../../core/signals/primitives.js";
|
|
2
|
+
|
|
3
|
+
//#region src/playback/behaviors/dom/track-current-time.d.ts
|
|
4
|
+
interface CurrentTimeState {
|
|
5
|
+
currentTime?: number;
|
|
6
|
+
}
|
|
7
|
+
interface CurrentTimeContext {
|
|
8
|
+
mediaElement?: HTMLMediaElement | undefined;
|
|
9
|
+
}
|
|
10
|
+
interface TrackCurrentTimeConfig {
|
|
11
|
+
/**
|
|
12
|
+
* Value written to `state.currentTime` when no media element is attached.
|
|
13
|
+
* Defaults to `0` — the HTMLMediaElement spec default.
|
|
14
|
+
*/
|
|
15
|
+
defaultCurrentTime?: number;
|
|
16
|
+
}
|
|
17
|
+
declare const trackCurrentTime: {
|
|
18
|
+
stateKeys: readonly ["currentTime"];
|
|
19
|
+
contextKeys: readonly ["mediaElement"];
|
|
20
|
+
setup: (deps: {
|
|
21
|
+
state: {
|
|
22
|
+
currentTime: Signal<CurrentTimeState['currentTime']>;
|
|
23
|
+
};
|
|
24
|
+
} & {
|
|
25
|
+
context: {
|
|
26
|
+
mediaElement: ReadonlySignal<CurrentTimeContext['mediaElement']>;
|
|
27
|
+
};
|
|
28
|
+
} & {
|
|
29
|
+
config: TrackCurrentTimeConfig;
|
|
30
|
+
}) => () => void;
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { CurrentTimeContext, CurrentTimeState, trackCurrentTime };
|
|
34
|
+
//# sourceMappingURL=track-current-time.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"track-current-time.d.ts","names":[],"sources":["../../../../../src/playback/behaviors/dom/track-current-time.ts"],"mappings":";;;UAoBiB,gBAAA;EACf,WAAA;AAAA;AAAA,UAGe,kBAAA;EACf,YAAA,GAAe,gBAAA;AAAA;AAAA,UAGA,sBAAA;EAJA;;;;EASf,kBAAA;AAAA;AAAA,cAgCW,gBAAA;;;;;mBAxBW,MAAA,CAAO,gBAAA;IAAA;EAAA;;oBACJ,cAAA,CAAe,kBAAA;IAAA;EAAA"}
|