rx-player 4.4.0 → 4.4.1-dev.2025101500
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/CHANGELOG.md +7 -0
- package/README.md +52 -113
- package/VERSION +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_worker.js +1 -1
- package/dist/commonjs/core/{main/common → entry}/FreezeResolver.d.ts +3 -3
- package/dist/commonjs/core/entry/FreezeResolver.d.ts.map +1 -0
- package/dist/commonjs/core/{main/common → entry}/FreezeResolver.js +3 -3
- package/dist/{es2017/core/main/worker → commonjs/core/entry}/content_preparer.d.ts +22 -15
- package/dist/commonjs/core/entry/content_preparer.d.ts.map +1 -0
- package/dist/commonjs/core/{main/worker → entry}/content_preparer.js +62 -64
- package/dist/{es2017/core/main/common → commonjs/core/entry}/content_time_boundaries_observer.d.ts +5 -5
- package/dist/commonjs/core/entry/content_time_boundaries_observer.d.ts.map +1 -0
- package/dist/commonjs/core/{main/common → entry}/content_time_boundaries_observer.js +6 -6
- package/dist/commonjs/core/entry/core_entry.d.ts +36 -0
- package/dist/commonjs/core/entry/core_entry.d.ts.map +1 -0
- package/dist/commonjs/core/{main/worker/worker_main.js → entry/core_entry.js} +192 -153
- package/dist/commonjs/core/{main/worker/worker_text_displayer_interface.d.ts → entry/core_text_displayer_interface.d.ts} +11 -11
- package/dist/commonjs/core/entry/core_text_displayer_interface.d.ts.map +1 -0
- package/dist/commonjs/core/{main/worker/worker_text_displayer_interface.js → entry/core_text_displayer_interface.js} +22 -22
- package/dist/commonjs/core/{main/common → entry}/create_content_time_boundaries_observer.d.ts +6 -6
- package/dist/commonjs/core/entry/create_content_time_boundaries_observer.d.ts.map +1 -0
- package/dist/commonjs/core/{main/common → entry}/create_content_time_boundaries_observer.js +1 -1
- package/dist/commonjs/core/{main/common → entry}/get_buffered_data_per_media_buffer.d.ts +4 -4
- package/dist/commonjs/core/entry/get_buffered_data_per_media_buffer.d.ts.map +1 -0
- package/dist/commonjs/core/{main/common → entry}/get_buffered_data_per_media_buffer.js +1 -1
- package/dist/{es2017/core/main/common → commonjs/core/entry}/get_thumbnail_data.d.ts +3 -3
- package/dist/commonjs/core/entry/get_thumbnail_data.d.ts.map +1 -0
- package/dist/commonjs/core/{main/common → entry}/get_thumbnail_data.js +2 -2
- package/dist/commonjs/core/entry/index.d.ts +5 -0
- package/dist/commonjs/core/entry/index.d.ts.map +1 -0
- package/dist/commonjs/core/entry/index.js +4 -0
- package/dist/{es2017/core/main/common → commonjs/core/entry}/synchronize_sinks_on_observation.d.ts +2 -2
- package/dist/commonjs/core/entry/synchronize_sinks_on_observation.d.ts.map +1 -0
- package/dist/commonjs/core/{main/worker → entry}/track_choice_setter.d.ts +4 -4
- package/dist/commonjs/core/entry/track_choice_setter.d.ts.map +1 -0
- package/dist/commonjs/core/{main/worker → entry}/track_choice_setter.js +4 -4
- package/dist/commonjs/core/entry/utils.d.ts +3 -0
- package/dist/commonjs/core/entry/utils.d.ts.map +1 -0
- package/dist/commonjs/core/entry/utils.js +11 -0
- package/dist/commonjs/core/stream/orchestrator/stream_orchestrator.d.ts.map +1 -1
- package/dist/commonjs/core/stream/orchestrator/stream_orchestrator.js +17 -0
- package/dist/commonjs/core/types.d.ts +519 -1
- package/dist/commonjs/core/types.d.ts.map +1 -1
- package/dist/commonjs/core/types.js +1 -0
- package/dist/commonjs/experimental/features/local.d.ts.map +1 -1
- package/dist/commonjs/experimental/features/local.js +7 -1
- package/dist/commonjs/experimental/features/metaplaylist.d.ts.map +1 -1
- package/dist/commonjs/experimental/features/metaplaylist.js +7 -1
- package/dist/commonjs/experimental/features/multi_thread.d.ts.map +1 -1
- package/dist/commonjs/experimental/features/multi_thread.js +6 -2
- package/dist/commonjs/features/features_object.js +1 -1
- package/dist/commonjs/features/list/dash.d.ts.map +1 -1
- package/dist/commonjs/features/list/dash.js +7 -1
- package/dist/commonjs/features/list/dash_wasm.d.ts.map +1 -1
- package/dist/commonjs/features/list/dash_wasm.js +7 -1
- package/dist/commonjs/features/list/media_source_main.d.ts.map +1 -1
- package/dist/commonjs/features/list/media_source_main.js +7 -1
- package/dist/commonjs/features/list/smooth.d.ts.map +1 -1
- package/dist/commonjs/features/list/smooth.js +7 -1
- package/dist/commonjs/features/types.d.ts +20 -4
- package/dist/commonjs/features/types.d.ts.map +1 -1
- package/dist/commonjs/main_thread/api/public_api.d.ts.map +1 -1
- package/dist/commonjs/main_thread/api/public_api.js +39 -42
- package/dist/commonjs/main_thread/core_interface/base.d.ts +13 -0
- package/dist/commonjs/main_thread/core_interface/base.d.ts.map +1 -0
- package/dist/commonjs/main_thread/core_interface/base.js +32 -0
- package/dist/commonjs/main_thread/core_interface/monothread.d.ts +13 -0
- package/dist/commonjs/main_thread/core_interface/monothread.d.ts.map +1 -0
- package/dist/commonjs/main_thread/core_interface/monothread.js +56 -0
- package/dist/commonjs/main_thread/core_interface/multithread.d.ts +25 -0
- package/dist/commonjs/main_thread/core_interface/multithread.d.ts.map +1 -0
- package/dist/commonjs/main_thread/core_interface/multithread.js +67 -0
- package/dist/commonjs/main_thread/core_interface/types.d.ts +6 -0
- package/dist/commonjs/main_thread/core_interface/types.d.ts.map +1 -0
- package/dist/commonjs/main_thread/core_interface/types.js +2 -0
- package/dist/commonjs/main_thread/init/media_source_content_initializer.d.ts +166 -108
- package/dist/commonjs/main_thread/init/media_source_content_initializer.d.ts.map +1 -1
- package/dist/commonjs/main_thread/init/media_source_content_initializer.js +1492 -919
- package/dist/commonjs/main_thread/init/utils/create_core_playback_observer.d.ts.map +1 -1
- package/dist/commonjs/main_thread/init/utils/create_core_playback_observer.js +2 -1
- package/dist/commonjs/main_thread/init/utils/update_manifest_codec_support.d.ts +1 -1
- package/dist/commonjs/main_thread/init/utils/update_manifest_codec_support.d.ts.map +1 -1
- package/dist/commonjs/main_thread/types.d.ts +537 -0
- package/dist/commonjs/main_thread/types.d.ts.map +1 -1
- package/dist/commonjs/manifest/utils.d.ts.map +1 -1
- package/dist/commonjs/manifest/utils.js +18 -4
- package/dist/commonjs/mse/worker_media_source_interface.d.ts +2 -2
- package/dist/commonjs/mse/worker_media_source_interface.d.ts.map +1 -1
- package/dist/commonjs/mse/worker_media_source_interface.js +12 -12
- package/dist/commonjs/parsers/manifest/smooth/create_parser.d.ts +1 -1
- package/dist/commonjs/parsers/manifest/smooth/create_parser.d.ts.map +1 -1
- package/dist/commonjs/parsers/manifest/smooth/create_parser.js +31 -27
- package/dist/commonjs/parsers/manifest/smooth/parse_C_nodes.d.ts +3 -2
- package/dist/commonjs/parsers/manifest/smooth/parse_C_nodes.d.ts.map +1 -1
- package/dist/commonjs/parsers/manifest/smooth/parse_C_nodes.js +16 -7
- package/dist/commonjs/parsers/manifest/smooth/parse_protection_node.d.ts +3 -2
- package/dist/commonjs/parsers/manifest/smooth/parse_protection_node.d.ts.map +1 -1
- package/dist/commonjs/parsers/manifest/smooth/parse_protection_node.js +37 -6
- package/dist/commonjs/parsers/manifest/smooth/utils/parseBoolean.d.ts +1 -1
- package/dist/commonjs/parsers/manifest/smooth/utils/parseBoolean.d.ts.map +1 -1
- package/dist/commonjs/parsers/manifest/smooth/utils/reduceChildren.d.ts +3 -2
- package/dist/commonjs/parsers/manifest/smooth/utils/reduceChildren.d.ts.map +1 -1
- package/dist/commonjs/parsers/manifest/smooth/utils/reduceChildren.js +28 -5
- package/dist/{es2017/playback_observer/worker_playback_observer.d.ts → commonjs/playback_observer/core_playback_observer.d.ts} +8 -8
- package/dist/commonjs/playback_observer/core_playback_observer.d.ts.map +1 -0
- package/dist/commonjs/playback_observer/{worker_playback_observer.js → core_playback_observer.js} +13 -13
- package/dist/commonjs/transports/smooth/pipelines.d.ts.map +1 -1
- package/dist/commonjs/transports/smooth/pipelines.js +25 -3
- package/dist/commonjs/worker_entry_point.js +62 -2
- package/dist/es2017/__GENERATED_CODE/embedded_worker.d.ts.map +1 -1
- package/dist/es2017/__GENERATED_CODE/embedded_worker.js +1 -1
- package/dist/es2017/core/{main/common → entry}/FreezeResolver.d.ts +3 -3
- package/dist/es2017/core/entry/FreezeResolver.d.ts.map +1 -0
- package/dist/es2017/core/{main/common → entry}/FreezeResolver.js +3 -3
- package/dist/{commonjs/core/main/worker → es2017/core/entry}/content_preparer.d.ts +22 -15
- package/dist/es2017/core/entry/content_preparer.d.ts.map +1 -0
- package/dist/es2017/core/{main/worker → entry}/content_preparer.js +53 -55
- package/dist/{commonjs/core/main/common → es2017/core/entry}/content_time_boundaries_observer.d.ts +5 -5
- package/dist/es2017/core/entry/content_time_boundaries_observer.d.ts.map +1 -0
- package/dist/es2017/core/{main/common → entry}/content_time_boundaries_observer.js +6 -6
- package/dist/es2017/core/entry/core_entry.d.ts +36 -0
- package/dist/es2017/core/entry/core_entry.d.ts.map +1 -0
- package/dist/es2017/core/{main/worker/worker_main.js → entry/core_entry.js} +153 -114
- package/dist/es2017/core/{main/worker/worker_text_displayer_interface.d.ts → entry/core_text_displayer_interface.d.ts} +11 -11
- package/dist/es2017/core/entry/core_text_displayer_interface.d.ts.map +1 -0
- package/dist/es2017/core/{main/worker/worker_text_displayer_interface.js → entry/core_text_displayer_interface.js} +10 -10
- package/dist/es2017/core/{main/common → entry}/create_content_time_boundaries_observer.d.ts +6 -6
- package/dist/es2017/core/entry/create_content_time_boundaries_observer.d.ts.map +1 -0
- package/dist/es2017/core/{main/common → entry}/create_content_time_boundaries_observer.js +1 -1
- package/dist/es2017/core/{main/common → entry}/get_buffered_data_per_media_buffer.d.ts +4 -4
- package/dist/es2017/core/entry/get_buffered_data_per_media_buffer.d.ts.map +1 -0
- package/dist/es2017/core/{main/common → entry}/get_buffered_data_per_media_buffer.js +1 -1
- package/dist/{commonjs/core/main/common → es2017/core/entry}/get_thumbnail_data.d.ts +3 -3
- package/dist/es2017/core/entry/get_thumbnail_data.d.ts.map +1 -0
- package/dist/es2017/core/{main/common → entry}/get_thumbnail_data.js +2 -2
- package/dist/es2017/core/entry/index.d.ts +5 -0
- package/dist/es2017/core/entry/index.d.ts.map +1 -0
- package/dist/es2017/core/entry/index.js +2 -0
- package/dist/{commonjs/core/main/common → es2017/core/entry}/synchronize_sinks_on_observation.d.ts +2 -2
- package/dist/es2017/core/entry/synchronize_sinks_on_observation.d.ts.map +1 -0
- package/dist/es2017/core/{main/worker → entry}/track_choice_setter.d.ts +4 -4
- package/dist/es2017/core/entry/track_choice_setter.d.ts.map +1 -0
- package/dist/es2017/core/{main/worker → entry}/track_choice_setter.js +4 -4
- package/dist/es2017/core/entry/utils.d.ts +3 -0
- package/dist/es2017/core/entry/utils.d.ts.map +1 -0
- package/dist/es2017/core/entry/utils.js +8 -0
- package/dist/es2017/core/stream/orchestrator/stream_orchestrator.d.ts.map +1 -1
- package/dist/es2017/core/stream/orchestrator/stream_orchestrator.js +18 -1
- package/dist/es2017/core/types.d.ts +519 -1
- package/dist/es2017/core/types.d.ts.map +1 -1
- package/dist/es2017/core/types.js +1 -0
- package/dist/es2017/experimental/features/local.d.ts.map +1 -1
- package/dist/es2017/experimental/features/local.js +7 -1
- package/dist/es2017/experimental/features/metaplaylist.d.ts.map +1 -1
- package/dist/es2017/experimental/features/metaplaylist.js +7 -1
- package/dist/es2017/experimental/features/multi_thread.d.ts.map +1 -1
- package/dist/es2017/experimental/features/multi_thread.js +6 -2
- package/dist/es2017/features/features_object.js +1 -1
- package/dist/es2017/features/list/dash.d.ts.map +1 -1
- package/dist/es2017/features/list/dash.js +7 -1
- package/dist/es2017/features/list/dash_wasm.d.ts.map +1 -1
- package/dist/es2017/features/list/dash_wasm.js +7 -1
- package/dist/es2017/features/list/media_source_main.d.ts.map +1 -1
- package/dist/es2017/features/list/media_source_main.js +7 -1
- package/dist/es2017/features/list/smooth.d.ts.map +1 -1
- package/dist/es2017/features/list/smooth.js +7 -1
- package/dist/es2017/features/types.d.ts +20 -4
- package/dist/es2017/features/types.d.ts.map +1 -1
- package/dist/es2017/main_thread/api/public_api.d.ts.map +1 -1
- package/dist/es2017/main_thread/api/public_api.js +40 -43
- package/dist/es2017/main_thread/core_interface/base.d.ts +13 -0
- package/dist/es2017/main_thread/core_interface/base.d.ts.map +1 -0
- package/dist/es2017/main_thread/core_interface/base.js +28 -0
- package/dist/es2017/main_thread/core_interface/monothread.d.ts +13 -0
- package/dist/es2017/main_thread/core_interface/monothread.d.ts.map +1 -0
- package/dist/es2017/main_thread/core_interface/monothread.js +32 -0
- package/dist/es2017/main_thread/core_interface/multithread.d.ts +25 -0
- package/dist/es2017/main_thread/core_interface/multithread.d.ts.map +1 -0
- package/dist/es2017/main_thread/core_interface/multithread.js +45 -0
- package/dist/es2017/main_thread/core_interface/types.d.ts +6 -0
- package/dist/es2017/main_thread/core_interface/types.d.ts.map +1 -0
- package/dist/es2017/main_thread/core_interface/types.js +1 -0
- package/dist/es2017/main_thread/init/media_source_content_initializer.d.ts +166 -108
- package/dist/es2017/main_thread/init/media_source_content_initializer.d.ts.map +1 -1
- package/dist/es2017/main_thread/init/media_source_content_initializer.js +1405 -760
- package/dist/es2017/main_thread/init/utils/create_core_playback_observer.d.ts.map +1 -1
- package/dist/es2017/main_thread/init/utils/create_core_playback_observer.js +2 -1
- package/dist/es2017/main_thread/init/utils/update_manifest_codec_support.d.ts +1 -1
- package/dist/es2017/main_thread/init/utils/update_manifest_codec_support.d.ts.map +1 -1
- package/dist/es2017/main_thread/types.d.ts +537 -0
- package/dist/es2017/main_thread/types.d.ts.map +1 -1
- package/dist/es2017/manifest/utils.d.ts.map +1 -1
- package/dist/es2017/manifest/utils.js +16 -4
- package/dist/es2017/mse/worker_media_source_interface.d.ts +2 -2
- package/dist/es2017/mse/worker_media_source_interface.d.ts.map +1 -1
- package/dist/es2017/mse/worker_media_source_interface.js +12 -12
- package/dist/es2017/parsers/manifest/smooth/create_parser.d.ts +1 -1
- package/dist/es2017/parsers/manifest/smooth/create_parser.d.ts.map +1 -1
- package/dist/es2017/parsers/manifest/smooth/create_parser.js +31 -27
- package/dist/es2017/parsers/manifest/smooth/parse_C_nodes.d.ts +3 -2
- package/dist/es2017/parsers/manifest/smooth/parse_C_nodes.d.ts.map +1 -1
- package/dist/es2017/parsers/manifest/smooth/parse_C_nodes.js +16 -7
- package/dist/es2017/parsers/manifest/smooth/parse_protection_node.d.ts +3 -2
- package/dist/es2017/parsers/manifest/smooth/parse_protection_node.d.ts.map +1 -1
- package/dist/es2017/parsers/manifest/smooth/parse_protection_node.js +15 -6
- package/dist/es2017/parsers/manifest/smooth/utils/parseBoolean.d.ts +1 -1
- package/dist/es2017/parsers/manifest/smooth/utils/parseBoolean.d.ts.map +1 -1
- package/dist/es2017/parsers/manifest/smooth/utils/reduceChildren.d.ts +3 -2
- package/dist/es2017/parsers/manifest/smooth/utils/reduceChildren.d.ts.map +1 -1
- package/dist/es2017/parsers/manifest/smooth/utils/reduceChildren.js +6 -5
- package/dist/{commonjs/playback_observer/worker_playback_observer.d.ts → es2017/playback_observer/core_playback_observer.d.ts} +8 -8
- package/dist/es2017/playback_observer/core_playback_observer.d.ts.map +1 -0
- package/dist/es2017/playback_observer/{worker_playback_observer.js → core_playback_observer.js} +2 -2
- package/dist/es2017/transports/smooth/pipelines.d.ts.map +1 -1
- package/dist/es2017/transports/smooth/pipelines.js +25 -3
- package/dist/es2017/worker_entry_point.js +62 -2
- package/dist/rx-player.js +21882 -19021
- package/dist/rx-player.min.js +20 -20
- package/dist/worker.js +8 -8
- package/package.json +1 -1
- package/src/README.md +88 -198
- package/src/__GENERATED_CODE/embedded_worker.ts +1 -1
- package/src/core/{main/common → entry}/FreezeResolver.ts +7 -7
- package/src/core/{main → entry}/README.md +1 -1
- package/src/core/{main/worker → entry}/content_preparer.ts +77 -76
- package/src/core/{main/common → entry}/content_time_boundaries_observer.ts +10 -10
- package/src/core/{main/worker/worker_main.ts → entry/core_entry.ts} +223 -149
- package/src/core/{main/worker/worker_text_displayer_interface.ts → entry/core_text_displayer_interface.ts} +26 -26
- package/src/core/{main/common → entry}/create_content_time_boundaries_observer.ts +7 -7
- package/src/core/{main/common → entry}/get_buffered_data_per_media_buffer.ts +6 -6
- package/src/core/{main/common → entry}/get_thumbnail_data.ts +5 -5
- package/src/core/entry/index.ts +4 -0
- package/src/core/{main/common → entry}/synchronize_sinks_on_observation.ts +2 -2
- package/src/core/{main/worker → entry}/track_choice_setter.ts +7 -7
- package/src/core/entry/utils.ts +11 -0
- package/src/core/stream/orchestrator/stream_orchestrator.ts +26 -1
- package/src/core/types.ts +631 -3
- package/src/experimental/features/__tests__/local.test.ts +11 -2
- package/src/experimental/features/__tests__/metaplaylist.test.ts +11 -2
- package/src/experimental/features/__tests__/multi_thread.test.ts +8 -3
- package/src/experimental/features/local.ts +7 -1
- package/src/experimental/features/metaplaylist.ts +7 -1
- package/src/experimental/features/multi_thread.ts +6 -2
- package/src/features/features_object.ts +1 -1
- package/src/features/list/__tests__/dash.test.ts +12 -3
- package/src/features/list/__tests__/smooth.test.ts +11 -2
- package/src/features/list/dash.ts +7 -1
- package/src/features/list/dash_wasm.ts +7 -1
- package/src/features/list/media_source_main.ts +7 -1
- package/src/features/list/smooth.ts +7 -1
- package/src/features/types.ts +23 -4
- package/src/main_thread/README.md +8 -0
- package/src/main_thread/api/public_api.ts +46 -48
- package/src/main_thread/core_interface/README.md +22 -0
- package/src/main_thread/core_interface/base.ts +36 -0
- package/src/main_thread/core_interface/monothread.ts +46 -0
- package/src/main_thread/core_interface/multithread.ts +49 -0
- package/src/main_thread/core_interface/types.ts +5 -0
- package/src/main_thread/init/media_source_content_initializer.ts +2034 -1152
- package/src/main_thread/init/utils/create_core_playback_observer.ts +2 -1
- package/src/main_thread/init/utils/update_manifest_codec_support.ts +1 -1
- package/src/main_thread/types.ts +610 -0
- package/src/manifest/utils.ts +20 -4
- package/src/mse/worker_media_source_interface.ts +35 -35
- package/src/parsers/manifest/smooth/create_parser.ts +40 -34
- package/src/parsers/manifest/smooth/parse_C_nodes.ts +19 -8
- package/src/parsers/manifest/smooth/parse_protection_node.ts +17 -9
- package/src/parsers/manifest/smooth/utils/parseBoolean.ts +1 -1
- package/src/parsers/manifest/smooth/utils/reduceChildren.ts +10 -7
- package/src/playback_observer/{worker_playback_observer.ts → core_playback_observer.ts} +13 -13
- package/src/transports/smooth/pipelines.ts +25 -5
- package/src/worker_entry_point.ts +71 -2
- package/dist/commonjs/core/main/common/FreezeResolver.d.ts.map +0 -1
- package/dist/commonjs/core/main/common/content_time_boundaries_observer.d.ts.map +0 -1
- package/dist/commonjs/core/main/common/create_content_time_boundaries_observer.d.ts.map +0 -1
- package/dist/commonjs/core/main/common/get_buffered_data_per_media_buffer.d.ts.map +0 -1
- package/dist/commonjs/core/main/common/get_thumbnail_data.d.ts.map +0 -1
- package/dist/commonjs/core/main/common/synchronize_sinks_on_observation.d.ts.map +0 -1
- package/dist/commonjs/core/main/worker/content_preparer.d.ts.map +0 -1
- package/dist/commonjs/core/main/worker/globals.d.ts +0 -14
- package/dist/commonjs/core/main/worker/globals.d.ts.map +0 -1
- package/dist/commonjs/core/main/worker/globals.js +0 -26
- package/dist/commonjs/core/main/worker/index.d.ts +0 -3
- package/dist/commonjs/core/main/worker/index.d.ts.map +0 -1
- package/dist/commonjs/core/main/worker/index.js +0 -4
- package/dist/commonjs/core/main/worker/send_message.d.ts +0 -4
- package/dist/commonjs/core/main/worker/send_message.d.ts.map +0 -1
- package/dist/commonjs/core/main/worker/send_message.js +0 -23
- package/dist/commonjs/core/main/worker/track_choice_setter.d.ts.map +0 -1
- package/dist/commonjs/core/main/worker/worker_main.d.ts +0 -2
- package/dist/commonjs/core/main/worker/worker_main.d.ts.map +0 -1
- package/dist/commonjs/core/main/worker/worker_text_displayer_interface.d.ts.map +0 -1
- package/dist/commonjs/main_thread/init/multi_thread_content_initializer.d.ts +0 -308
- package/dist/commonjs/main_thread/init/multi_thread_content_initializer.d.ts.map +0 -1
- package/dist/commonjs/main_thread/init/multi_thread_content_initializer.js +0 -1713
- package/dist/commonjs/main_thread/init/send_message.d.ts +0 -3
- package/dist/commonjs/main_thread/init/send_message.d.ts.map +0 -1
- package/dist/commonjs/main_thread/init/send_message.js +0 -13
- package/dist/commonjs/multithread_types.d.ts +0 -915
- package/dist/commonjs/multithread_types.d.ts.map +0 -1
- package/dist/commonjs/multithread_types.js +0 -7
- package/dist/commonjs/playback_observer/worker_playback_observer.d.ts.map +0 -1
- package/dist/es2017/core/main/common/FreezeResolver.d.ts.map +0 -1
- package/dist/es2017/core/main/common/content_time_boundaries_observer.d.ts.map +0 -1
- package/dist/es2017/core/main/common/create_content_time_boundaries_observer.d.ts.map +0 -1
- package/dist/es2017/core/main/common/get_buffered_data_per_media_buffer.d.ts.map +0 -1
- package/dist/es2017/core/main/common/get_thumbnail_data.d.ts.map +0 -1
- package/dist/es2017/core/main/common/synchronize_sinks_on_observation.d.ts.map +0 -1
- package/dist/es2017/core/main/worker/content_preparer.d.ts.map +0 -1
- package/dist/es2017/core/main/worker/globals.d.ts +0 -14
- package/dist/es2017/core/main/worker/globals.d.ts.map +0 -1
- package/dist/es2017/core/main/worker/globals.js +0 -18
- package/dist/es2017/core/main/worker/index.d.ts +0 -3
- package/dist/es2017/core/main/worker/index.d.ts.map +0 -1
- package/dist/es2017/core/main/worker/index.js +0 -2
- package/dist/es2017/core/main/worker/send_message.d.ts +0 -4
- package/dist/es2017/core/main/worker/send_message.d.ts.map +0 -1
- package/dist/es2017/core/main/worker/send_message.js +0 -19
- package/dist/es2017/core/main/worker/track_choice_setter.d.ts.map +0 -1
- package/dist/es2017/core/main/worker/worker_main.d.ts +0 -2
- package/dist/es2017/core/main/worker/worker_main.d.ts.map +0 -1
- package/dist/es2017/core/main/worker/worker_text_displayer_interface.d.ts.map +0 -1
- package/dist/es2017/main_thread/init/multi_thread_content_initializer.d.ts +0 -308
- package/dist/es2017/main_thread/init/multi_thread_content_initializer.d.ts.map +0 -1
- package/dist/es2017/main_thread/init/multi_thread_content_initializer.js +0 -1559
- package/dist/es2017/main_thread/init/send_message.d.ts +0 -3
- package/dist/es2017/main_thread/init/send_message.d.ts.map +0 -1
- package/dist/es2017/main_thread/init/send_message.js +0 -10
- package/dist/es2017/multithread_types.d.ts +0 -915
- package/dist/es2017/multithread_types.d.ts.map +0 -1
- package/dist/es2017/multithread_types.js +0 -6
- package/dist/es2017/playback_observer/worker_playback_observer.d.ts.map +0 -1
- package/src/core/main/worker/globals.ts +0 -38
- package/src/core/main/worker/index.ts +0 -2
- package/src/core/main/worker/send_message.ts +0 -28
- package/src/main_thread/init/multi_thread_content_initializer.ts +0 -2330
- package/src/main_thread/init/send_message.ts +0 -15
- package/src/multithread_types.ts +0 -1095
- /package/dist/commonjs/core/{main/common → entry}/synchronize_sinks_on_observation.js +0 -0
- /package/dist/es2017/core/{main/common → entry}/synchronize_sinks_on_observation.js +0 -0
|
@@ -1,2330 +0,0 @@
|
|
|
1
|
-
import type { IMediaElement } from "../../compat/browser_compatibility_types";
|
|
2
|
-
import getEmeApiImplementation from "../../compat/eme";
|
|
3
|
-
import mayMediaElementFailOnUndecipherableData from "../../compat/may_media_element_fail_on_undecipherable_data";
|
|
4
|
-
import shouldReloadMediaSourceOnDecipherabilityUpdate from "../../compat/should_reload_media_source_on_decipherability_update";
|
|
5
|
-
import type { ISegmentSinkMetrics } from "../../core/segment_sinks/segment_sinks_store";
|
|
6
|
-
import type {
|
|
7
|
-
IAdaptiveRepresentationSelectorArguments,
|
|
8
|
-
IAdaptationChoice,
|
|
9
|
-
IResolutionInfo,
|
|
10
|
-
} from "../../core/types";
|
|
11
|
-
import {
|
|
12
|
-
EncryptedMediaError,
|
|
13
|
-
MediaError,
|
|
14
|
-
NetworkError,
|
|
15
|
-
OtherError,
|
|
16
|
-
SourceBufferError,
|
|
17
|
-
} from "../../errors";
|
|
18
|
-
import features from "../../features";
|
|
19
|
-
import log from "../../log";
|
|
20
|
-
import type { IManifestMetadata } from "../../manifest";
|
|
21
|
-
import {
|
|
22
|
-
replicateUpdatesOnManifestMetadata,
|
|
23
|
-
updateDecipherabilityFromKeyIds,
|
|
24
|
-
updateDecipherabilityFromProtectionData,
|
|
25
|
-
} from "../../manifest";
|
|
26
|
-
import MainMediaSourceInterface from "../../mse/main_media_source_interface";
|
|
27
|
-
import type {
|
|
28
|
-
ICreateMediaSourceWorkerMessage,
|
|
29
|
-
ISentError,
|
|
30
|
-
ISentLogValue,
|
|
31
|
-
IWorkerMessage,
|
|
32
|
-
} from "../../multithread_types";
|
|
33
|
-
import { MainThreadMessageType, WorkerMessageType } from "../../multithread_types";
|
|
34
|
-
import type {
|
|
35
|
-
IReadOnlyPlaybackObserver,
|
|
36
|
-
IMediaElementPlaybackObserver,
|
|
37
|
-
} from "../../playback_observer";
|
|
38
|
-
import type { IWorkerPlaybackObservation } from "../../playback_observer/worker_playback_observer";
|
|
39
|
-
import type {
|
|
40
|
-
ICmcdOptions,
|
|
41
|
-
IInitialManifest,
|
|
42
|
-
IKeySystemOption,
|
|
43
|
-
IPlayerError,
|
|
44
|
-
} from "../../public_types";
|
|
45
|
-
import type { IThumbnailResponse, ITransportOptions } from "../../transports";
|
|
46
|
-
import arrayFind from "../../utils/array_find";
|
|
47
|
-
import assert, { assertUnreachable } from "../../utils/assert";
|
|
48
|
-
import idGenerator from "../../utils/id_generator";
|
|
49
|
-
import isNullOrUndefined from "../../utils/is_null_or_undefined";
|
|
50
|
-
import type { IAcceptedLogValue } from "../../utils/logger";
|
|
51
|
-
import objectAssign from "../../utils/object_assign";
|
|
52
|
-
import type { IReadOnlySharedReference } from "../../utils/reference";
|
|
53
|
-
import SharedReference from "../../utils/reference";
|
|
54
|
-
import { RequestError } from "../../utils/request";
|
|
55
|
-
import type { CancellationSignal } from "../../utils/task_canceller";
|
|
56
|
-
import TaskCanceller, { CancellationError } from "../../utils/task_canceller";
|
|
57
|
-
import type { IContentProtection } from "../decrypt";
|
|
58
|
-
import type IContentDecryptor from "../decrypt";
|
|
59
|
-
import { ContentDecryptorState, getKeySystemConfiguration } from "../decrypt";
|
|
60
|
-
import type { ITextDisplayer } from "../text_displayer";
|
|
61
|
-
import sendMessage from "./send_message";
|
|
62
|
-
import type { ITextDisplayerOptions } from "./types";
|
|
63
|
-
import { ContentInitializer } from "./types";
|
|
64
|
-
import createCorePlaybackObserver from "./utils/create_core_playback_observer";
|
|
65
|
-
import {
|
|
66
|
-
resetMediaElement,
|
|
67
|
-
disableRemotePlaybackOnManagedMediaSource,
|
|
68
|
-
} from "./utils/create_media_source";
|
|
69
|
-
import type { IInitialTimeOptions } from "./utils/get_initial_time";
|
|
70
|
-
import getInitialTime from "./utils/get_initial_time";
|
|
71
|
-
import getLoadedReference from "./utils/get_loaded_reference";
|
|
72
|
-
import performInitialSeekAndPlay from "./utils/initial_seek_and_play";
|
|
73
|
-
import RebufferingController from "./utils/rebuffering_controller";
|
|
74
|
-
import StreamEventsEmitter from "./utils/stream_events_emitter/stream_events_emitter";
|
|
75
|
-
import listenToMediaError from "./utils/throw_on_media_error";
|
|
76
|
-
import { updateManifestCodecSupport } from "./utils/update_manifest_codec_support";
|
|
77
|
-
|
|
78
|
-
const generateContentId = idGenerator();
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* @class MultiThreadContentInitializer
|
|
82
|
-
*/
|
|
83
|
-
export default class MultiThreadContentInitializer extends ContentInitializer {
|
|
84
|
-
/** Constructor settings associated to this `MultiThreadContentInitializer`. */
|
|
85
|
-
private _settings: IInitializeArguments;
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* The WebWorker may be sending messages as soon as we're preparing the
|
|
89
|
-
* content but the `MultiThreadContentInitializer` is only able to handle all of
|
|
90
|
-
* them only once `start`ed.
|
|
91
|
-
*
|
|
92
|
-
* As such `_queuedWorkerMessages` is set to an Array when `prepare` has been
|
|
93
|
-
* called but not `start` yet, and contains all worker messages that have to
|
|
94
|
-
* be processed when `start` is called.
|
|
95
|
-
*
|
|
96
|
-
* It is set to `null` when there's no need to rely on that queue (either not
|
|
97
|
-
* yet `prepare`d or already `start`ed).
|
|
98
|
-
*/
|
|
99
|
-
private _queuedWorkerMessages: MessageEvent[] | null;
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Information relative to the current loaded content.
|
|
103
|
-
*
|
|
104
|
-
* `null` when no content is prepared yet.
|
|
105
|
-
*/
|
|
106
|
-
private _currentContentInfo: IMultiThreadContentInitializerContentInfos | null;
|
|
107
|
-
/**
|
|
108
|
-
* `TaskCanceller` allowing to abort everything that the
|
|
109
|
-
* `MultiThreadContentInitializer` is doing.
|
|
110
|
-
*/
|
|
111
|
-
private _initCanceller: TaskCanceller;
|
|
112
|
-
/**
|
|
113
|
-
* `TaskCanceller` allowing to abort and clean-up every task and resource
|
|
114
|
-
* linked to the current `MediaSource` instance.
|
|
115
|
-
*
|
|
116
|
-
* It may be triggered either at content stop (and thus at the same time than
|
|
117
|
-
* the `_initCanceller`) or when reloading the content.
|
|
118
|
-
*/
|
|
119
|
-
private _currentMediaSourceCanceller: TaskCanceller;
|
|
120
|
-
|
|
121
|
-
private _awaitingRequests: {
|
|
122
|
-
nextRequestId: number;
|
|
123
|
-
/**
|
|
124
|
-
* Stores the resolvers and the current messageId that is sent to the web worker to
|
|
125
|
-
* receive segment sink metrics.
|
|
126
|
-
* The purpose of collecting metrics is for monitoring and debugging.
|
|
127
|
-
*/
|
|
128
|
-
pendingSinkMetrics: Map<
|
|
129
|
-
number /* request id */,
|
|
130
|
-
{
|
|
131
|
-
resolve: (value: ISegmentSinkMetrics | undefined) => void;
|
|
132
|
-
}
|
|
133
|
-
>;
|
|
134
|
-
/**
|
|
135
|
-
* Stores the resolvers and the current messageId that is sent to the web worker to
|
|
136
|
-
* receive image thumbnails.
|
|
137
|
-
*/
|
|
138
|
-
pendingThumbnailFetching: Map<
|
|
139
|
-
number /* request id */,
|
|
140
|
-
{
|
|
141
|
-
resolve: (value: IThumbnailResponse) => void;
|
|
142
|
-
reject: (error: Error) => void;
|
|
143
|
-
}
|
|
144
|
-
>;
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Create a new `MultiThreadContentInitializer`, associated to the given
|
|
149
|
-
* settings.
|
|
150
|
-
* @param {Object} settings
|
|
151
|
-
*/
|
|
152
|
-
constructor(settings: IInitializeArguments) {
|
|
153
|
-
super();
|
|
154
|
-
this._settings = settings;
|
|
155
|
-
this._initCanceller = new TaskCanceller();
|
|
156
|
-
this._currentMediaSourceCanceller = new TaskCanceller();
|
|
157
|
-
this._currentMediaSourceCanceller.linkToSignal(this._initCanceller.signal);
|
|
158
|
-
this._currentContentInfo = null;
|
|
159
|
-
this._awaitingRequests = {
|
|
160
|
-
nextRequestId: 0,
|
|
161
|
-
pendingSinkMetrics: new Map(),
|
|
162
|
-
pendingThumbnailFetching: new Map(),
|
|
163
|
-
};
|
|
164
|
-
this._queuedWorkerMessages = null;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Perform non-destructive preparation steps, to prepare a future content.
|
|
169
|
-
*/
|
|
170
|
-
public prepare(): void {
|
|
171
|
-
if (this._currentContentInfo !== null || this._initCanceller.isUsed()) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
const contentId = generateContentId();
|
|
175
|
-
const { adaptiveOptions, transportOptions, useMseInWorker, worker } = this._settings;
|
|
176
|
-
const { wantedBufferAhead, maxVideoBufferSize, maxBufferAhead, maxBufferBehind } =
|
|
177
|
-
this._settings.bufferOptions;
|
|
178
|
-
const initialVideoBitrate = adaptiveOptions.initialBitrates.video;
|
|
179
|
-
const initialAudioBitrate = adaptiveOptions.initialBitrates.audio;
|
|
180
|
-
this._currentContentInfo = {
|
|
181
|
-
contentId,
|
|
182
|
-
contentDecryptor: null,
|
|
183
|
-
manifest: null,
|
|
184
|
-
mediaSourceInfo: null,
|
|
185
|
-
rebufferingController: null,
|
|
186
|
-
streamEventsEmitter: null,
|
|
187
|
-
initialTime: undefined,
|
|
188
|
-
autoPlay: undefined,
|
|
189
|
-
initialPlayPerformed: null,
|
|
190
|
-
useMseInWorker,
|
|
191
|
-
};
|
|
192
|
-
sendMessage(worker, {
|
|
193
|
-
type: MainThreadMessageType.PrepareContent,
|
|
194
|
-
value: {
|
|
195
|
-
contentId,
|
|
196
|
-
cmcd: this._settings.cmcd,
|
|
197
|
-
enableRepresentationAvoidance: this._settings.enableRepresentationAvoidance,
|
|
198
|
-
url: this._settings.url,
|
|
199
|
-
hasText: this._hasTextBufferFeature(),
|
|
200
|
-
transportOptions,
|
|
201
|
-
initialVideoBitrate,
|
|
202
|
-
initialAudioBitrate,
|
|
203
|
-
manifestRetryOptions: {
|
|
204
|
-
...this._settings.manifestRequestSettings,
|
|
205
|
-
lowLatencyMode: this._settings.lowLatencyMode,
|
|
206
|
-
},
|
|
207
|
-
segmentRetryOptions: this._settings.segmentRequestOptions,
|
|
208
|
-
useMseInWorker,
|
|
209
|
-
},
|
|
210
|
-
});
|
|
211
|
-
this._initCanceller.signal.register(() => {
|
|
212
|
-
sendMessage(worker, {
|
|
213
|
-
type: MainThreadMessageType.StopContent,
|
|
214
|
-
contentId,
|
|
215
|
-
value: null,
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
if (this._initCanceller.isUsed()) {
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
this._queuedWorkerMessages = [];
|
|
222
|
-
log.debug("Init", "addEventListener prepare buffering worker messages");
|
|
223
|
-
const onmessage = (evt: MessageEvent): void => {
|
|
224
|
-
const msgData = evt.data as unknown as IWorkerMessage;
|
|
225
|
-
const type = msgData.type;
|
|
226
|
-
switch (type) {
|
|
227
|
-
case WorkerMessageType.LogMessage: {
|
|
228
|
-
const formatted: IAcceptedLogValue[] = msgData.value.logs.map((l) => {
|
|
229
|
-
switch (typeof l) {
|
|
230
|
-
case "string":
|
|
231
|
-
case "number":
|
|
232
|
-
case "boolean":
|
|
233
|
-
case "undefined":
|
|
234
|
-
return l;
|
|
235
|
-
case "object":
|
|
236
|
-
if (l === null) {
|
|
237
|
-
return null;
|
|
238
|
-
}
|
|
239
|
-
return formatSentLogObject(l);
|
|
240
|
-
default:
|
|
241
|
-
assertUnreachable(l);
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
switch (msgData.value.logLevel) {
|
|
245
|
-
case "NONE":
|
|
246
|
-
break;
|
|
247
|
-
case "ERROR":
|
|
248
|
-
log.error(msgData.value.namespace, ...formatted);
|
|
249
|
-
break;
|
|
250
|
-
case "WARNING":
|
|
251
|
-
log.warn(msgData.value.namespace, ...formatted);
|
|
252
|
-
break;
|
|
253
|
-
case "INFO":
|
|
254
|
-
log.info(msgData.value.namespace, ...formatted);
|
|
255
|
-
break;
|
|
256
|
-
case "DEBUG":
|
|
257
|
-
log.debug(msgData.value.namespace, ...formatted);
|
|
258
|
-
break;
|
|
259
|
-
default:
|
|
260
|
-
assertUnreachable(msgData.value.logLevel);
|
|
261
|
-
}
|
|
262
|
-
break;
|
|
263
|
-
}
|
|
264
|
-
default:
|
|
265
|
-
if (this._queuedWorkerMessages !== null) {
|
|
266
|
-
this._queuedWorkerMessages.push(evt);
|
|
267
|
-
}
|
|
268
|
-
break;
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
|
-
this._settings.worker.addEventListener("message", onmessage);
|
|
272
|
-
const onmessageerror = (_msg: MessageEvent) => {
|
|
273
|
-
log.error("Init", "Error when receiving message from worker.");
|
|
274
|
-
};
|
|
275
|
-
this._settings.worker.addEventListener("messageerror", onmessageerror);
|
|
276
|
-
this._initCanceller.signal.register(() => {
|
|
277
|
-
log.debug("Init", "removeEventListener prepare for worker message");
|
|
278
|
-
this._settings.worker.removeEventListener("message", onmessage);
|
|
279
|
-
this._settings.worker.removeEventListener("messageerror", onmessageerror);
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
// Also bind all `SharedReference` objects:
|
|
283
|
-
|
|
284
|
-
const throttleVideoBitrate =
|
|
285
|
-
adaptiveOptions.throttlers.throttleBitrate.video ?? new SharedReference(Infinity);
|
|
286
|
-
bindNumberReferencesToWorker(
|
|
287
|
-
worker,
|
|
288
|
-
this._initCanceller.signal,
|
|
289
|
-
[wantedBufferAhead, "wantedBufferAhead"],
|
|
290
|
-
[maxVideoBufferSize, "maxVideoBufferSize"],
|
|
291
|
-
[maxBufferAhead, "maxBufferAhead"],
|
|
292
|
-
[maxBufferBehind, "maxBufferBehind"],
|
|
293
|
-
[throttleVideoBitrate, "throttleVideoBitrate"],
|
|
294
|
-
);
|
|
295
|
-
|
|
296
|
-
const limitVideoResolution =
|
|
297
|
-
adaptiveOptions.throttlers.limitResolution.video ??
|
|
298
|
-
new SharedReference<IResolutionInfo>({
|
|
299
|
-
height: undefined,
|
|
300
|
-
width: undefined,
|
|
301
|
-
pixelRatio: 1,
|
|
302
|
-
});
|
|
303
|
-
limitVideoResolution.onUpdate(
|
|
304
|
-
(newVal) => {
|
|
305
|
-
sendMessage(worker, {
|
|
306
|
-
type: MainThreadMessageType.ReferenceUpdate,
|
|
307
|
-
value: { name: "limitVideoResolution", newVal },
|
|
308
|
-
});
|
|
309
|
-
},
|
|
310
|
-
{ clearSignal: this._initCanceller.signal, emitCurrentValue: true },
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* Update URL of the Manifest.
|
|
316
|
-
* @param {Array.<string>|undefined} urls - URLs to reach that Manifest from
|
|
317
|
-
* the most prioritized URL to the least prioritized URL.
|
|
318
|
-
* @param {boolean} refreshNow - If `true` the resource in question (e.g.
|
|
319
|
-
* DASH's MPD) will be refreshed immediately.
|
|
320
|
-
*/
|
|
321
|
-
public updateContentUrls(urls: string[] | undefined, refreshNow: boolean): void {
|
|
322
|
-
if (this._currentContentInfo === null) {
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
sendMessage(this._settings.worker, {
|
|
326
|
-
type: MainThreadMessageType.ContentUrlsUpdate,
|
|
327
|
-
contentId: this._currentContentInfo.contentId,
|
|
328
|
-
value: { urls, refreshNow },
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* @param {HTMLMediaElement} mediaElement
|
|
334
|
-
* @param {Object} playbackObserver
|
|
335
|
-
*/
|
|
336
|
-
public start(
|
|
337
|
-
mediaElement: IMediaElement,
|
|
338
|
-
playbackObserver: IMediaElementPlaybackObserver,
|
|
339
|
-
): void {
|
|
340
|
-
this.prepare(); // Load Manifest if not already done
|
|
341
|
-
if (this._initCanceller.isUsed()) {
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
let textDisplayer: ITextDisplayer | null = null;
|
|
346
|
-
if (
|
|
347
|
-
this._settings.textTrackOptions.textTrackMode === "html" &&
|
|
348
|
-
features.htmlTextDisplayer !== null
|
|
349
|
-
) {
|
|
350
|
-
assert(this._hasTextBufferFeature());
|
|
351
|
-
textDisplayer = new features.htmlTextDisplayer(
|
|
352
|
-
mediaElement,
|
|
353
|
-
this._settings.textTrackOptions.textTrackElement,
|
|
354
|
-
);
|
|
355
|
-
} else if (features.nativeTextDisplayer !== null) {
|
|
356
|
-
assert(this._hasTextBufferFeature());
|
|
357
|
-
textDisplayer = new features.nativeTextDisplayer(mediaElement);
|
|
358
|
-
} else {
|
|
359
|
-
assert(!this._hasTextBufferFeature());
|
|
360
|
-
}
|
|
361
|
-
this._initCanceller.signal.register(() => {
|
|
362
|
-
textDisplayer?.stop();
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
/** Translate errors coming from the media element into RxPlayer errors. */
|
|
366
|
-
listenToMediaError(
|
|
367
|
-
mediaElement,
|
|
368
|
-
(error: MediaError) => this._onFatalError(error),
|
|
369
|
-
this._initCanceller.signal,
|
|
370
|
-
);
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* Send content protection initialization data.
|
|
374
|
-
* TODO remove and use ContentDecryptor directly when possible.
|
|
375
|
-
*/
|
|
376
|
-
const lastContentProtection = new SharedReference<IContentProtection | null>(null);
|
|
377
|
-
|
|
378
|
-
const mediaSourceStatus = new SharedReference<MediaSourceInitializationStatus>(
|
|
379
|
-
MediaSourceInitializationStatus.Nothing,
|
|
380
|
-
);
|
|
381
|
-
|
|
382
|
-
const { statusRef: drmInitializationStatus, contentDecryptor } =
|
|
383
|
-
this._initializeContentDecryption(
|
|
384
|
-
mediaElement,
|
|
385
|
-
lastContentProtection,
|
|
386
|
-
mediaSourceStatus,
|
|
387
|
-
() => notifyAndStartMediaSourceReload(0, undefined, undefined),
|
|
388
|
-
this._initCanceller.signal,
|
|
389
|
-
);
|
|
390
|
-
const contentInfo = this._currentContentInfo;
|
|
391
|
-
if (contentInfo !== null) {
|
|
392
|
-
contentInfo.contentDecryptor = contentDecryptor;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
const playbackStartParams = {
|
|
396
|
-
mediaElement,
|
|
397
|
-
textDisplayer,
|
|
398
|
-
playbackObserver,
|
|
399
|
-
drmInitializationStatus,
|
|
400
|
-
mediaSourceStatus,
|
|
401
|
-
};
|
|
402
|
-
mediaSourceStatus.onUpdate(
|
|
403
|
-
(msInitStatus, stopListeningMSStatus) => {
|
|
404
|
-
if (msInitStatus === MediaSourceInitializationStatus.Attached) {
|
|
405
|
-
stopListeningMSStatus();
|
|
406
|
-
this._startPlaybackIfReady(playbackStartParams);
|
|
407
|
-
}
|
|
408
|
-
},
|
|
409
|
-
{ clearSignal: this._initCanceller.signal, emitCurrentValue: true },
|
|
410
|
-
);
|
|
411
|
-
drmInitializationStatus.onUpdate(
|
|
412
|
-
(initializationStatus, stopListeningDrm) => {
|
|
413
|
-
if (initializationStatus.initializationState.type === "initialized") {
|
|
414
|
-
stopListeningDrm();
|
|
415
|
-
this._startPlaybackIfReady(playbackStartParams);
|
|
416
|
-
}
|
|
417
|
-
},
|
|
418
|
-
{ emitCurrentValue: true, clearSignal: this._initCanceller.signal },
|
|
419
|
-
);
|
|
420
|
-
|
|
421
|
-
/**
|
|
422
|
-
* Reset directly (synchronously) the current `MediaSource` and signal to
|
|
423
|
-
* the core that we did so.
|
|
424
|
-
* @param {number} deltaPosition - Position you want to seek to after
|
|
425
|
-
* reloading, as a delta in seconds from the last polled playing position.
|
|
426
|
-
* @param {number|undefined} minimumPosition - If set, minimum time bound
|
|
427
|
-
* in seconds after `deltaPosition` has been applied.
|
|
428
|
-
* @param {number|undefined} maximumPosition - If set, minimum time bound
|
|
429
|
-
* in seconds after `deltaPosition` has been applied.
|
|
430
|
-
*/
|
|
431
|
-
const notifyAndStartMediaSourceReload = (
|
|
432
|
-
deltaPosition: number,
|
|
433
|
-
minimumPosition: number | undefined,
|
|
434
|
-
maximumPosition: number | undefined,
|
|
435
|
-
): void => {
|
|
436
|
-
const reloadingContentInfo = this._currentContentInfo;
|
|
437
|
-
if (reloadingContentInfo === null) {
|
|
438
|
-
log.warn("Init", "Asked to reload when no content is loaded.");
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
if (
|
|
442
|
-
reloadingContentInfo === null ||
|
|
443
|
-
reloadingContentInfo.mediaSourceInfo === null
|
|
444
|
-
) {
|
|
445
|
-
log.warn("Init", "Asked to reload when no MediaSource is active.");
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
const mediaSourceId =
|
|
450
|
-
reloadingContentInfo.mediaSourceInfo.type === "main"
|
|
451
|
-
? reloadingContentInfo.mediaSourceInfo.mediaSource.id
|
|
452
|
-
: reloadingContentInfo.mediaSourceInfo.mediaSourceId;
|
|
453
|
-
sendMessage(this._settings.worker, {
|
|
454
|
-
type: MainThreadMessageType.MediaSourceReload,
|
|
455
|
-
mediaSourceId,
|
|
456
|
-
value: null,
|
|
457
|
-
});
|
|
458
|
-
reloadMediaSource(deltaPosition, minimumPosition, maximumPosition);
|
|
459
|
-
};
|
|
460
|
-
|
|
461
|
-
/**
|
|
462
|
-
* Reset directly (synchronously) the current `MediaSource`.
|
|
463
|
-
*
|
|
464
|
-
* It is assumed that `core` already knows about this action. If not, call
|
|
465
|
-
* `notifyAndStartMediaSourceReload` instead.
|
|
466
|
-
* @param {number} deltaPosition - Position you want to seek to after
|
|
467
|
-
* reloading, as a delta in seconds from the last polled playing position.
|
|
468
|
-
* @param {number|undefined} minimumPosition - If set, minimum time bound
|
|
469
|
-
* in seconds after `deltaPosition` has been applied.
|
|
470
|
-
* @param {number|undefined} maximumPosition - If set, minimum time bound
|
|
471
|
-
* in seconds after `deltaPosition` has been applied.
|
|
472
|
-
*/
|
|
473
|
-
const reloadMediaSource = (
|
|
474
|
-
deltaPosition: number,
|
|
475
|
-
minimumPosition: number | undefined,
|
|
476
|
-
maximumPosition: number | undefined,
|
|
477
|
-
): void => {
|
|
478
|
-
const reloadingContentInfo = this._currentContentInfo;
|
|
479
|
-
if (reloadingContentInfo === null) {
|
|
480
|
-
log.warn("Init", "Asked to reload when no content is loaded.");
|
|
481
|
-
return;
|
|
482
|
-
}
|
|
483
|
-
const lastObservation = playbackObserver.getReference().getValue();
|
|
484
|
-
const currentPosition = lastObservation.position.getWanted();
|
|
485
|
-
const isPaused =
|
|
486
|
-
reloadingContentInfo.initialPlayPerformed?.getValue() === true ||
|
|
487
|
-
reloadingContentInfo.autoPlay === undefined
|
|
488
|
-
? lastObservation.paused
|
|
489
|
-
: !reloadingContentInfo.autoPlay;
|
|
490
|
-
let position = currentPosition + deltaPosition;
|
|
491
|
-
if (minimumPosition !== undefined) {
|
|
492
|
-
position = Math.max(minimumPosition, position);
|
|
493
|
-
}
|
|
494
|
-
if (maximumPosition !== undefined) {
|
|
495
|
-
position = Math.min(maximumPosition, position);
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
this._reload(
|
|
499
|
-
mediaElement,
|
|
500
|
-
textDisplayer,
|
|
501
|
-
playbackObserver,
|
|
502
|
-
mediaSourceStatus,
|
|
503
|
-
position,
|
|
504
|
-
!isPaused,
|
|
505
|
-
);
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
const onmessage = (msg: MessageEvent) => {
|
|
509
|
-
const msgData = msg.data as unknown as IWorkerMessage;
|
|
510
|
-
switch (msgData.type) {
|
|
511
|
-
case WorkerMessageType.AttachMediaSource: {
|
|
512
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
513
|
-
return;
|
|
514
|
-
}
|
|
515
|
-
if (this._currentContentInfo !== null) {
|
|
516
|
-
if (this._currentContentInfo.mediaSourceInfo?.type === "main") {
|
|
517
|
-
this._currentContentInfo.mediaSourceInfo.mediaSource.dispose();
|
|
518
|
-
}
|
|
519
|
-
this._currentContentInfo.mediaSourceInfo = {
|
|
520
|
-
type: "core",
|
|
521
|
-
mediaSourceId: msgData.mediaSourceId,
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
const mediaSourceLink = msgData.value;
|
|
526
|
-
mediaSourceStatus.onUpdate(
|
|
527
|
-
(currStatus, stopListening) => {
|
|
528
|
-
if (currStatus === MediaSourceInitializationStatus.AttachNow) {
|
|
529
|
-
stopListening();
|
|
530
|
-
log.info("media", "Attaching MediaSource URL to the media element");
|
|
531
|
-
if (mediaSourceLink.type === "handle") {
|
|
532
|
-
mediaElement.srcObject = mediaSourceLink.value;
|
|
533
|
-
this._currentMediaSourceCanceller.signal.register(() => {
|
|
534
|
-
mediaElement.srcObject = null;
|
|
535
|
-
});
|
|
536
|
-
} else {
|
|
537
|
-
mediaElement.src = mediaSourceLink.value;
|
|
538
|
-
this._currentMediaSourceCanceller.signal.register(() => {
|
|
539
|
-
resetMediaElement(mediaElement, mediaSourceLink.value);
|
|
540
|
-
});
|
|
541
|
-
}
|
|
542
|
-
disableRemotePlaybackOnManagedMediaSource(
|
|
543
|
-
mediaElement,
|
|
544
|
-
this._currentMediaSourceCanceller.signal,
|
|
545
|
-
);
|
|
546
|
-
mediaSourceStatus.setValue(MediaSourceInitializationStatus.Attached);
|
|
547
|
-
}
|
|
548
|
-
},
|
|
549
|
-
{ emitCurrentValue: true, clearSignal: this._initCanceller.signal },
|
|
550
|
-
);
|
|
551
|
-
break;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
case WorkerMessageType.Warning:
|
|
555
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
|
-
this.trigger("warning", formatWorkerError(msgData.value));
|
|
559
|
-
break;
|
|
560
|
-
|
|
561
|
-
case WorkerMessageType.Error:
|
|
562
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
563
|
-
return;
|
|
564
|
-
}
|
|
565
|
-
this._onFatalError(formatWorkerError(msgData.value));
|
|
566
|
-
break;
|
|
567
|
-
|
|
568
|
-
case WorkerMessageType.CreateMediaSource:
|
|
569
|
-
this._onCreateMediaSourceMessage(
|
|
570
|
-
msgData,
|
|
571
|
-
mediaElement,
|
|
572
|
-
mediaSourceStatus,
|
|
573
|
-
this._settings.worker,
|
|
574
|
-
);
|
|
575
|
-
break;
|
|
576
|
-
|
|
577
|
-
case WorkerMessageType.AddSourceBuffer:
|
|
578
|
-
{
|
|
579
|
-
if (
|
|
580
|
-
this._currentContentInfo?.mediaSourceInfo?.type !== "main" ||
|
|
581
|
-
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
582
|
-
msgData.mediaSourceId
|
|
583
|
-
) {
|
|
584
|
-
return;
|
|
585
|
-
}
|
|
586
|
-
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
587
|
-
mediaSource.addSourceBuffer(
|
|
588
|
-
msgData.value.sourceBufferType,
|
|
589
|
-
msgData.value.codec,
|
|
590
|
-
);
|
|
591
|
-
}
|
|
592
|
-
break;
|
|
593
|
-
|
|
594
|
-
case WorkerMessageType.SourceBufferAppend:
|
|
595
|
-
{
|
|
596
|
-
if (
|
|
597
|
-
this._currentContentInfo?.mediaSourceInfo?.type !== "main" ||
|
|
598
|
-
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
599
|
-
msgData.mediaSourceId
|
|
600
|
-
) {
|
|
601
|
-
return;
|
|
602
|
-
}
|
|
603
|
-
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
604
|
-
const sourceBuffer = arrayFind(
|
|
605
|
-
mediaSource.sourceBuffers,
|
|
606
|
-
(s) => s.type === msgData.sourceBufferType,
|
|
607
|
-
);
|
|
608
|
-
if (sourceBuffer === undefined) {
|
|
609
|
-
return;
|
|
610
|
-
}
|
|
611
|
-
sourceBuffer
|
|
612
|
-
.appendBuffer(msgData.value.data, msgData.value.params)
|
|
613
|
-
.then((buffered) => {
|
|
614
|
-
sendMessage(this._settings.worker, {
|
|
615
|
-
type: MainThreadMessageType.SourceBufferSuccess,
|
|
616
|
-
mediaSourceId: mediaSource.id,
|
|
617
|
-
sourceBufferType: sourceBuffer.type,
|
|
618
|
-
operationId: msgData.operationId,
|
|
619
|
-
value: { buffered },
|
|
620
|
-
});
|
|
621
|
-
})
|
|
622
|
-
.catch((error) => {
|
|
623
|
-
sendMessage(this._settings.worker, {
|
|
624
|
-
type: MainThreadMessageType.SourceBufferError,
|
|
625
|
-
mediaSourceId: mediaSource.id,
|
|
626
|
-
sourceBufferType: sourceBuffer.type,
|
|
627
|
-
operationId: msgData.operationId,
|
|
628
|
-
value:
|
|
629
|
-
error instanceof CancellationError
|
|
630
|
-
? { errorName: "CancellationError" }
|
|
631
|
-
: formatSourceBufferError(error).serialize(),
|
|
632
|
-
});
|
|
633
|
-
});
|
|
634
|
-
}
|
|
635
|
-
break;
|
|
636
|
-
|
|
637
|
-
case WorkerMessageType.SourceBufferRemove:
|
|
638
|
-
{
|
|
639
|
-
if (
|
|
640
|
-
this._currentContentInfo?.mediaSourceInfo?.type !== "main" ||
|
|
641
|
-
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
642
|
-
msgData.mediaSourceId
|
|
643
|
-
) {
|
|
644
|
-
return;
|
|
645
|
-
}
|
|
646
|
-
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
647
|
-
const sourceBuffer = arrayFind(
|
|
648
|
-
mediaSource.sourceBuffers,
|
|
649
|
-
(s) => s.type === msgData.sourceBufferType,
|
|
650
|
-
);
|
|
651
|
-
if (sourceBuffer === undefined) {
|
|
652
|
-
return;
|
|
653
|
-
}
|
|
654
|
-
sourceBuffer
|
|
655
|
-
.remove(msgData.value.start, msgData.value.end)
|
|
656
|
-
.then((buffered) => {
|
|
657
|
-
sendMessage(this._settings.worker, {
|
|
658
|
-
type: MainThreadMessageType.SourceBufferSuccess,
|
|
659
|
-
mediaSourceId: mediaSource.id,
|
|
660
|
-
sourceBufferType: sourceBuffer.type,
|
|
661
|
-
operationId: msgData.operationId,
|
|
662
|
-
value: { buffered },
|
|
663
|
-
});
|
|
664
|
-
})
|
|
665
|
-
.catch((error) => {
|
|
666
|
-
sendMessage(this._settings.worker, {
|
|
667
|
-
type: MainThreadMessageType.SourceBufferError,
|
|
668
|
-
mediaSourceId: mediaSource.id,
|
|
669
|
-
sourceBufferType: sourceBuffer.type,
|
|
670
|
-
operationId: msgData.operationId,
|
|
671
|
-
value:
|
|
672
|
-
error instanceof CancellationError
|
|
673
|
-
? { errorName: "CancellationError" }
|
|
674
|
-
: formatSourceBufferError(error).serialize(),
|
|
675
|
-
});
|
|
676
|
-
});
|
|
677
|
-
}
|
|
678
|
-
break;
|
|
679
|
-
|
|
680
|
-
case WorkerMessageType.AbortSourceBuffer:
|
|
681
|
-
{
|
|
682
|
-
if (
|
|
683
|
-
this._currentContentInfo?.mediaSourceInfo?.type !== "main" ||
|
|
684
|
-
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
685
|
-
msgData.mediaSourceId
|
|
686
|
-
) {
|
|
687
|
-
return;
|
|
688
|
-
}
|
|
689
|
-
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
690
|
-
const sourceBuffer = arrayFind(
|
|
691
|
-
mediaSource.sourceBuffers,
|
|
692
|
-
(s) => s.type === msgData.sourceBufferType,
|
|
693
|
-
);
|
|
694
|
-
if (sourceBuffer === undefined) {
|
|
695
|
-
return;
|
|
696
|
-
}
|
|
697
|
-
sourceBuffer.abort();
|
|
698
|
-
}
|
|
699
|
-
break;
|
|
700
|
-
|
|
701
|
-
case WorkerMessageType.UpdateMediaSourceDuration:
|
|
702
|
-
{
|
|
703
|
-
if (
|
|
704
|
-
this._currentContentInfo?.mediaSourceInfo?.type !== "main" ||
|
|
705
|
-
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
706
|
-
msgData.mediaSourceId
|
|
707
|
-
) {
|
|
708
|
-
return;
|
|
709
|
-
}
|
|
710
|
-
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
711
|
-
if (mediaSource?.id !== msgData.mediaSourceId) {
|
|
712
|
-
return;
|
|
713
|
-
}
|
|
714
|
-
mediaSource.setDuration(msgData.value.duration, msgData.value.isRealEndKnown);
|
|
715
|
-
}
|
|
716
|
-
break;
|
|
717
|
-
|
|
718
|
-
case WorkerMessageType.InterruptMediaSourceDurationUpdate:
|
|
719
|
-
{
|
|
720
|
-
if (
|
|
721
|
-
this._currentContentInfo?.mediaSourceInfo?.type !== "main" ||
|
|
722
|
-
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
723
|
-
msgData.mediaSourceId
|
|
724
|
-
) {
|
|
725
|
-
return;
|
|
726
|
-
}
|
|
727
|
-
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
728
|
-
if (mediaSource?.id !== msgData.mediaSourceId) {
|
|
729
|
-
return;
|
|
730
|
-
}
|
|
731
|
-
mediaSource.interruptDurationSetting();
|
|
732
|
-
}
|
|
733
|
-
break;
|
|
734
|
-
|
|
735
|
-
case WorkerMessageType.EndOfStream:
|
|
736
|
-
{
|
|
737
|
-
if (
|
|
738
|
-
this._currentContentInfo?.mediaSourceInfo?.type !== "main" ||
|
|
739
|
-
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
740
|
-
msgData.mediaSourceId
|
|
741
|
-
) {
|
|
742
|
-
return;
|
|
743
|
-
}
|
|
744
|
-
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
745
|
-
mediaSource.maintainEndOfStream();
|
|
746
|
-
}
|
|
747
|
-
break;
|
|
748
|
-
|
|
749
|
-
case WorkerMessageType.InterruptEndOfStream:
|
|
750
|
-
{
|
|
751
|
-
if (
|
|
752
|
-
this._currentContentInfo?.mediaSourceInfo?.type !== "main" ||
|
|
753
|
-
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
754
|
-
msgData.mediaSourceId
|
|
755
|
-
) {
|
|
756
|
-
return;
|
|
757
|
-
}
|
|
758
|
-
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
759
|
-
mediaSource.stopEndOfStream();
|
|
760
|
-
}
|
|
761
|
-
break;
|
|
762
|
-
|
|
763
|
-
case WorkerMessageType.DisposeMediaSource:
|
|
764
|
-
{
|
|
765
|
-
if (
|
|
766
|
-
this._currentContentInfo?.mediaSourceInfo?.type !== "main" ||
|
|
767
|
-
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
768
|
-
msgData.mediaSourceId
|
|
769
|
-
) {
|
|
770
|
-
return;
|
|
771
|
-
}
|
|
772
|
-
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
773
|
-
mediaSource.dispose();
|
|
774
|
-
}
|
|
775
|
-
break;
|
|
776
|
-
|
|
777
|
-
case WorkerMessageType.NeedsBufferFlush: {
|
|
778
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
779
|
-
return;
|
|
780
|
-
}
|
|
781
|
-
const lastObservation = playbackObserver.getReference().getValue();
|
|
782
|
-
const currentTime = lastObservation.position.isAwaitingFuturePosition()
|
|
783
|
-
? lastObservation.position.getWanted()
|
|
784
|
-
: mediaElement.currentTime;
|
|
785
|
-
const relativeResumingPosition = msgData.value?.relativeResumingPosition ?? 0;
|
|
786
|
-
const canBeApproximateSeek = Boolean(
|
|
787
|
-
msgData.value?.relativePosHasBeenDefaulted,
|
|
788
|
-
);
|
|
789
|
-
let wantedSeekingTime: number;
|
|
790
|
-
|
|
791
|
-
if (relativeResumingPosition === 0 && canBeApproximateSeek) {
|
|
792
|
-
// in case relativeResumingPosition is 0, we still perform
|
|
793
|
-
// a tiny seek to be sure that the browser will correclty reload the video.
|
|
794
|
-
wantedSeekingTime = currentTime + 0.001;
|
|
795
|
-
} else {
|
|
796
|
-
wantedSeekingTime = currentTime + relativeResumingPosition;
|
|
797
|
-
}
|
|
798
|
-
playbackObserver.setCurrentTime(wantedSeekingTime);
|
|
799
|
-
break;
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
case WorkerMessageType.ActivePeriodChanged: {
|
|
803
|
-
if (
|
|
804
|
-
this._currentContentInfo?.contentId !== msgData.contentId ||
|
|
805
|
-
this._currentContentInfo.manifest === null
|
|
806
|
-
) {
|
|
807
|
-
return;
|
|
808
|
-
}
|
|
809
|
-
const period = arrayFind(
|
|
810
|
-
this._currentContentInfo.manifest.periods,
|
|
811
|
-
(p) => p.id === msgData.value.periodId,
|
|
812
|
-
);
|
|
813
|
-
if (period !== undefined) {
|
|
814
|
-
this.trigger("activePeriodChanged", { period });
|
|
815
|
-
}
|
|
816
|
-
break;
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
case WorkerMessageType.AdaptationChanged: {
|
|
820
|
-
if (
|
|
821
|
-
this._currentContentInfo?.contentId !== msgData.contentId ||
|
|
822
|
-
this._currentContentInfo.manifest === null
|
|
823
|
-
) {
|
|
824
|
-
return;
|
|
825
|
-
}
|
|
826
|
-
const period = arrayFind(
|
|
827
|
-
this._currentContentInfo.manifest.periods,
|
|
828
|
-
(p) => p.id === msgData.value.periodId,
|
|
829
|
-
);
|
|
830
|
-
if (period === undefined) {
|
|
831
|
-
return;
|
|
832
|
-
}
|
|
833
|
-
if (msgData.value.adaptationId === null) {
|
|
834
|
-
this.trigger("adaptationChange", {
|
|
835
|
-
period,
|
|
836
|
-
adaptation: null,
|
|
837
|
-
type: msgData.value.type,
|
|
838
|
-
});
|
|
839
|
-
return;
|
|
840
|
-
}
|
|
841
|
-
const adaptations = period.adaptations[msgData.value.type] ?? [];
|
|
842
|
-
const adaptation = arrayFind(
|
|
843
|
-
adaptations,
|
|
844
|
-
(a) => a.id === msgData.value.adaptationId,
|
|
845
|
-
);
|
|
846
|
-
if (adaptation !== undefined) {
|
|
847
|
-
this.trigger("adaptationChange", {
|
|
848
|
-
period,
|
|
849
|
-
adaptation,
|
|
850
|
-
type: msgData.value.type,
|
|
851
|
-
});
|
|
852
|
-
}
|
|
853
|
-
break;
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
case WorkerMessageType.RepresentationChanged: {
|
|
857
|
-
if (
|
|
858
|
-
this._currentContentInfo?.contentId !== msgData.contentId ||
|
|
859
|
-
this._currentContentInfo.manifest === null
|
|
860
|
-
) {
|
|
861
|
-
return;
|
|
862
|
-
}
|
|
863
|
-
const period = arrayFind(
|
|
864
|
-
this._currentContentInfo.manifest.periods,
|
|
865
|
-
(p) => p.id === msgData.value.periodId,
|
|
866
|
-
);
|
|
867
|
-
if (period === undefined) {
|
|
868
|
-
return;
|
|
869
|
-
}
|
|
870
|
-
if (msgData.value.representationId === null) {
|
|
871
|
-
this.trigger("representationChange", {
|
|
872
|
-
period,
|
|
873
|
-
type: msgData.value.type,
|
|
874
|
-
representation: null,
|
|
875
|
-
});
|
|
876
|
-
return;
|
|
877
|
-
}
|
|
878
|
-
const adaptations = period.adaptations[msgData.value.type] ?? [];
|
|
879
|
-
const adaptation = arrayFind(
|
|
880
|
-
adaptations,
|
|
881
|
-
(a) => a.id === msgData.value.adaptationId,
|
|
882
|
-
);
|
|
883
|
-
if (adaptation === undefined) {
|
|
884
|
-
return;
|
|
885
|
-
}
|
|
886
|
-
const representation = arrayFind(
|
|
887
|
-
adaptation.representations,
|
|
888
|
-
(r) => r.id === msgData.value.representationId,
|
|
889
|
-
);
|
|
890
|
-
if (representation !== undefined) {
|
|
891
|
-
this.trigger("representationChange", {
|
|
892
|
-
period,
|
|
893
|
-
type: msgData.value.type,
|
|
894
|
-
representation,
|
|
895
|
-
});
|
|
896
|
-
}
|
|
897
|
-
break;
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
case WorkerMessageType.EncryptionDataEncountered:
|
|
901
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
902
|
-
return;
|
|
903
|
-
}
|
|
904
|
-
lastContentProtection.setValue(msgData.value);
|
|
905
|
-
break;
|
|
906
|
-
|
|
907
|
-
case WorkerMessageType.ManifestReady: {
|
|
908
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
909
|
-
return;
|
|
910
|
-
}
|
|
911
|
-
const manifest = msgData.value.manifest;
|
|
912
|
-
this._currentContentInfo.manifest = manifest;
|
|
913
|
-
this._updateCodecSupport(manifest, mediaElement);
|
|
914
|
-
this._startPlaybackIfReady(playbackStartParams);
|
|
915
|
-
break;
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
case WorkerMessageType.ManifestUpdate: {
|
|
919
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
920
|
-
return;
|
|
921
|
-
}
|
|
922
|
-
const manifest = this._currentContentInfo?.manifest;
|
|
923
|
-
if (isNullOrUndefined(manifest)) {
|
|
924
|
-
log.error("Init", "Manifest update but no Manifest loaded");
|
|
925
|
-
return;
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
replicateUpdatesOnManifestMetadata(
|
|
929
|
-
manifest,
|
|
930
|
-
msgData.value.manifest,
|
|
931
|
-
msgData.value.updates,
|
|
932
|
-
);
|
|
933
|
-
this._currentContentInfo?.streamEventsEmitter?.onManifestUpdate(manifest);
|
|
934
|
-
|
|
935
|
-
this._updateCodecSupport(manifest, mediaElement);
|
|
936
|
-
this.trigger("manifestUpdate", msgData.value.updates);
|
|
937
|
-
break;
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
case WorkerMessageType.UpdatePlaybackRate:
|
|
941
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
942
|
-
return;
|
|
943
|
-
}
|
|
944
|
-
playbackObserver.setPlaybackRate(msgData.value);
|
|
945
|
-
break;
|
|
946
|
-
|
|
947
|
-
case WorkerMessageType.BitrateEstimateChange:
|
|
948
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
949
|
-
return;
|
|
950
|
-
}
|
|
951
|
-
this.trigger("bitrateEstimateChange", {
|
|
952
|
-
type: msgData.value.bufferType,
|
|
953
|
-
bitrate: msgData.value.bitrate,
|
|
954
|
-
});
|
|
955
|
-
break;
|
|
956
|
-
|
|
957
|
-
case WorkerMessageType.InbandEvent:
|
|
958
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
959
|
-
return;
|
|
960
|
-
}
|
|
961
|
-
this.trigger("inbandEvents", msgData.value);
|
|
962
|
-
break;
|
|
963
|
-
|
|
964
|
-
case WorkerMessageType.LockedStream: {
|
|
965
|
-
if (
|
|
966
|
-
this._currentContentInfo?.contentId !== msgData.contentId ||
|
|
967
|
-
this._currentContentInfo.manifest === null
|
|
968
|
-
) {
|
|
969
|
-
return;
|
|
970
|
-
}
|
|
971
|
-
const period = arrayFind(
|
|
972
|
-
this._currentContentInfo.manifest.periods,
|
|
973
|
-
(p) => p.id === msgData.value.periodId,
|
|
974
|
-
);
|
|
975
|
-
if (period === undefined) {
|
|
976
|
-
return;
|
|
977
|
-
}
|
|
978
|
-
this._currentContentInfo.rebufferingController?.onLockedStream(
|
|
979
|
-
msgData.value.bufferType,
|
|
980
|
-
period,
|
|
981
|
-
);
|
|
982
|
-
break;
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
case WorkerMessageType.PeriodStreamReady: {
|
|
986
|
-
if (
|
|
987
|
-
this._currentContentInfo?.contentId !== msgData.contentId ||
|
|
988
|
-
this._currentContentInfo.manifest === null
|
|
989
|
-
) {
|
|
990
|
-
return;
|
|
991
|
-
}
|
|
992
|
-
const period = arrayFind(
|
|
993
|
-
this._currentContentInfo.manifest.periods,
|
|
994
|
-
(p) => p.id === msgData.value.periodId,
|
|
995
|
-
);
|
|
996
|
-
if (period === undefined) {
|
|
997
|
-
return;
|
|
998
|
-
}
|
|
999
|
-
const ref = new SharedReference<IAdaptationChoice | null | undefined>(
|
|
1000
|
-
undefined,
|
|
1001
|
-
);
|
|
1002
|
-
ref.onUpdate(
|
|
1003
|
-
(adapChoice) => {
|
|
1004
|
-
if (this._currentContentInfo === null) {
|
|
1005
|
-
ref.finish();
|
|
1006
|
-
return;
|
|
1007
|
-
}
|
|
1008
|
-
if (!isNullOrUndefined(adapChoice)) {
|
|
1009
|
-
adapChoice.representations.onUpdate(
|
|
1010
|
-
(repChoice, stopListening) => {
|
|
1011
|
-
if (this._currentContentInfo === null) {
|
|
1012
|
-
stopListening();
|
|
1013
|
-
return;
|
|
1014
|
-
}
|
|
1015
|
-
sendMessage(this._settings.worker, {
|
|
1016
|
-
type: MainThreadMessageType.RepresentationUpdate,
|
|
1017
|
-
contentId: this._currentContentInfo.contentId,
|
|
1018
|
-
value: {
|
|
1019
|
-
periodId: msgData.value.periodId,
|
|
1020
|
-
adaptationId: adapChoice.adaptationId,
|
|
1021
|
-
bufferType: msgData.value.bufferType,
|
|
1022
|
-
choice: repChoice,
|
|
1023
|
-
},
|
|
1024
|
-
});
|
|
1025
|
-
},
|
|
1026
|
-
{ clearSignal: this._initCanceller.signal },
|
|
1027
|
-
);
|
|
1028
|
-
}
|
|
1029
|
-
sendMessage(this._settings.worker, {
|
|
1030
|
-
type: MainThreadMessageType.TrackUpdate,
|
|
1031
|
-
contentId: this._currentContentInfo.contentId,
|
|
1032
|
-
value: {
|
|
1033
|
-
periodId: msgData.value.periodId,
|
|
1034
|
-
bufferType: msgData.value.bufferType,
|
|
1035
|
-
choice: isNullOrUndefined(adapChoice)
|
|
1036
|
-
? adapChoice
|
|
1037
|
-
: {
|
|
1038
|
-
adaptationId: adapChoice.adaptationId,
|
|
1039
|
-
switchingMode: adapChoice.switchingMode,
|
|
1040
|
-
initialRepresentations: adapChoice.representations.getValue(),
|
|
1041
|
-
relativeResumingPosition: adapChoice.relativeResumingPosition,
|
|
1042
|
-
},
|
|
1043
|
-
},
|
|
1044
|
-
});
|
|
1045
|
-
},
|
|
1046
|
-
{ clearSignal: this._initCanceller.signal },
|
|
1047
|
-
);
|
|
1048
|
-
this.trigger("periodStreamReady", {
|
|
1049
|
-
period,
|
|
1050
|
-
type: msgData.value.bufferType,
|
|
1051
|
-
adaptationRef: ref,
|
|
1052
|
-
});
|
|
1053
|
-
break;
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
case WorkerMessageType.PeriodStreamCleared: {
|
|
1057
|
-
if (
|
|
1058
|
-
this._currentContentInfo?.contentId !== msgData.contentId ||
|
|
1059
|
-
this._currentContentInfo.manifest === null
|
|
1060
|
-
) {
|
|
1061
|
-
return;
|
|
1062
|
-
}
|
|
1063
|
-
this.trigger("periodStreamCleared", {
|
|
1064
|
-
periodId: msgData.value.periodId,
|
|
1065
|
-
type: msgData.value.bufferType,
|
|
1066
|
-
});
|
|
1067
|
-
break;
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
case WorkerMessageType.DiscontinuityUpdate: {
|
|
1071
|
-
if (
|
|
1072
|
-
this._currentContentInfo?.contentId !== msgData.contentId ||
|
|
1073
|
-
this._currentContentInfo.manifest === null
|
|
1074
|
-
) {
|
|
1075
|
-
return;
|
|
1076
|
-
}
|
|
1077
|
-
const period = arrayFind(
|
|
1078
|
-
this._currentContentInfo.manifest.periods,
|
|
1079
|
-
(p) => p.id === msgData.value.periodId,
|
|
1080
|
-
);
|
|
1081
|
-
if (period === undefined) {
|
|
1082
|
-
log.warn("Init", "Discontinuity's Period not found", {
|
|
1083
|
-
periodId: msgData.value.periodId,
|
|
1084
|
-
});
|
|
1085
|
-
return;
|
|
1086
|
-
}
|
|
1087
|
-
this._currentContentInfo.rebufferingController?.updateDiscontinuityInfo({
|
|
1088
|
-
period,
|
|
1089
|
-
bufferType: msgData.value.bufferType,
|
|
1090
|
-
discontinuity: msgData.value.discontinuity,
|
|
1091
|
-
position: msgData.value.position,
|
|
1092
|
-
});
|
|
1093
|
-
break;
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
case WorkerMessageType.PushTextData: {
|
|
1097
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
1098
|
-
return;
|
|
1099
|
-
}
|
|
1100
|
-
if (textDisplayer === null) {
|
|
1101
|
-
log.warn("text", "Received AddTextData message but no text displayer exists");
|
|
1102
|
-
} else {
|
|
1103
|
-
try {
|
|
1104
|
-
const ranges = textDisplayer.pushTextData(msgData.value);
|
|
1105
|
-
sendMessage(this._settings.worker, {
|
|
1106
|
-
type: MainThreadMessageType.PushTextDataSuccess,
|
|
1107
|
-
contentId: msgData.contentId,
|
|
1108
|
-
value: { ranges },
|
|
1109
|
-
});
|
|
1110
|
-
} catch (err) {
|
|
1111
|
-
const message = err instanceof Error ? err.message : "Unknown error";
|
|
1112
|
-
sendMessage(this._settings.worker, {
|
|
1113
|
-
type: MainThreadMessageType.PushTextDataError,
|
|
1114
|
-
contentId: msgData.contentId,
|
|
1115
|
-
value: { message },
|
|
1116
|
-
});
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
break;
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
case WorkerMessageType.RemoveTextData: {
|
|
1123
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
1124
|
-
return;
|
|
1125
|
-
}
|
|
1126
|
-
if (textDisplayer === null) {
|
|
1127
|
-
log.warn(
|
|
1128
|
-
"text",
|
|
1129
|
-
"Received RemoveTextData message but no text displayer exists",
|
|
1130
|
-
);
|
|
1131
|
-
} else {
|
|
1132
|
-
try {
|
|
1133
|
-
const ranges = textDisplayer.removeBuffer(
|
|
1134
|
-
msgData.value.start,
|
|
1135
|
-
msgData.value.end,
|
|
1136
|
-
);
|
|
1137
|
-
sendMessage(this._settings.worker, {
|
|
1138
|
-
type: MainThreadMessageType.RemoveTextDataSuccess,
|
|
1139
|
-
contentId: msgData.contentId,
|
|
1140
|
-
value: { ranges },
|
|
1141
|
-
});
|
|
1142
|
-
} catch (err) {
|
|
1143
|
-
const message = err instanceof Error ? err.message : "Unknown error";
|
|
1144
|
-
sendMessage(this._settings.worker, {
|
|
1145
|
-
type: MainThreadMessageType.RemoveTextDataError,
|
|
1146
|
-
contentId: msgData.contentId,
|
|
1147
|
-
value: { message },
|
|
1148
|
-
});
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
break;
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
case WorkerMessageType.ResetTextDisplayer: {
|
|
1155
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
1156
|
-
return;
|
|
1157
|
-
}
|
|
1158
|
-
if (textDisplayer === null) {
|
|
1159
|
-
log.warn(
|
|
1160
|
-
"text",
|
|
1161
|
-
"Received ResetTextDisplayer message but no text displayer exists",
|
|
1162
|
-
);
|
|
1163
|
-
} else {
|
|
1164
|
-
textDisplayer.reset();
|
|
1165
|
-
}
|
|
1166
|
-
break;
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
case WorkerMessageType.StopTextDisplayer: {
|
|
1170
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
1171
|
-
return;
|
|
1172
|
-
}
|
|
1173
|
-
if (textDisplayer === null) {
|
|
1174
|
-
log.warn(
|
|
1175
|
-
"text",
|
|
1176
|
-
"Received StopTextDisplayer message but no text displayer exists",
|
|
1177
|
-
);
|
|
1178
|
-
} else {
|
|
1179
|
-
textDisplayer.stop();
|
|
1180
|
-
}
|
|
1181
|
-
break;
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
case WorkerMessageType.ReloadingMediaSource:
|
|
1185
|
-
{
|
|
1186
|
-
if (
|
|
1187
|
-
this._currentContentInfo === null ||
|
|
1188
|
-
this._currentContentInfo.mediaSourceInfo === null
|
|
1189
|
-
) {
|
|
1190
|
-
return;
|
|
1191
|
-
}
|
|
1192
|
-
const mediaSourceId =
|
|
1193
|
-
this._currentContentInfo.mediaSourceInfo.type === "main"
|
|
1194
|
-
? this._currentContentInfo.mediaSourceInfo.mediaSource.id
|
|
1195
|
-
: this._currentContentInfo.mediaSourceInfo.mediaSourceId;
|
|
1196
|
-
if (mediaSourceId !== msgData.mediaSourceId) {
|
|
1197
|
-
return;
|
|
1198
|
-
}
|
|
1199
|
-
reloadMediaSource(
|
|
1200
|
-
msgData.value.timeOffset,
|
|
1201
|
-
msgData.value.minimumPosition,
|
|
1202
|
-
msgData.value.maximumPosition,
|
|
1203
|
-
);
|
|
1204
|
-
}
|
|
1205
|
-
break;
|
|
1206
|
-
|
|
1207
|
-
case WorkerMessageType.NeedsDecipherabilityFlush:
|
|
1208
|
-
{
|
|
1209
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
1210
|
-
return;
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
const keySystem = getKeySystemConfiguration(mediaElement);
|
|
1214
|
-
if (shouldReloadMediaSourceOnDecipherabilityUpdate(keySystem?.[0])) {
|
|
1215
|
-
notifyAndStartMediaSourceReload(0, undefined, undefined);
|
|
1216
|
-
} else {
|
|
1217
|
-
const lastObservation = playbackObserver.getReference().getValue();
|
|
1218
|
-
|
|
1219
|
-
const currentPosition = lastObservation.position.getWanted();
|
|
1220
|
-
|
|
1221
|
-
// simple seek close to the current position
|
|
1222
|
-
// to flush the buffers
|
|
1223
|
-
if (currentPosition + 0.001 < lastObservation.duration) {
|
|
1224
|
-
playbackObserver.setCurrentTime(mediaElement.currentTime + 0.001);
|
|
1225
|
-
} else {
|
|
1226
|
-
playbackObserver.setCurrentTime(currentPosition);
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
}
|
|
1230
|
-
break;
|
|
1231
|
-
|
|
1232
|
-
case WorkerMessageType.SegmentSinkStoreUpdate: {
|
|
1233
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
1234
|
-
return;
|
|
1235
|
-
}
|
|
1236
|
-
const sinkObj = this._awaitingRequests.pendingSinkMetrics.get(
|
|
1237
|
-
msgData.value.requestId,
|
|
1238
|
-
);
|
|
1239
|
-
if (sinkObj !== undefined) {
|
|
1240
|
-
sinkObj.resolve(msgData.value.segmentSinkMetrics);
|
|
1241
|
-
} else {
|
|
1242
|
-
log.error("Init", "Failed to send segment sink store update");
|
|
1243
|
-
}
|
|
1244
|
-
break;
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
case WorkerMessageType.InitSuccess:
|
|
1248
|
-
case WorkerMessageType.InitError:
|
|
1249
|
-
// Should already be handled by the API
|
|
1250
|
-
break;
|
|
1251
|
-
|
|
1252
|
-
case WorkerMessageType.LogMessage:
|
|
1253
|
-
// Already handled by prepare's handler
|
|
1254
|
-
break;
|
|
1255
|
-
case WorkerMessageType.ThumbnailDataResponse: {
|
|
1256
|
-
if (this._currentContentInfo?.contentId !== msgData.contentId) {
|
|
1257
|
-
return;
|
|
1258
|
-
}
|
|
1259
|
-
const tObj = this._awaitingRequests.pendingThumbnailFetching.get(
|
|
1260
|
-
msgData.value.requestId,
|
|
1261
|
-
);
|
|
1262
|
-
if (tObj !== undefined) {
|
|
1263
|
-
if (msgData.value.status === "error") {
|
|
1264
|
-
tObj.reject(formatWorkerError(msgData.value.error));
|
|
1265
|
-
} else {
|
|
1266
|
-
tObj.resolve(msgData.value.data);
|
|
1267
|
-
}
|
|
1268
|
-
} else {
|
|
1269
|
-
log.error("Init", "Failed to send segment sink store update");
|
|
1270
|
-
}
|
|
1271
|
-
break;
|
|
1272
|
-
}
|
|
1273
|
-
default:
|
|
1274
|
-
assertUnreachable(msgData);
|
|
1275
|
-
}
|
|
1276
|
-
};
|
|
1277
|
-
|
|
1278
|
-
log.debug("Init", "addEventListener for worker message");
|
|
1279
|
-
if (this._queuedWorkerMessages !== null) {
|
|
1280
|
-
const bufferedMessages = this._queuedWorkerMessages.slice();
|
|
1281
|
-
log.debug("Init", "Processing buffered messages", {
|
|
1282
|
-
ammount: bufferedMessages.length,
|
|
1283
|
-
});
|
|
1284
|
-
for (const message of bufferedMessages) {
|
|
1285
|
-
onmessage(message);
|
|
1286
|
-
}
|
|
1287
|
-
this._queuedWorkerMessages = null;
|
|
1288
|
-
}
|
|
1289
|
-
this._settings.worker.addEventListener("message", onmessage);
|
|
1290
|
-
this._initCanceller.signal.register(() => {
|
|
1291
|
-
log.debug("Init", "removeEventListener for worker message");
|
|
1292
|
-
this._settings.worker.removeEventListener("message", onmessage);
|
|
1293
|
-
});
|
|
1294
|
-
}
|
|
1295
|
-
|
|
1296
|
-
public dispose(): void {
|
|
1297
|
-
this._initCanceller.cancel();
|
|
1298
|
-
if (this._currentContentInfo !== null) {
|
|
1299
|
-
if (this._currentContentInfo.mediaSourceInfo?.type === "main") {
|
|
1300
|
-
this._currentContentInfo.mediaSourceInfo.mediaSource.dispose();
|
|
1301
|
-
}
|
|
1302
|
-
this._currentContentInfo = null;
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
private _onFatalError(err: unknown) {
|
|
1307
|
-
if (this._initCanceller.isUsed()) {
|
|
1308
|
-
return;
|
|
1309
|
-
}
|
|
1310
|
-
this._initCanceller.cancel();
|
|
1311
|
-
this.trigger("error", err);
|
|
1312
|
-
}
|
|
1313
|
-
|
|
1314
|
-
private _initializeContentDecryption(
|
|
1315
|
-
mediaElement: IMediaElement,
|
|
1316
|
-
lastContentProtection: IReadOnlySharedReference<null | IContentProtection>,
|
|
1317
|
-
mediaSourceStatus: SharedReference<MediaSourceInitializationStatus>,
|
|
1318
|
-
reloadMediaSource: () => void,
|
|
1319
|
-
cancelSignal: CancellationSignal,
|
|
1320
|
-
): {
|
|
1321
|
-
statusRef: IReadOnlySharedReference<IDrmInitializationStatus>;
|
|
1322
|
-
contentDecryptor: IContentDecryptor | null;
|
|
1323
|
-
} {
|
|
1324
|
-
const { keySystems } = this._settings;
|
|
1325
|
-
|
|
1326
|
-
// TODO private?
|
|
1327
|
-
const createEmeDisabledReference = (errMsg: string) => {
|
|
1328
|
-
mediaSourceStatus.setValue(MediaSourceInitializationStatus.AttachNow);
|
|
1329
|
-
lastContentProtection.onUpdate(
|
|
1330
|
-
(data, stopListening) => {
|
|
1331
|
-
if (data === null) {
|
|
1332
|
-
// initial value
|
|
1333
|
-
return;
|
|
1334
|
-
}
|
|
1335
|
-
stopListening();
|
|
1336
|
-
const err = new EncryptedMediaError("MEDIA_IS_ENCRYPTED_ERROR", errMsg, {
|
|
1337
|
-
keyStatuses: undefined,
|
|
1338
|
-
keySystemConfiguration: undefined,
|
|
1339
|
-
keySystem: undefined,
|
|
1340
|
-
});
|
|
1341
|
-
this._onFatalError(err);
|
|
1342
|
-
},
|
|
1343
|
-
{ clearSignal: cancelSignal },
|
|
1344
|
-
);
|
|
1345
|
-
const ref = new SharedReference({
|
|
1346
|
-
initializationState: {
|
|
1347
|
-
type: "initialized" as const,
|
|
1348
|
-
value: null,
|
|
1349
|
-
},
|
|
1350
|
-
contentDecryptor: null,
|
|
1351
|
-
drmSystemId: undefined,
|
|
1352
|
-
});
|
|
1353
|
-
ref.finish(); // We know that no new value will be triggered
|
|
1354
|
-
return { statusRef: ref, contentDecryptor: null };
|
|
1355
|
-
};
|
|
1356
|
-
|
|
1357
|
-
if (keySystems.length === 0) {
|
|
1358
|
-
return createEmeDisabledReference("No `keySystems` option given.");
|
|
1359
|
-
} else if (features.decrypt === null) {
|
|
1360
|
-
return createEmeDisabledReference("EME feature not activated.");
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
|
-
const ContentDecryptor = features.decrypt;
|
|
1364
|
-
const emeApi = mediaElement.FORCED_EME_API ?? getEmeApiImplementation("auto");
|
|
1365
|
-
if (emeApi === null) {
|
|
1366
|
-
return createEmeDisabledReference("EME API not available on the current page.");
|
|
1367
|
-
}
|
|
1368
|
-
log.debug("Init", "Creating ContentDecryptor");
|
|
1369
|
-
const contentDecryptor = new ContentDecryptor(emeApi, mediaElement, keySystems);
|
|
1370
|
-
const drmStatusRef = new SharedReference<IDrmInitializationStatus>(
|
|
1371
|
-
{
|
|
1372
|
-
initializationState: { type: "uninitialized", value: null },
|
|
1373
|
-
drmSystemId: undefined,
|
|
1374
|
-
},
|
|
1375
|
-
cancelSignal,
|
|
1376
|
-
);
|
|
1377
|
-
|
|
1378
|
-
const updateCodecSupportOnStateChange = (state: ContentDecryptorState) => {
|
|
1379
|
-
if (state > ContentDecryptorState.Initializing) {
|
|
1380
|
-
const manifest = this._currentContentInfo?.manifest;
|
|
1381
|
-
if (isNullOrUndefined(manifest)) {
|
|
1382
|
-
return;
|
|
1383
|
-
}
|
|
1384
|
-
this._updateCodecSupport(manifest, mediaElement);
|
|
1385
|
-
contentDecryptor.removeEventListener(
|
|
1386
|
-
"stateChange",
|
|
1387
|
-
updateCodecSupportOnStateChange,
|
|
1388
|
-
);
|
|
1389
|
-
}
|
|
1390
|
-
};
|
|
1391
|
-
contentDecryptor.addEventListener("stateChange", updateCodecSupportOnStateChange);
|
|
1392
|
-
|
|
1393
|
-
contentDecryptor.addEventListener("keyIdsCompatibilityUpdate", (updates) => {
|
|
1394
|
-
if (
|
|
1395
|
-
this._currentContentInfo === null ||
|
|
1396
|
-
this._currentContentInfo.manifest === null
|
|
1397
|
-
) {
|
|
1398
|
-
return;
|
|
1399
|
-
}
|
|
1400
|
-
const manUpdates = updateDecipherabilityFromKeyIds(
|
|
1401
|
-
this._currentContentInfo.manifest,
|
|
1402
|
-
updates,
|
|
1403
|
-
);
|
|
1404
|
-
if (
|
|
1405
|
-
mayMediaElementFailOnUndecipherableData() &&
|
|
1406
|
-
manUpdates.some((e) => e.representation.decipherable !== true)
|
|
1407
|
-
) {
|
|
1408
|
-
reloadMediaSource();
|
|
1409
|
-
} else {
|
|
1410
|
-
sendMessage(this._settings.worker, {
|
|
1411
|
-
type: MainThreadMessageType.DecipherabilityStatusUpdate,
|
|
1412
|
-
contentId: this._currentContentInfo.contentId,
|
|
1413
|
-
value: manUpdates.map((s) => ({
|
|
1414
|
-
representationUniqueId: s.representation.uniqueId,
|
|
1415
|
-
decipherable: s.representation.decipherable,
|
|
1416
|
-
})),
|
|
1417
|
-
});
|
|
1418
|
-
}
|
|
1419
|
-
this.trigger("decipherabilityUpdate", manUpdates);
|
|
1420
|
-
});
|
|
1421
|
-
contentDecryptor.addEventListener("blackListProtectionData", (protData) => {
|
|
1422
|
-
if (
|
|
1423
|
-
this._currentContentInfo === null ||
|
|
1424
|
-
this._currentContentInfo.manifest === null
|
|
1425
|
-
) {
|
|
1426
|
-
return;
|
|
1427
|
-
}
|
|
1428
|
-
const manUpdates = updateDecipherabilityFromProtectionData(
|
|
1429
|
-
this._currentContentInfo.manifest,
|
|
1430
|
-
protData,
|
|
1431
|
-
);
|
|
1432
|
-
if (
|
|
1433
|
-
mayMediaElementFailOnUndecipherableData() &&
|
|
1434
|
-
manUpdates.some((e) => e.representation.decipherable !== true)
|
|
1435
|
-
) {
|
|
1436
|
-
reloadMediaSource();
|
|
1437
|
-
} else {
|
|
1438
|
-
sendMessage(this._settings.worker, {
|
|
1439
|
-
type: MainThreadMessageType.DecipherabilityStatusUpdate,
|
|
1440
|
-
contentId: this._currentContentInfo.contentId,
|
|
1441
|
-
value: manUpdates.map((s) => ({
|
|
1442
|
-
representationUniqueId: s.representation.uniqueId,
|
|
1443
|
-
decipherable: s.representation.decipherable,
|
|
1444
|
-
})),
|
|
1445
|
-
});
|
|
1446
|
-
}
|
|
1447
|
-
this.trigger("decipherabilityUpdate", manUpdates);
|
|
1448
|
-
});
|
|
1449
|
-
contentDecryptor.addEventListener("stateChange", (state) => {
|
|
1450
|
-
if (state === ContentDecryptorState.WaitingForAttachment) {
|
|
1451
|
-
mediaSourceStatus.onUpdate(
|
|
1452
|
-
(currStatus, stopListening) => {
|
|
1453
|
-
if (currStatus === MediaSourceInitializationStatus.Nothing) {
|
|
1454
|
-
mediaSourceStatus.setValue(MediaSourceInitializationStatus.AttachNow);
|
|
1455
|
-
} else if (currStatus === MediaSourceInitializationStatus.Attached) {
|
|
1456
|
-
stopListening();
|
|
1457
|
-
if (state === ContentDecryptorState.WaitingForAttachment) {
|
|
1458
|
-
contentDecryptor.attach();
|
|
1459
|
-
}
|
|
1460
|
-
}
|
|
1461
|
-
},
|
|
1462
|
-
{ clearSignal: cancelSignal, emitCurrentValue: true },
|
|
1463
|
-
);
|
|
1464
|
-
} else if (state === ContentDecryptorState.ReadyForContent) {
|
|
1465
|
-
drmStatusRef.setValue({
|
|
1466
|
-
initializationState: { type: "initialized", value: null },
|
|
1467
|
-
drmSystemId: contentDecryptor.systemId,
|
|
1468
|
-
});
|
|
1469
|
-
contentDecryptor.removeEventListener("stateChange");
|
|
1470
|
-
}
|
|
1471
|
-
});
|
|
1472
|
-
|
|
1473
|
-
contentDecryptor.addEventListener("error", (error) => {
|
|
1474
|
-
this._onFatalError(error);
|
|
1475
|
-
});
|
|
1476
|
-
|
|
1477
|
-
contentDecryptor.addEventListener("warning", (error) => {
|
|
1478
|
-
this.trigger("warning", error);
|
|
1479
|
-
});
|
|
1480
|
-
|
|
1481
|
-
lastContentProtection.onUpdate(
|
|
1482
|
-
(data) => {
|
|
1483
|
-
if (data === null) {
|
|
1484
|
-
return;
|
|
1485
|
-
}
|
|
1486
|
-
contentDecryptor.onInitializationData(data);
|
|
1487
|
-
},
|
|
1488
|
-
{ clearSignal: cancelSignal },
|
|
1489
|
-
);
|
|
1490
|
-
|
|
1491
|
-
cancelSignal.register(() => {
|
|
1492
|
-
contentDecryptor.dispose();
|
|
1493
|
-
});
|
|
1494
|
-
|
|
1495
|
-
return { statusRef: drmStatusRef, contentDecryptor };
|
|
1496
|
-
}
|
|
1497
|
-
/**
|
|
1498
|
-
* Retrieves all unknown codecs from the current manifest, checks these unknown codecs
|
|
1499
|
-
* to determine if they are supported, updates the manifest with the support
|
|
1500
|
-
* status of these codecs, and forwards the list of supported codecs to the web worker.
|
|
1501
|
-
* @param manifest
|
|
1502
|
-
*/
|
|
1503
|
-
private _updateCodecSupport(manifest: IManifestMetadata, mediaElement: IMediaElement) {
|
|
1504
|
-
try {
|
|
1505
|
-
const updatedCodecs = updateManifestCodecSupport(
|
|
1506
|
-
manifest,
|
|
1507
|
-
this._currentContentInfo?.contentDecryptor ?? null,
|
|
1508
|
-
mediaElement,
|
|
1509
|
-
this._currentContentInfo?.useMseInWorker ?? false,
|
|
1510
|
-
);
|
|
1511
|
-
if (updatedCodecs.length > 0) {
|
|
1512
|
-
sendMessage(this._settings.worker, {
|
|
1513
|
-
type: MainThreadMessageType.CodecSupportUpdate,
|
|
1514
|
-
value: updatedCodecs,
|
|
1515
|
-
});
|
|
1516
|
-
// TODO what if one day the worker updates codec support by itself?
|
|
1517
|
-
// We wouldn't know...
|
|
1518
|
-
this.trigger("codecSupportUpdate", null);
|
|
1519
|
-
}
|
|
1520
|
-
} catch (err) {
|
|
1521
|
-
this._onFatalError(err);
|
|
1522
|
-
}
|
|
1523
|
-
}
|
|
1524
|
-
|
|
1525
|
-
private _hasTextBufferFeature(): boolean {
|
|
1526
|
-
return (
|
|
1527
|
-
(this._settings.textTrackOptions.textTrackMode === "html" &&
|
|
1528
|
-
features.htmlTextDisplayer !== null) ||
|
|
1529
|
-
features.nativeTextDisplayer !== null
|
|
1530
|
-
);
|
|
1531
|
-
}
|
|
1532
|
-
|
|
1533
|
-
private _reload(
|
|
1534
|
-
mediaElement: IMediaElement,
|
|
1535
|
-
textDisplayer: ITextDisplayer | null,
|
|
1536
|
-
playbackObserver: IMediaElementPlaybackObserver,
|
|
1537
|
-
mediaSourceStatus: SharedReference<MediaSourceInitializationStatus>,
|
|
1538
|
-
position: number,
|
|
1539
|
-
autoPlay: boolean,
|
|
1540
|
-
) {
|
|
1541
|
-
this._currentMediaSourceCanceller.cancel();
|
|
1542
|
-
this._currentMediaSourceCanceller = new TaskCanceller();
|
|
1543
|
-
this._currentMediaSourceCanceller.linkToSignal(this._initCanceller.signal);
|
|
1544
|
-
mediaSourceStatus.setValue(MediaSourceInitializationStatus.AttachNow);
|
|
1545
|
-
this.trigger("reloadingMediaSource", { position, autoPlay });
|
|
1546
|
-
|
|
1547
|
-
mediaSourceStatus.onUpdate(
|
|
1548
|
-
(status, stopListeningMSStatusUpdates) => {
|
|
1549
|
-
if (status !== MediaSourceInitializationStatus.Attached) {
|
|
1550
|
-
return;
|
|
1551
|
-
}
|
|
1552
|
-
stopListeningMSStatusUpdates();
|
|
1553
|
-
const corePlaybackObserver = this._setUpModulesOnNewMediaSource(
|
|
1554
|
-
{
|
|
1555
|
-
initialTime: position,
|
|
1556
|
-
autoPlay,
|
|
1557
|
-
mediaElement,
|
|
1558
|
-
textDisplayer,
|
|
1559
|
-
playbackObserver,
|
|
1560
|
-
},
|
|
1561
|
-
this._currentMediaSourceCanceller.signal,
|
|
1562
|
-
);
|
|
1563
|
-
|
|
1564
|
-
if (
|
|
1565
|
-
!this._currentMediaSourceCanceller.isUsed() &&
|
|
1566
|
-
corePlaybackObserver !== null &&
|
|
1567
|
-
this._currentContentInfo !== null
|
|
1568
|
-
) {
|
|
1569
|
-
const contentId = this._currentContentInfo.contentId;
|
|
1570
|
-
corePlaybackObserver.listen(
|
|
1571
|
-
(obs) => {
|
|
1572
|
-
sendMessage(this._settings.worker, {
|
|
1573
|
-
type: MainThreadMessageType.PlaybackObservation,
|
|
1574
|
-
contentId,
|
|
1575
|
-
value: objectAssign(obs, {
|
|
1576
|
-
position: obs.position.serialize(),
|
|
1577
|
-
}),
|
|
1578
|
-
});
|
|
1579
|
-
},
|
|
1580
|
-
{
|
|
1581
|
-
includeLastObservation: true,
|
|
1582
|
-
clearSignal: this._currentMediaSourceCanceller.signal,
|
|
1583
|
-
},
|
|
1584
|
-
);
|
|
1585
|
-
}
|
|
1586
|
-
},
|
|
1587
|
-
{
|
|
1588
|
-
clearSignal: this._currentMediaSourceCanceller.signal,
|
|
1589
|
-
emitCurrentValue: true,
|
|
1590
|
-
},
|
|
1591
|
-
);
|
|
1592
|
-
}
|
|
1593
|
-
|
|
1594
|
-
/**
|
|
1595
|
-
* Start-up modules and mechanisms (initial seek, auto-play etc.) needed each
|
|
1596
|
-
* time a content is loaded AND re-loaded on a `HTMLMediaElement`, when the
|
|
1597
|
-
* manifest is known.
|
|
1598
|
-
*
|
|
1599
|
-
* Note that this does not include reacting to incoming worker messages nor
|
|
1600
|
-
* sending them, those actions have to be handled separately.
|
|
1601
|
-
*
|
|
1602
|
-
* @param {Object} parameters
|
|
1603
|
-
* @param {Object} cancelSignal
|
|
1604
|
-
* @returns {Object|null} - Playback Observer created for this content. `null`
|
|
1605
|
-
* only if playback initialization failed (most likely because it has been
|
|
1606
|
-
* cancelled).
|
|
1607
|
-
*/
|
|
1608
|
-
private _setUpModulesOnNewMediaSource(
|
|
1609
|
-
parameters: {
|
|
1610
|
-
initialTime: number;
|
|
1611
|
-
autoPlay: boolean;
|
|
1612
|
-
mediaElement: IMediaElement;
|
|
1613
|
-
textDisplayer: ITextDisplayer | null;
|
|
1614
|
-
playbackObserver: IMediaElementPlaybackObserver;
|
|
1615
|
-
},
|
|
1616
|
-
cancelSignal: CancellationSignal,
|
|
1617
|
-
): IReadOnlyPlaybackObserver<IWorkerPlaybackObservation> | null {
|
|
1618
|
-
if (cancelSignal.isCancelled()) {
|
|
1619
|
-
return null;
|
|
1620
|
-
}
|
|
1621
|
-
if (this._currentContentInfo === null) {
|
|
1622
|
-
log.error("Init", "Setting up modules without a contentId");
|
|
1623
|
-
return null;
|
|
1624
|
-
}
|
|
1625
|
-
if (this._currentContentInfo.manifest === null) {
|
|
1626
|
-
log.error("Init", "Setting up modules without a loaded Manifest");
|
|
1627
|
-
return null;
|
|
1628
|
-
}
|
|
1629
|
-
|
|
1630
|
-
const { manifest, mediaSourceInfo } = this._currentContentInfo;
|
|
1631
|
-
const { speed } = this._settings;
|
|
1632
|
-
const { initialTime, autoPlay, mediaElement, textDisplayer, playbackObserver } =
|
|
1633
|
-
parameters;
|
|
1634
|
-
this._currentContentInfo.initialTime = initialTime;
|
|
1635
|
-
this._currentContentInfo.autoPlay = autoPlay;
|
|
1636
|
-
|
|
1637
|
-
const { autoPlayResult, initialPlayPerformed } = performInitialSeekAndPlay(
|
|
1638
|
-
{
|
|
1639
|
-
mediaElement,
|
|
1640
|
-
playbackObserver,
|
|
1641
|
-
startTime: initialTime,
|
|
1642
|
-
mustAutoPlay: autoPlay,
|
|
1643
|
-
onWarning: (err) => this.trigger("warning", err),
|
|
1644
|
-
isDirectfile: false,
|
|
1645
|
-
},
|
|
1646
|
-
cancelSignal,
|
|
1647
|
-
);
|
|
1648
|
-
this._currentContentInfo.initialPlayPerformed = initialPlayPerformed;
|
|
1649
|
-
const corePlaybackObserver = createCorePlaybackObserver(
|
|
1650
|
-
playbackObserver,
|
|
1651
|
-
{
|
|
1652
|
-
autoPlay,
|
|
1653
|
-
initialPlayPerformed,
|
|
1654
|
-
manifest,
|
|
1655
|
-
mediaSource:
|
|
1656
|
-
mediaSourceInfo?.type === "main" ? mediaSourceInfo.mediaSource : null,
|
|
1657
|
-
speed,
|
|
1658
|
-
textDisplayer,
|
|
1659
|
-
},
|
|
1660
|
-
cancelSignal,
|
|
1661
|
-
);
|
|
1662
|
-
|
|
1663
|
-
if (cancelSignal.isCancelled()) {
|
|
1664
|
-
return null;
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
|
-
/**
|
|
1668
|
-
* Class trying to avoid various stalling situations, emitting "stalled"
|
|
1669
|
-
* events when it cannot, as well as "unstalled" events when it get out of one.
|
|
1670
|
-
*/
|
|
1671
|
-
const rebufferingController = new RebufferingController(
|
|
1672
|
-
playbackObserver,
|
|
1673
|
-
manifest,
|
|
1674
|
-
speed,
|
|
1675
|
-
);
|
|
1676
|
-
rebufferingController.addEventListener("stalled", (evt) =>
|
|
1677
|
-
this.trigger("stalled", evt),
|
|
1678
|
-
);
|
|
1679
|
-
rebufferingController.addEventListener("unstalled", () =>
|
|
1680
|
-
this.trigger("unstalled", null),
|
|
1681
|
-
);
|
|
1682
|
-
rebufferingController.addEventListener("warning", (err) =>
|
|
1683
|
-
this.trigger("warning", err),
|
|
1684
|
-
);
|
|
1685
|
-
cancelSignal.register(() => {
|
|
1686
|
-
rebufferingController.destroy();
|
|
1687
|
-
});
|
|
1688
|
-
rebufferingController.start();
|
|
1689
|
-
this._currentContentInfo.rebufferingController = rebufferingController;
|
|
1690
|
-
|
|
1691
|
-
const currentContentInfo = this._currentContentInfo;
|
|
1692
|
-
initialPlayPerformed.onUpdate(
|
|
1693
|
-
(isPerformed, stopListening) => {
|
|
1694
|
-
if (isPerformed) {
|
|
1695
|
-
stopListening();
|
|
1696
|
-
const streamEventsEmitter = new StreamEventsEmitter(manifest, playbackObserver);
|
|
1697
|
-
currentContentInfo.streamEventsEmitter = streamEventsEmitter;
|
|
1698
|
-
streamEventsEmitter.addEventListener(
|
|
1699
|
-
"event",
|
|
1700
|
-
(payload) => {
|
|
1701
|
-
this.trigger("streamEvent", payload);
|
|
1702
|
-
},
|
|
1703
|
-
cancelSignal,
|
|
1704
|
-
);
|
|
1705
|
-
streamEventsEmitter.addEventListener(
|
|
1706
|
-
"eventSkip",
|
|
1707
|
-
(payload) => {
|
|
1708
|
-
this.trigger("streamEventSkip", payload);
|
|
1709
|
-
},
|
|
1710
|
-
cancelSignal,
|
|
1711
|
-
);
|
|
1712
|
-
streamEventsEmitter.start();
|
|
1713
|
-
cancelSignal.register(() => {
|
|
1714
|
-
streamEventsEmitter.stop();
|
|
1715
|
-
});
|
|
1716
|
-
}
|
|
1717
|
-
},
|
|
1718
|
-
{ clearSignal: cancelSignal, emitCurrentValue: true },
|
|
1719
|
-
);
|
|
1720
|
-
|
|
1721
|
-
const _getSegmentSinkMetrics = async (): Promise<ISegmentSinkMetrics | undefined> => {
|
|
1722
|
-
this._awaitingRequests.nextRequestId++;
|
|
1723
|
-
const requestId = this._awaitingRequests.nextRequestId;
|
|
1724
|
-
sendMessage(this._settings.worker, {
|
|
1725
|
-
type: MainThreadMessageType.PullSegmentSinkStoreInfos,
|
|
1726
|
-
value: { requestId },
|
|
1727
|
-
});
|
|
1728
|
-
return new Promise((resolve, reject) => {
|
|
1729
|
-
const rejectFn = (err: CancellationError) => {
|
|
1730
|
-
cancelSignal.deregister(rejectFn);
|
|
1731
|
-
this._awaitingRequests.pendingSinkMetrics.delete(requestId);
|
|
1732
|
-
return reject(err);
|
|
1733
|
-
};
|
|
1734
|
-
this._awaitingRequests.pendingSinkMetrics.set(requestId, {
|
|
1735
|
-
resolve: (value: ISegmentSinkMetrics | undefined) => {
|
|
1736
|
-
cancelSignal.deregister(rejectFn);
|
|
1737
|
-
this._awaitingRequests.pendingSinkMetrics.delete(requestId);
|
|
1738
|
-
resolve(value);
|
|
1739
|
-
},
|
|
1740
|
-
});
|
|
1741
|
-
cancelSignal.register(rejectFn);
|
|
1742
|
-
});
|
|
1743
|
-
};
|
|
1744
|
-
const _getThumbnailsData = async (
|
|
1745
|
-
periodId: string,
|
|
1746
|
-
thumbnailTrackId: string,
|
|
1747
|
-
time: number,
|
|
1748
|
-
): Promise<IThumbnailResponse> => {
|
|
1749
|
-
if (this._currentContentInfo === null) {
|
|
1750
|
-
return Promise.reject(new Error("Cannot fetch thumbnails: No content loaded."));
|
|
1751
|
-
}
|
|
1752
|
-
this._awaitingRequests.nextRequestId++;
|
|
1753
|
-
const requestId = this._awaitingRequests.nextRequestId;
|
|
1754
|
-
sendMessage(this._settings.worker, {
|
|
1755
|
-
type: MainThreadMessageType.ThumbnailDataRequest,
|
|
1756
|
-
contentId: this._currentContentInfo.contentId,
|
|
1757
|
-
value: { requestId, periodId, thumbnailTrackId, time },
|
|
1758
|
-
});
|
|
1759
|
-
|
|
1760
|
-
return new Promise((resolve, reject) => {
|
|
1761
|
-
const rejectFn = (err: CancellationError) => {
|
|
1762
|
-
cleanUp();
|
|
1763
|
-
reject(err);
|
|
1764
|
-
};
|
|
1765
|
-
const cleanUp = () => {
|
|
1766
|
-
cancelSignal.deregister(rejectFn);
|
|
1767
|
-
this._awaitingRequests.pendingThumbnailFetching.delete(requestId);
|
|
1768
|
-
};
|
|
1769
|
-
|
|
1770
|
-
this._awaitingRequests.pendingThumbnailFetching.set(requestId, {
|
|
1771
|
-
resolve: (value: IThumbnailResponse) => {
|
|
1772
|
-
cleanUp();
|
|
1773
|
-
resolve(value);
|
|
1774
|
-
},
|
|
1775
|
-
reject: (value: unknown) => {
|
|
1776
|
-
cleanUp();
|
|
1777
|
-
reject(value);
|
|
1778
|
-
},
|
|
1779
|
-
});
|
|
1780
|
-
cancelSignal.register(rejectFn);
|
|
1781
|
-
});
|
|
1782
|
-
};
|
|
1783
|
-
/**
|
|
1784
|
-
* Emit a "loaded" events once the initial play has been performed and the
|
|
1785
|
-
* media can begin playback.
|
|
1786
|
-
* Also emits warning events if issues arise when doing so.
|
|
1787
|
-
*/
|
|
1788
|
-
autoPlayResult
|
|
1789
|
-
.then(() => {
|
|
1790
|
-
getLoadedReference(playbackObserver, false, cancelSignal).onUpdate(
|
|
1791
|
-
(isLoaded, stopListening) => {
|
|
1792
|
-
if (isLoaded) {
|
|
1793
|
-
stopListening();
|
|
1794
|
-
this.trigger("loaded", {
|
|
1795
|
-
getSegmentSinkMetrics: _getSegmentSinkMetrics,
|
|
1796
|
-
getThumbnailData: _getThumbnailsData,
|
|
1797
|
-
});
|
|
1798
|
-
}
|
|
1799
|
-
},
|
|
1800
|
-
{ emitCurrentValue: true, clearSignal: cancelSignal },
|
|
1801
|
-
);
|
|
1802
|
-
})
|
|
1803
|
-
.catch((err) => {
|
|
1804
|
-
if (cancelSignal.isCancelled()) {
|
|
1805
|
-
return;
|
|
1806
|
-
}
|
|
1807
|
-
this._onFatalError(err);
|
|
1808
|
-
});
|
|
1809
|
-
|
|
1810
|
-
return corePlaybackObserver;
|
|
1811
|
-
}
|
|
1812
|
-
|
|
1813
|
-
/**
|
|
1814
|
-
* Initialize content playback if and only if those conditions are filled:
|
|
1815
|
-
* - The Manifest is fetched and stored in `this._currentContentInfo`.
|
|
1816
|
-
* - `drmInitializationStatus` indicates that DRM matters are initialized.
|
|
1817
|
-
* - `mediaSourceStatus` indicates that the MediaSource is attached to the
|
|
1818
|
-
* `mediaElement`.
|
|
1819
|
-
*
|
|
1820
|
-
* In other cases, this method will do nothing.
|
|
1821
|
-
*
|
|
1822
|
-
* To call when any of those conditions might become `true`, to start-up
|
|
1823
|
-
* playback.
|
|
1824
|
-
*
|
|
1825
|
-
* @param {Object} parameters
|
|
1826
|
-
* @returns {boolean} - Returns `true` if all conditions where met for
|
|
1827
|
-
* playback start.
|
|
1828
|
-
*/
|
|
1829
|
-
private _startPlaybackIfReady(parameters: {
|
|
1830
|
-
mediaElement: IMediaElement;
|
|
1831
|
-
textDisplayer: ITextDisplayer | null;
|
|
1832
|
-
playbackObserver: IMediaElementPlaybackObserver;
|
|
1833
|
-
drmInitializationStatus: IReadOnlySharedReference<IDrmInitializationStatus>;
|
|
1834
|
-
mediaSourceStatus: IReadOnlySharedReference<MediaSourceInitializationStatus>;
|
|
1835
|
-
}): boolean {
|
|
1836
|
-
if (this._currentContentInfo === null || this._currentContentInfo.manifest === null) {
|
|
1837
|
-
return false;
|
|
1838
|
-
}
|
|
1839
|
-
const drmInitStatus = parameters.drmInitializationStatus.getValue();
|
|
1840
|
-
if (drmInitStatus.initializationState.type !== "initialized") {
|
|
1841
|
-
return false;
|
|
1842
|
-
}
|
|
1843
|
-
const msInitStatus = parameters.mediaSourceStatus.getValue();
|
|
1844
|
-
if (msInitStatus !== MediaSourceInitializationStatus.Attached) {
|
|
1845
|
-
return false;
|
|
1846
|
-
}
|
|
1847
|
-
|
|
1848
|
-
const { contentId, manifest } = this._currentContentInfo;
|
|
1849
|
-
log.debug("Init", "Calculating initial time");
|
|
1850
|
-
const initialTime = getInitialTime(
|
|
1851
|
-
manifest,
|
|
1852
|
-
this._settings.lowLatencyMode,
|
|
1853
|
-
this._settings.startAt,
|
|
1854
|
-
);
|
|
1855
|
-
log.debug("Init", "Initial time calculated", { initialTime });
|
|
1856
|
-
const { enableFastSwitching, onCodecSwitch } = this._settings.bufferOptions;
|
|
1857
|
-
const corePlaybackObserver = this._setUpModulesOnNewMediaSource(
|
|
1858
|
-
{
|
|
1859
|
-
initialTime,
|
|
1860
|
-
autoPlay: this._settings.autoPlay,
|
|
1861
|
-
mediaElement: parameters.mediaElement,
|
|
1862
|
-
textDisplayer: parameters.textDisplayer,
|
|
1863
|
-
playbackObserver: parameters.playbackObserver,
|
|
1864
|
-
},
|
|
1865
|
-
this._currentMediaSourceCanceller.signal,
|
|
1866
|
-
);
|
|
1867
|
-
|
|
1868
|
-
if (this._currentMediaSourceCanceller.isUsed() || corePlaybackObserver === null) {
|
|
1869
|
-
return true;
|
|
1870
|
-
}
|
|
1871
|
-
const initialObservation = corePlaybackObserver.getReference().getValue();
|
|
1872
|
-
const sentInitialObservation = objectAssign(initialObservation, {
|
|
1873
|
-
position: initialObservation.position.serialize(),
|
|
1874
|
-
});
|
|
1875
|
-
sendMessage(this._settings.worker, {
|
|
1876
|
-
type: MainThreadMessageType.StartPreparedContent,
|
|
1877
|
-
contentId,
|
|
1878
|
-
value: {
|
|
1879
|
-
initialTime,
|
|
1880
|
-
initialObservation: sentInitialObservation,
|
|
1881
|
-
drmSystemId: drmInitStatus.drmSystemId,
|
|
1882
|
-
enableFastSwitching,
|
|
1883
|
-
onCodecSwitch,
|
|
1884
|
-
},
|
|
1885
|
-
});
|
|
1886
|
-
|
|
1887
|
-
corePlaybackObserver.listen(
|
|
1888
|
-
(obs) => {
|
|
1889
|
-
sendMessage(this._settings.worker, {
|
|
1890
|
-
type: MainThreadMessageType.PlaybackObservation,
|
|
1891
|
-
contentId,
|
|
1892
|
-
value: objectAssign(obs, { position: obs.position.serialize() }),
|
|
1893
|
-
});
|
|
1894
|
-
},
|
|
1895
|
-
{
|
|
1896
|
-
includeLastObservation: false,
|
|
1897
|
-
clearSignal: this._currentMediaSourceCanceller.signal,
|
|
1898
|
-
},
|
|
1899
|
-
);
|
|
1900
|
-
this.trigger("manifestReady", manifest);
|
|
1901
|
-
return true;
|
|
1902
|
-
}
|
|
1903
|
-
|
|
1904
|
-
/**
|
|
1905
|
-
* Handles Worker messages asking to create a MediaSource.
|
|
1906
|
-
* @param {Object} msg - The worker's message received.
|
|
1907
|
-
* @param {HTMLMediaElement} mediaElement - HTMLMediaElement on which the
|
|
1908
|
-
* content plays.
|
|
1909
|
-
* @param {Worker} worker - The WebWorker concerned, messages may be sent back
|
|
1910
|
-
* to it.
|
|
1911
|
-
*/
|
|
1912
|
-
private _onCreateMediaSourceMessage(
|
|
1913
|
-
msg: ICreateMediaSourceWorkerMessage,
|
|
1914
|
-
mediaElement: IMediaElement,
|
|
1915
|
-
mediaSourceStatus: SharedReference<MediaSourceInitializationStatus>,
|
|
1916
|
-
worker: Worker,
|
|
1917
|
-
): void {
|
|
1918
|
-
if (this._currentContentInfo?.contentId !== msg.contentId) {
|
|
1919
|
-
log.info("Init", "Ignoring MediaSource attachment due to wrong `contentId`");
|
|
1920
|
-
} else {
|
|
1921
|
-
const { mediaSourceId } = msg;
|
|
1922
|
-
try {
|
|
1923
|
-
mediaSourceStatus.onUpdate(
|
|
1924
|
-
(currStatus, stopListening) => {
|
|
1925
|
-
if (this._currentContentInfo === null) {
|
|
1926
|
-
stopListening();
|
|
1927
|
-
return;
|
|
1928
|
-
}
|
|
1929
|
-
if (currStatus === MediaSourceInitializationStatus.AttachNow) {
|
|
1930
|
-
stopListening();
|
|
1931
|
-
const mediaSource = new MainMediaSourceInterface(mediaSourceId);
|
|
1932
|
-
if (this._currentContentInfo.mediaSourceInfo?.type === "main") {
|
|
1933
|
-
this._currentContentInfo.mediaSourceInfo.mediaSource.dispose();
|
|
1934
|
-
}
|
|
1935
|
-
this._currentContentInfo.mediaSourceInfo = {
|
|
1936
|
-
type: "main",
|
|
1937
|
-
mediaSource,
|
|
1938
|
-
};
|
|
1939
|
-
mediaSource.addEventListener("mediaSourceOpen", () => {
|
|
1940
|
-
sendMessage(worker, {
|
|
1941
|
-
type: MainThreadMessageType.MediaSourceReadyStateChange,
|
|
1942
|
-
mediaSourceId,
|
|
1943
|
-
value: "open",
|
|
1944
|
-
});
|
|
1945
|
-
});
|
|
1946
|
-
mediaSource.addEventListener("mediaSourceEnded", () => {
|
|
1947
|
-
sendMessage(worker, {
|
|
1948
|
-
type: MainThreadMessageType.MediaSourceReadyStateChange,
|
|
1949
|
-
mediaSourceId,
|
|
1950
|
-
value: "ended",
|
|
1951
|
-
});
|
|
1952
|
-
});
|
|
1953
|
-
mediaSource.addEventListener("mediaSourceClose", () => {
|
|
1954
|
-
sendMessage(worker, {
|
|
1955
|
-
type: MainThreadMessageType.MediaSourceReadyStateChange,
|
|
1956
|
-
mediaSourceId,
|
|
1957
|
-
value: "closed",
|
|
1958
|
-
});
|
|
1959
|
-
});
|
|
1960
|
-
let url: string | null = null;
|
|
1961
|
-
if (mediaSource.handle.type === "handle") {
|
|
1962
|
-
mediaElement.srcObject = mediaSource.handle.value;
|
|
1963
|
-
} else {
|
|
1964
|
-
url = URL.createObjectURL(mediaSource.handle.value);
|
|
1965
|
-
mediaElement.src = url;
|
|
1966
|
-
}
|
|
1967
|
-
this._currentMediaSourceCanceller.signal.register(() => {
|
|
1968
|
-
mediaSource.dispose();
|
|
1969
|
-
resetMediaElement(mediaElement, url);
|
|
1970
|
-
});
|
|
1971
|
-
mediaSourceStatus.setValue(MediaSourceInitializationStatus.Attached);
|
|
1972
|
-
disableRemotePlaybackOnManagedMediaSource(
|
|
1973
|
-
mediaElement,
|
|
1974
|
-
this._currentMediaSourceCanceller.signal,
|
|
1975
|
-
);
|
|
1976
|
-
}
|
|
1977
|
-
},
|
|
1978
|
-
{
|
|
1979
|
-
emitCurrentValue: true,
|
|
1980
|
-
clearSignal: this._currentMediaSourceCanceller.signal,
|
|
1981
|
-
},
|
|
1982
|
-
);
|
|
1983
|
-
} catch (_err) {
|
|
1984
|
-
const error = new OtherError(
|
|
1985
|
-
"NONE",
|
|
1986
|
-
"Unknown error when creating the MediaSource",
|
|
1987
|
-
);
|
|
1988
|
-
this._onFatalError(error);
|
|
1989
|
-
}
|
|
1990
|
-
}
|
|
1991
|
-
}
|
|
1992
|
-
}
|
|
1993
|
-
|
|
1994
|
-
export interface IMultiThreadContentInitializerContentInfos {
|
|
1995
|
-
/**
|
|
1996
|
-
* "contentId", which is the identifier for the currently loaded content.
|
|
1997
|
-
* Allows to ensure that the WebWorker is referencing the current content, not
|
|
1998
|
-
* a previously stopped one.
|
|
1999
|
-
*/
|
|
2000
|
-
contentId: string;
|
|
2001
|
-
/**
|
|
2002
|
-
* Current parsed Manifest.
|
|
2003
|
-
* `null` if not fetched / parsed yet.
|
|
2004
|
-
*/
|
|
2005
|
-
manifest: IManifestMetadata | null;
|
|
2006
|
-
/**
|
|
2007
|
-
* Current MediaSource linked to the content.
|
|
2008
|
-
*
|
|
2009
|
-
* `null` if no MediaSource is currently created for the content.
|
|
2010
|
-
*/
|
|
2011
|
-
mediaSourceInfo:
|
|
2012
|
-
| {
|
|
2013
|
-
type: "main";
|
|
2014
|
-
mediaSource: MainMediaSourceInterface;
|
|
2015
|
-
}
|
|
2016
|
-
| {
|
|
2017
|
-
type: "core";
|
|
2018
|
-
mediaSourceId: string;
|
|
2019
|
-
}
|
|
2020
|
-
| null;
|
|
2021
|
-
|
|
2022
|
-
/**
|
|
2023
|
-
* Current `RebufferingController` linked to the content, allowing to
|
|
2024
|
-
* detect and handle rebuffering situations.
|
|
2025
|
-
*
|
|
2026
|
-
* `null` if none is currently created for the content.
|
|
2027
|
-
*/
|
|
2028
|
-
rebufferingController: RebufferingController | null;
|
|
2029
|
-
/**
|
|
2030
|
-
* Current `StreamEventsEmitter` linked to the content, allowing to
|
|
2031
|
-
* send events found in the Manifest.
|
|
2032
|
-
*
|
|
2033
|
-
* `null` if none is currently created for the content.
|
|
2034
|
-
*/
|
|
2035
|
-
streamEventsEmitter: StreamEventsEmitter | null;
|
|
2036
|
-
/**
|
|
2037
|
-
* The initial position to seek to in seconds once the content is loadeed.
|
|
2038
|
-
* `undefined` if unknown yet.
|
|
2039
|
-
*/
|
|
2040
|
-
initialTime: number | undefined;
|
|
2041
|
-
/**
|
|
2042
|
-
* Whether to automatically play once the content is loaded.
|
|
2043
|
-
* `undefined` if unknown yet.
|
|
2044
|
-
*/
|
|
2045
|
-
autoPlay: boolean | undefined;
|
|
2046
|
-
/**
|
|
2047
|
-
* Set to `true` once the initial play (or skipping the initial play when
|
|
2048
|
-
* autoplay is not enabled) has been done.
|
|
2049
|
-
* Set to `false` when it hasn't been done yet.
|
|
2050
|
-
*
|
|
2051
|
-
* Set to `null` when those considerations are not taken yet.
|
|
2052
|
-
*/
|
|
2053
|
-
initialPlayPerformed: IReadOnlySharedReference<boolean> | null;
|
|
2054
|
-
/**
|
|
2055
|
-
* Set to the initialized `ContentDecryptor` instance linked to that content.
|
|
2056
|
-
*
|
|
2057
|
-
* Set to `null` when those considerations are not taken.
|
|
2058
|
-
*/
|
|
2059
|
-
contentDecryptor: IContentDecryptor | null;
|
|
2060
|
-
/**
|
|
2061
|
-
* If `true`, MSE API should be used in the core part of the RxPlayer (in the
|
|
2062
|
-
* WebWorker).
|
|
2063
|
-
* If `false`, they should be relied on on main thread.
|
|
2064
|
-
*/
|
|
2065
|
-
useMseInWorker: boolean;
|
|
2066
|
-
}
|
|
2067
|
-
|
|
2068
|
-
/** Arguments to give to the `InitializeOnMediaSource` function. */
|
|
2069
|
-
export interface IInitializeArguments {
|
|
2070
|
-
/** WebWorker inside which the core code runs. */
|
|
2071
|
-
worker: Worker;
|
|
2072
|
-
/**
|
|
2073
|
-
* If `true`, MSE API should be used in the core part of the RxPlayer (in the
|
|
2074
|
-
* WebWorker).
|
|
2075
|
-
* If `false`, they should be relied on on main thread.
|
|
2076
|
-
*
|
|
2077
|
-
* This might depend on both browser capabilities and preferences. It is
|
|
2078
|
-
* assumed that the caller perform all those checks, the `ContentInitializer`
|
|
2079
|
-
* won't check again the validity of this value.
|
|
2080
|
-
*/
|
|
2081
|
-
useMseInWorker: boolean;
|
|
2082
|
-
/** Options concerning the ABR logic. */
|
|
2083
|
-
adaptiveOptions: IAdaptiveRepresentationSelectorArguments;
|
|
2084
|
-
/** `true` if we should play when loaded. */
|
|
2085
|
-
autoPlay: boolean;
|
|
2086
|
-
/** Options concerning the media buffers. */
|
|
2087
|
-
bufferOptions: {
|
|
2088
|
-
/** Buffer "goal" at which we stop downloading new segments. */
|
|
2089
|
-
wantedBufferAhead: IReadOnlySharedReference<number>;
|
|
2090
|
-
/** Buffer maximum size in kiloBytes at which we stop downloading */
|
|
2091
|
-
maxVideoBufferSize: IReadOnlySharedReference<number>;
|
|
2092
|
-
/** Max buffer size after the current position, in seconds (we GC further up). */
|
|
2093
|
-
maxBufferAhead: IReadOnlySharedReference<number>;
|
|
2094
|
-
/** Max buffer size before the current position, in seconds (we GC further down). */
|
|
2095
|
-
maxBufferBehind: IReadOnlySharedReference<number>;
|
|
2096
|
-
/**
|
|
2097
|
-
* Enable/Disable fastSwitching: allow to replace lower-quality segments by
|
|
2098
|
-
* higher-quality ones to have a faster transition.
|
|
2099
|
-
*/
|
|
2100
|
-
enableFastSwitching: boolean;
|
|
2101
|
-
/** Behavior when a new video and/or audio codec is encountered. */
|
|
2102
|
-
onCodecSwitch: "continue" | "reload";
|
|
2103
|
-
};
|
|
2104
|
-
/**
|
|
2105
|
-
* When set to an object, enable "Common Media Client Data", or "CMCD".
|
|
2106
|
-
*/
|
|
2107
|
-
cmcd?: ICmcdOptions | undefined;
|
|
2108
|
-
/**
|
|
2109
|
-
* If `true`, the RxPlayer can enable its "Representation avoidance"
|
|
2110
|
-
* mechanism, where it avoid loading Representation that it suspect
|
|
2111
|
-
* have issues being decoded on the current device.
|
|
2112
|
-
*/
|
|
2113
|
-
enableRepresentationAvoidance: boolean;
|
|
2114
|
-
/** Every encryption configuration set. */
|
|
2115
|
-
keySystems: IKeySystemOption[];
|
|
2116
|
-
/** `true` to play low-latency contents optimally. */
|
|
2117
|
-
lowLatencyMode: boolean;
|
|
2118
|
-
/** Options relative to the streaming protocol. */
|
|
2119
|
-
transportOptions: Omit<
|
|
2120
|
-
ITransportOptions,
|
|
2121
|
-
"manifestLoader" | "segmentLoader" | "representationFilter"
|
|
2122
|
-
> & {
|
|
2123
|
-
// Unsupported features have to be disabled explicitely
|
|
2124
|
-
// TODO support them
|
|
2125
|
-
manifestLoader: undefined;
|
|
2126
|
-
segmentLoader: undefined;
|
|
2127
|
-
|
|
2128
|
-
// Option which has to be set as a Funtion string to work.
|
|
2129
|
-
representationFilter: string | undefined;
|
|
2130
|
-
};
|
|
2131
|
-
/** Settings linked to Manifest requests. */
|
|
2132
|
-
manifestRequestSettings: {
|
|
2133
|
-
/** Maximum number of time a request on error will be retried. */
|
|
2134
|
-
maxRetry: number | undefined;
|
|
2135
|
-
/**
|
|
2136
|
-
* Timeout after which request are aborted and, depending on other options,
|
|
2137
|
-
* retried.
|
|
2138
|
-
* To set to `-1` for no timeout.
|
|
2139
|
-
* `undefined` will lead to a default, large, timeout being used.
|
|
2140
|
-
*/
|
|
2141
|
-
requestTimeout: number | undefined;
|
|
2142
|
-
/**
|
|
2143
|
-
* Connection timeout, in milliseconds, after which the request is canceled
|
|
2144
|
-
* if the responses headers has not being received.
|
|
2145
|
-
* Do not set or set to "undefined" to disable it.
|
|
2146
|
-
*/
|
|
2147
|
-
connectionTimeout: number | undefined;
|
|
2148
|
-
/** Limit the frequency of Manifest updates. */
|
|
2149
|
-
minimumManifestUpdateInterval: number;
|
|
2150
|
-
/**
|
|
2151
|
-
* Potential first Manifest to rely on, allowing to skip the initial Manifest
|
|
2152
|
-
* request.
|
|
2153
|
-
*/
|
|
2154
|
-
initialManifest: IInitialManifest | undefined;
|
|
2155
|
-
};
|
|
2156
|
-
/** Configuration for the segment requesting logic. */
|
|
2157
|
-
segmentRequestOptions: {
|
|
2158
|
-
lowLatencyMode: boolean;
|
|
2159
|
-
/**
|
|
2160
|
-
* Amount of time after which a request should be aborted.
|
|
2161
|
-
* `undefined` indicates that a default value is wanted.
|
|
2162
|
-
* `-1` indicates no timeout.
|
|
2163
|
-
*/
|
|
2164
|
-
requestTimeout: number | undefined;
|
|
2165
|
-
/**
|
|
2166
|
-
* Amount of time, in milliseconds, after which a request that hasn't receive
|
|
2167
|
-
* the headers and status code should be aborted and optionnaly retried,
|
|
2168
|
-
* depending on the maxRetry configuration.
|
|
2169
|
-
*/
|
|
2170
|
-
connectionTimeout: number | undefined;
|
|
2171
|
-
/** Maximum number of time a request on error will be retried. */
|
|
2172
|
-
maxRetry: number | undefined;
|
|
2173
|
-
};
|
|
2174
|
-
/** Emit the playback rate (speed) set by the user. */
|
|
2175
|
-
speed: IReadOnlySharedReference<number>;
|
|
2176
|
-
/** The configured starting position. */
|
|
2177
|
-
startAt?: IInitialTimeOptions | undefined;
|
|
2178
|
-
/** Configuration specific to the text track. */
|
|
2179
|
-
textTrackOptions: ITextDisplayerOptions;
|
|
2180
|
-
/** URL of the Manifest. `undefined` if unknown or not pertinent. */
|
|
2181
|
-
url: string | undefined;
|
|
2182
|
-
}
|
|
2183
|
-
|
|
2184
|
-
function bindNumberReferencesToWorker(
|
|
2185
|
-
worker: Worker,
|
|
2186
|
-
cancellationSignal: CancellationSignal,
|
|
2187
|
-
...refs: Array<
|
|
2188
|
-
[
|
|
2189
|
-
IReadOnlySharedReference<number>,
|
|
2190
|
-
(
|
|
2191
|
-
| "wantedBufferAhead"
|
|
2192
|
-
| "maxVideoBufferSize"
|
|
2193
|
-
| "maxBufferBehind"
|
|
2194
|
-
| "maxBufferAhead"
|
|
2195
|
-
| "throttleVideoBitrate"
|
|
2196
|
-
),
|
|
2197
|
-
]
|
|
2198
|
-
>
|
|
2199
|
-
): void {
|
|
2200
|
-
for (const ref of refs) {
|
|
2201
|
-
ref[0].onUpdate(
|
|
2202
|
-
(newVal) => {
|
|
2203
|
-
// NOTE: The TypeScript checks have already been made by this function's
|
|
2204
|
-
// overload, but the body here is not aware of that.
|
|
2205
|
-
sendMessage(worker, {
|
|
2206
|
-
type: MainThreadMessageType.ReferenceUpdate,
|
|
2207
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
|
|
2208
|
-
value: { name: ref[1] as any, newVal: newVal as any },
|
|
2209
|
-
});
|
|
2210
|
-
},
|
|
2211
|
-
{ clearSignal: cancellationSignal, emitCurrentValue: true },
|
|
2212
|
-
);
|
|
2213
|
-
}
|
|
2214
|
-
}
|
|
2215
|
-
|
|
2216
|
-
function formatWorkerError(sentError: ISentError): IPlayerError {
|
|
2217
|
-
switch (sentError.name) {
|
|
2218
|
-
case "NetworkError":
|
|
2219
|
-
return new NetworkError(
|
|
2220
|
-
sentError.code,
|
|
2221
|
-
new RequestError(
|
|
2222
|
-
sentError.baseError.url,
|
|
2223
|
-
sentError.baseError.status,
|
|
2224
|
-
sentError.baseError.type,
|
|
2225
|
-
),
|
|
2226
|
-
);
|
|
2227
|
-
case "MediaError":
|
|
2228
|
-
// eslint-disable-next-line
|
|
2229
|
-
return new MediaError(sentError.code as any, sentError.reason, {
|
|
2230
|
-
tracks: sentError.tracks,
|
|
2231
|
-
});
|
|
2232
|
-
case "EncryptedMediaError":
|
|
2233
|
-
// We assume that everything have already been checked Worker-side here
|
|
2234
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
2235
|
-
return new EncryptedMediaError(sentError.code, sentError.reason, {
|
|
2236
|
-
keyStatuses: sentError.keyStatuses,
|
|
2237
|
-
keySystemConfiguration: sentError.keySystemConfiguration,
|
|
2238
|
-
keySystem: sentError.keySystem,
|
|
2239
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2240
|
-
} as any);
|
|
2241
|
-
case "OtherError":
|
|
2242
|
-
return new OtherError(sentError.code, sentError.reason);
|
|
2243
|
-
}
|
|
2244
|
-
}
|
|
2245
|
-
|
|
2246
|
-
/** Enume allowing to state what is the current status of MediaSource initialization. */
|
|
2247
|
-
const enum MediaSourceInitializationStatus {
|
|
2248
|
-
/**
|
|
2249
|
-
* The `MediaSource` is not attached to the `HTMLMediaElement` and shouldn't
|
|
2250
|
-
* be yet.
|
|
2251
|
-
*/
|
|
2252
|
-
Nothing,
|
|
2253
|
-
/**
|
|
2254
|
-
* The `MediaSource` is not yet attached to the `HTMLMediaElement` but it
|
|
2255
|
-
* now can and should be.
|
|
2256
|
-
*
|
|
2257
|
-
* The purpose of this enum variant is to be set when wanting to indicate
|
|
2258
|
-
* that `MediaSource` attachment has to be done, in code that do not have
|
|
2259
|
-
* the capability to do so.
|
|
2260
|
-
*
|
|
2261
|
-
* The code that can do so would then read that value and then set this enum
|
|
2262
|
-
* to `Attached` once the `MediaSource` is attached.
|
|
2263
|
-
*/
|
|
2264
|
-
AttachNow,
|
|
2265
|
-
/** The `MediaSource` is attached to the `HTMLMediaElement`. */
|
|
2266
|
-
Attached,
|
|
2267
|
-
}
|
|
2268
|
-
|
|
2269
|
-
interface IDrmInitializationStatus {
|
|
2270
|
-
/** Current initialization state the decryption logic is in. */
|
|
2271
|
-
initializationState: IDecryptionInitializationState;
|
|
2272
|
-
/**
|
|
2273
|
-
* If set, corresponds to the hex string describing the current key system
|
|
2274
|
-
* used.
|
|
2275
|
-
* `undefined` if unknown or if it does not apply.
|
|
2276
|
-
*/
|
|
2277
|
-
drmSystemId: string | undefined;
|
|
2278
|
-
}
|
|
2279
|
-
|
|
2280
|
-
/** Initialization steps to add decryption capabilities to an `HTMLMediaElement`. */
|
|
2281
|
-
type IDecryptionInitializationState =
|
|
2282
|
-
/**
|
|
2283
|
-
* Decryption capabilities have not been initialized yet.
|
|
2284
|
-
* You should wait before performing any action on the concerned
|
|
2285
|
-
* `HTMLMediaElement` (such as linking a content / `MediaSource` to it).
|
|
2286
|
-
*/
|
|
2287
|
-
| { type: "uninitialized"; value: null }
|
|
2288
|
-
/**
|
|
2289
|
-
* The `MediaSource` or media url can be linked AND segments can be pushed to
|
|
2290
|
-
* the `HTMLMediaElement` on which decryption capabilities were wanted.
|
|
2291
|
-
*/
|
|
2292
|
-
| {
|
|
2293
|
-
type: "initialized";
|
|
2294
|
-
value: null;
|
|
2295
|
-
};
|
|
2296
|
-
|
|
2297
|
-
function formatSourceBufferError(error: unknown): SourceBufferError {
|
|
2298
|
-
if (error instanceof SourceBufferError) {
|
|
2299
|
-
return error;
|
|
2300
|
-
} else if (error instanceof Error) {
|
|
2301
|
-
return new SourceBufferError(
|
|
2302
|
-
error.name,
|
|
2303
|
-
error.message,
|
|
2304
|
-
error.name === "QuotaExceededError",
|
|
2305
|
-
);
|
|
2306
|
-
} else {
|
|
2307
|
-
return new SourceBufferError("Error", "Unknown SourceBufferError Error", false);
|
|
2308
|
-
}
|
|
2309
|
-
}
|
|
2310
|
-
|
|
2311
|
-
/**
|
|
2312
|
-
* The Core might send back logs. In that situation, the message might be
|
|
2313
|
-
* formatted slightly differently to be able to cross threads (so a
|
|
2314
|
-
* serializable format has to be sent).
|
|
2315
|
-
*
|
|
2316
|
-
* This function translates that Core format to what's expected by the
|
|
2317
|
-
* logger.
|
|
2318
|
-
*
|
|
2319
|
-
* @param {*} arg
|
|
2320
|
-
* @returns {*}
|
|
2321
|
-
*/
|
|
2322
|
-
function formatSentLogObject(arg: ISentLogValue): IAcceptedLogValue {
|
|
2323
|
-
if (typeof arg !== "object") {
|
|
2324
|
-
return arg;
|
|
2325
|
-
}
|
|
2326
|
-
if (arg?.isSerializedError === true) {
|
|
2327
|
-
return formatWorkerError(arg as ISentError);
|
|
2328
|
-
}
|
|
2329
|
-
return arg as Exclude<ISentLogValue, ISentError>;
|
|
2330
|
-
}
|