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,63 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
* Copyright 2015 CANAL+ Group
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
import isCodecSupported from "../../compat/is_codec_supported";
|
|
1
|
+
import getEmeApiImplementation from "../../compat/eme";
|
|
17
2
|
import mayMediaElementFailOnUndecipherableData from "../../compat/may_media_element_fail_on_undecipherable_data";
|
|
18
3
|
import shouldReloadMediaSourceOnDecipherabilityUpdate from "../../compat/should_reload_media_source_on_decipherability_update";
|
|
19
|
-
import
|
|
20
|
-
import AdaptiveRepresentationSelector from "../../core/adaptive";
|
|
21
|
-
import CmcdDataBuilder from "../../core/cmcd";
|
|
22
|
-
import { CdnPrioritizer, createThumbnailFetcher, ManifestFetcher, SegmentQueueCreator, } from "../../core/fetchers";
|
|
23
|
-
import createContentTimeBoundariesObserver from "../../core/main/common/create_content_time_boundaries_observer";
|
|
24
|
-
import FreezeResolver from "../../core/main/common/FreezeResolver";
|
|
25
|
-
import getThumbnailData from "../../core/main/common/get_thumbnail_data";
|
|
26
|
-
import synchronizeSegmentSinksOnObservation from "../../core/main/common/synchronize_sinks_on_observation";
|
|
27
|
-
import SegmentSinksStore from "../../core/segment_sinks";
|
|
28
|
-
import StreamOrchestrator from "../../core/stream";
|
|
29
|
-
import { MediaError } from "../../errors";
|
|
4
|
+
import { EncryptedMediaError, MediaError, NetworkError, OtherError, SourceBufferError, } from "../../errors";
|
|
30
5
|
import features from "../../features";
|
|
31
6
|
import log from "../../log";
|
|
32
|
-
import
|
|
7
|
+
import { replicateUpdatesOnManifestMetadata, updateDecipherabilityFromKeyIds, updateDecipherabilityFromProtectionData, } from "../../manifest";
|
|
8
|
+
import MainMediaSourceInterface from "../../mse/main_media_source_interface";
|
|
9
|
+
import arrayFind from "../../utils/array_find";
|
|
33
10
|
import assert, { assertUnreachable } from "../../utils/assert";
|
|
34
|
-
import
|
|
11
|
+
import idGenerator from "../../utils/id_generator";
|
|
35
12
|
import isNullOrUndefined from "../../utils/is_null_or_undefined";
|
|
36
|
-
import noop from "../../utils/noop";
|
|
37
13
|
import objectAssign from "../../utils/object_assign";
|
|
38
|
-
import
|
|
39
|
-
import
|
|
14
|
+
import SharedReference from "../../utils/reference";
|
|
15
|
+
import { RequestError } from "../../utils/request";
|
|
16
|
+
import TaskCanceller, { CancellationError } from "../../utils/task_canceller";
|
|
40
17
|
import { ContentDecryptorState, getKeySystemConfiguration } from "../decrypt";
|
|
41
18
|
import { ContentInitializer } from "./types";
|
|
42
19
|
import createCorePlaybackObserver from "./utils/create_core_playback_observer";
|
|
43
|
-
import
|
|
20
|
+
import { resetMediaElement, disableRemotePlaybackOnManagedMediaSource, } from "./utils/create_media_source";
|
|
44
21
|
import getInitialTime from "./utils/get_initial_time";
|
|
45
22
|
import getLoadedReference from "./utils/get_loaded_reference";
|
|
46
23
|
import performInitialSeekAndPlay from "./utils/initial_seek_and_play";
|
|
47
|
-
import initializeContentDecryption from "./utils/initialize_content_decryption";
|
|
48
|
-
import MainThreadTextDisplayerInterface from "./utils/main_thread_text_displayer_interface";
|
|
49
24
|
import RebufferingController from "./utils/rebuffering_controller";
|
|
50
|
-
import StreamEventsEmitter from "./utils/stream_events_emitter";
|
|
25
|
+
import StreamEventsEmitter from "./utils/stream_events_emitter/stream_events_emitter";
|
|
51
26
|
import listenToMediaError from "./utils/throw_on_media_error";
|
|
27
|
+
import { updateManifestCodecSupport } from "./utils/update_manifest_codec_support";
|
|
28
|
+
const generateContentId = idGenerator();
|
|
52
29
|
/**
|
|
53
|
-
* Allows to load a new content thanks to the MediaSource Extensions (a.k.a. MSE)
|
|
54
|
-
* Web APIs.
|
|
55
|
-
*
|
|
56
|
-
* Through this `ContentInitializer`, a Manifest will be fetched (and depending
|
|
57
|
-
* on the situation, refreshed), a `MediaSource` instance will be linked to the
|
|
58
|
-
* wanted `HTMLMediaElement` and chunks of media data, called segments, will be
|
|
59
|
-
* pushed on buffers associated to this `MediaSource` instance.
|
|
60
|
-
*
|
|
61
30
|
* @class MediaSourceContentInitializer
|
|
62
31
|
*/
|
|
63
32
|
export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
@@ -68,51 +37,146 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
68
37
|
*/
|
|
69
38
|
constructor(settings) {
|
|
70
39
|
super();
|
|
71
|
-
this.
|
|
40
|
+
this._settings = settings;
|
|
72
41
|
this._initCanceller = new TaskCanceller();
|
|
73
|
-
this.
|
|
74
|
-
this.
|
|
75
|
-
|
|
76
|
-
this.
|
|
77
|
-
|
|
78
|
-
|
|
42
|
+
this._currentMediaSourceCanceller = new TaskCanceller();
|
|
43
|
+
this._currentMediaSourceCanceller.linkToSignal(this._initCanceller.signal);
|
|
44
|
+
this._currentContentInfo = null;
|
|
45
|
+
this._awaitingRequests = {
|
|
46
|
+
nextRequestId: 0,
|
|
47
|
+
pendingSinkMetrics: new Map(),
|
|
48
|
+
pendingThumbnailFetching: new Map(),
|
|
49
|
+
};
|
|
50
|
+
this._queuedCoreMessages = null;
|
|
79
51
|
}
|
|
80
52
|
/**
|
|
81
53
|
* Perform non-destructive preparation steps, to prepare a future content.
|
|
82
|
-
* For now, this mainly mean loading the Manifest document.
|
|
83
54
|
*/
|
|
84
55
|
prepare() {
|
|
85
|
-
|
|
56
|
+
var _a, _b;
|
|
57
|
+
if (this._currentContentInfo !== null || this._initCanceller.isUsed()) {
|
|
86
58
|
return;
|
|
87
59
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
60
|
+
const contentId = generateContentId();
|
|
61
|
+
const { adaptiveOptions, transport, transportOptions, useMseInWorker, coreInterface, } = this._settings;
|
|
62
|
+
const { wantedBufferAhead, maxVideoBufferSize, maxBufferAhead, maxBufferBehind } = this._settings.bufferOptions;
|
|
63
|
+
const initialVideoBitrate = adaptiveOptions.initialBitrates.video;
|
|
64
|
+
const initialAudioBitrate = adaptiveOptions.initialBitrates.audio;
|
|
65
|
+
this._currentContentInfo = {
|
|
66
|
+
contentId,
|
|
67
|
+
contentDecryptor: null,
|
|
68
|
+
manifest: null,
|
|
69
|
+
mediaSourceInfo: null,
|
|
70
|
+
rebufferingController: null,
|
|
71
|
+
streamEventsEmitter: null,
|
|
72
|
+
initialTime: undefined,
|
|
73
|
+
autoPlay: undefined,
|
|
74
|
+
initialPlayPerformed: null,
|
|
75
|
+
useMseInWorker,
|
|
76
|
+
};
|
|
77
|
+
coreInterface.sendMessage({
|
|
78
|
+
type: "prepare" /* MainThreadMessageType.PrepareContent */,
|
|
79
|
+
value: {
|
|
80
|
+
contentId,
|
|
81
|
+
cmcd: this._settings.cmcd,
|
|
82
|
+
enableRepresentationAvoidance: this._settings.enableRepresentationAvoidance,
|
|
83
|
+
url: this._settings.url,
|
|
84
|
+
hasText: this._hasTextBufferFeature(),
|
|
85
|
+
transport,
|
|
86
|
+
transportOptions,
|
|
87
|
+
initialVideoBitrate,
|
|
88
|
+
initialAudioBitrate,
|
|
89
|
+
manifestRetryOptions: Object.assign(Object.assign({}, this._settings.manifestRequestSettings), { lowLatencyMode: this._settings.lowLatencyMode }),
|
|
90
|
+
segmentRetryOptions: this._settings.segmentRequestOptions,
|
|
91
|
+
useMseInWorker,
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
this._initCanceller.signal.register(() => {
|
|
95
|
+
coreInterface.sendMessage({
|
|
96
|
+
type: "stop" /* MainThreadMessageType.StopContent */,
|
|
97
|
+
contentId,
|
|
98
|
+
value: null,
|
|
96
99
|
});
|
|
97
|
-
})
|
|
98
|
-
this.
|
|
100
|
+
});
|
|
101
|
+
if (this._initCanceller.isUsed()) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
this._queuedCoreMessages = [];
|
|
105
|
+
log.debug("Init", "addEventListener prepare buffering core messages");
|
|
106
|
+
const onmessage = (msgData) => {
|
|
107
|
+
if (msgData.type !== "log" /* CoreMessageType.LogMessage */) {
|
|
108
|
+
log.debug("Init", "Core message received", msgData.type);
|
|
109
|
+
}
|
|
110
|
+
const type = msgData.type;
|
|
111
|
+
switch (type) {
|
|
112
|
+
case "log" /* CoreMessageType.LogMessage */: {
|
|
113
|
+
const formatted = msgData.value.logs.map((l) => {
|
|
114
|
+
switch (typeof l) {
|
|
115
|
+
case "string":
|
|
116
|
+
case "number":
|
|
117
|
+
case "boolean":
|
|
118
|
+
case "undefined":
|
|
119
|
+
return l;
|
|
120
|
+
case "object":
|
|
121
|
+
if (l === null) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
return formatSentLogObject(l);
|
|
125
|
+
default:
|
|
126
|
+
assertUnreachable(l);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
switch (msgData.value.logLevel) {
|
|
130
|
+
case "NONE":
|
|
131
|
+
break;
|
|
132
|
+
case "ERROR":
|
|
133
|
+
log.error(msgData.value.namespace, ...formatted);
|
|
134
|
+
break;
|
|
135
|
+
case "WARNING":
|
|
136
|
+
log.warn(msgData.value.namespace, ...formatted);
|
|
137
|
+
break;
|
|
138
|
+
case "INFO":
|
|
139
|
+
log.info(msgData.value.namespace, ...formatted);
|
|
140
|
+
break;
|
|
141
|
+
case "DEBUG":
|
|
142
|
+
log.debug(msgData.value.namespace, ...formatted);
|
|
143
|
+
break;
|
|
144
|
+
default:
|
|
145
|
+
assertUnreachable(msgData.value.logLevel);
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
default:
|
|
150
|
+
if (this._queuedCoreMessages !== null) {
|
|
151
|
+
this._queuedCoreMessages.push(msgData);
|
|
152
|
+
}
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
this._settings.coreInterface.addMessageListener(onmessage);
|
|
157
|
+
const onmessageerror = () => {
|
|
158
|
+
log.error("Init", "Error when receiving message from core.");
|
|
159
|
+
};
|
|
160
|
+
this._settings.coreInterface.addErrorListener(onmessageerror);
|
|
99
161
|
this._initCanceller.signal.register(() => {
|
|
100
|
-
|
|
162
|
+
log.debug("Init", "removeEventListener prepare for core message");
|
|
163
|
+
this._settings.coreInterface.removeMessageListener(onmessage);
|
|
164
|
+
this._settings.coreInterface.removeErrorListener(onmessageerror);
|
|
101
165
|
});
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
/** Translate errors coming from the media element into RxPlayer errors. */
|
|
110
|
-
listenToMediaError(mediaElement, (error) => this._onFatalError(error), this._initCanceller.signal);
|
|
111
|
-
this._setupInitialMediaSourceAndDecryption(mediaElement)
|
|
112
|
-
.then((initResult) => this._onInitialMediaSourceReady(mediaElement, initResult.mediaSource, playbackObserver, initResult.drmSystemId, initResult.unlinkMediaSource))
|
|
113
|
-
.catch((err) => {
|
|
114
|
-
this._onFatalError(err);
|
|
166
|
+
// Also bind all `SharedReference` objects:
|
|
167
|
+
const throttleVideoBitrate = (_a = adaptiveOptions.throttlers.throttleBitrate.video) !== null && _a !== void 0 ? _a : new SharedReference(Infinity);
|
|
168
|
+
bindNumberReferencesToCore(coreInterface, this._initCanceller.signal, [wantedBufferAhead, "wantedBufferAhead"], [maxVideoBufferSize, "maxVideoBufferSize"], [maxBufferAhead, "maxBufferAhead"], [maxBufferBehind, "maxBufferBehind"], [throttleVideoBitrate, "throttleVideoBitrate"]);
|
|
169
|
+
const limitVideoResolution = (_b = adaptiveOptions.throttlers.limitResolution.video) !== null && _b !== void 0 ? _b : new SharedReference({
|
|
170
|
+
height: undefined,
|
|
171
|
+
width: undefined,
|
|
172
|
+
pixelRatio: 1,
|
|
115
173
|
});
|
|
174
|
+
limitVideoResolution.onUpdate((newVal) => {
|
|
175
|
+
coreInterface.sendMessage({
|
|
176
|
+
type: "ref-update" /* MainThreadMessageType.ReferenceUpdate */,
|
|
177
|
+
value: { name: "limitVideoResolution", newVal },
|
|
178
|
+
});
|
|
179
|
+
}, { clearSignal: this._initCanceller.signal, emitCurrentValue: true });
|
|
116
180
|
}
|
|
117
181
|
/**
|
|
118
182
|
* Update URL of the Manifest.
|
|
@@ -122,275 +186,1068 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
122
186
|
* DASH's MPD) will be refreshed immediately.
|
|
123
187
|
*/
|
|
124
188
|
updateContentUrls(urls, refreshNow) {
|
|
125
|
-
this.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
189
|
+
if (this._currentContentInfo === null) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
this._settings.coreInterface.sendMessage({
|
|
193
|
+
type: "urls-update" /* MainThreadMessageType.ContentUrlsUpdate */,
|
|
194
|
+
contentId: this._currentContentInfo.contentId,
|
|
195
|
+
value: { urls, refreshNow },
|
|
196
|
+
});
|
|
133
197
|
}
|
|
134
198
|
/**
|
|
135
|
-
*
|
|
136
|
-
* @param {
|
|
199
|
+
* @param {HTMLMediaElement} mediaElement
|
|
200
|
+
* @param {Object} playbackObserver
|
|
137
201
|
*/
|
|
138
|
-
|
|
202
|
+
start(mediaElement, playbackObserver) {
|
|
203
|
+
this.prepare(); // Load Manifest if not already done
|
|
139
204
|
if (this._initCanceller.isUsed()) {
|
|
140
205
|
return;
|
|
141
206
|
}
|
|
142
|
-
|
|
143
|
-
this.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
207
|
+
let textDisplayer = null;
|
|
208
|
+
if (this._settings.textTrackOptions.textTrackMode === "html" &&
|
|
209
|
+
features.htmlTextDisplayer !== null) {
|
|
210
|
+
assert(this._hasTextBufferFeature());
|
|
211
|
+
textDisplayer = new features.htmlTextDisplayer(mediaElement, this._settings.textTrackOptions.textTrackElement);
|
|
212
|
+
}
|
|
213
|
+
else if (features.nativeTextDisplayer !== null) {
|
|
214
|
+
assert(this._hasTextBufferFeature());
|
|
215
|
+
textDisplayer = new features.nativeTextDisplayer(mediaElement);
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
assert(!this._hasTextBufferFeature());
|
|
219
|
+
}
|
|
220
|
+
this._initCanceller.signal.register(() => {
|
|
221
|
+
textDisplayer === null || textDisplayer === void 0 ? void 0 : textDisplayer.stop();
|
|
222
|
+
});
|
|
223
|
+
/** Translate errors coming from the media element into RxPlayer errors. */
|
|
224
|
+
listenToMediaError(mediaElement, (error) => this._onFatalError(error), this._initCanceller.signal);
|
|
225
|
+
/**
|
|
226
|
+
* Send content protection initialization data.
|
|
227
|
+
* TODO remove and use ContentDecryptor directly when possible.
|
|
228
|
+
*/
|
|
229
|
+
const lastContentProtection = new SharedReference(null);
|
|
230
|
+
const mediaSourceStatus = new SharedReference(0 /* MediaSourceInitializationStatus.Nothing */);
|
|
231
|
+
const { statusRef: drmInitializationStatus, contentDecryptor } = this._initializeContentDecryption(mediaElement, lastContentProtection, mediaSourceStatus, () => notifyAndStartMediaSourceReload(0, undefined, undefined), this._initCanceller.signal);
|
|
232
|
+
const contentInfo = this._currentContentInfo;
|
|
233
|
+
if (contentInfo !== null) {
|
|
234
|
+
contentInfo.contentDecryptor = contentDecryptor;
|
|
235
|
+
}
|
|
236
|
+
const playbackStartParams = {
|
|
237
|
+
mediaElement,
|
|
238
|
+
textDisplayer,
|
|
239
|
+
playbackObserver,
|
|
240
|
+
drmInitializationStatus,
|
|
241
|
+
mediaSourceStatus,
|
|
242
|
+
};
|
|
243
|
+
mediaSourceStatus.onUpdate((msInitStatus, stopListeningMSStatus) => {
|
|
244
|
+
if (msInitStatus === 2 /* MediaSourceInitializationStatus.Attached */) {
|
|
245
|
+
stopListeningMSStatus();
|
|
246
|
+
this._startPlaybackIfReady(playbackStartParams);
|
|
247
|
+
}
|
|
248
|
+
}, { clearSignal: this._initCanceller.signal, emitCurrentValue: true });
|
|
249
|
+
drmInitializationStatus.onUpdate((initializationStatus, stopListeningDrm) => {
|
|
250
|
+
if (initializationStatus.initializationState.type === "initialized") {
|
|
251
|
+
stopListeningDrm();
|
|
252
|
+
this._startPlaybackIfReady(playbackStartParams);
|
|
253
|
+
}
|
|
254
|
+
}, { emitCurrentValue: true, clearSignal: this._initCanceller.signal });
|
|
255
|
+
/**
|
|
256
|
+
* Reset directly (synchronously) the current `MediaSource` and signal to
|
|
257
|
+
* the core that we did so.
|
|
258
|
+
* @param {number} deltaPosition - Position you want to seek to after
|
|
259
|
+
* reloading, as a delta in seconds from the last polled playing position.
|
|
260
|
+
* @param {number|undefined} minimumPosition - If set, minimum time bound
|
|
261
|
+
* in seconds after `deltaPosition` has been applied.
|
|
262
|
+
* @param {number|undefined} maximumPosition - If set, minimum time bound
|
|
263
|
+
* in seconds after `deltaPosition` has been applied.
|
|
264
|
+
*/
|
|
265
|
+
const notifyAndStartMediaSourceReload = (deltaPosition, minimumPosition, maximumPosition) => {
|
|
266
|
+
const reloadingContentInfo = this._currentContentInfo;
|
|
267
|
+
if (reloadingContentInfo === null) {
|
|
268
|
+
log.warn("Init", "Asked to reload when no content is loaded.");
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (reloadingContentInfo === null ||
|
|
272
|
+
reloadingContentInfo.mediaSourceInfo === null) {
|
|
273
|
+
log.warn("Init", "Asked to reload when no MediaSource is active.");
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const mediaSourceId = reloadingContentInfo.mediaSourceInfo.type === "main"
|
|
277
|
+
? reloadingContentInfo.mediaSourceInfo.mediaSource.id
|
|
278
|
+
: reloadingContentInfo.mediaSourceInfo.mediaSourceId;
|
|
279
|
+
this._settings.coreInterface.sendMessage({
|
|
280
|
+
type: "ms-reload" /* MainThreadMessageType.MediaSourceReload */,
|
|
281
|
+
mediaSourceId,
|
|
282
|
+
value: null,
|
|
283
|
+
});
|
|
284
|
+
reloadMediaSource(deltaPosition, minimumPosition, maximumPosition);
|
|
285
|
+
};
|
|
286
|
+
/**
|
|
287
|
+
* Reset directly (synchronously) the current `MediaSource`.
|
|
288
|
+
*
|
|
289
|
+
* It is assumed that `core` already knows about this action. If not, call
|
|
290
|
+
* `notifyAndStartMediaSourceReload` instead.
|
|
291
|
+
* @param {number} deltaPosition - Position you want to seek to after
|
|
292
|
+
* reloading, as a delta in seconds from the last polled playing position.
|
|
293
|
+
* @param {number|undefined} minimumPosition - If set, minimum time bound
|
|
294
|
+
* in seconds after `deltaPosition` has been applied.
|
|
295
|
+
* @param {number|undefined} maximumPosition - If set, minimum time bound
|
|
296
|
+
* in seconds after `deltaPosition` has been applied.
|
|
297
|
+
*/
|
|
298
|
+
const reloadMediaSource = (deltaPosition, minimumPosition, maximumPosition) => {
|
|
299
|
+
var _a;
|
|
300
|
+
const reloadingContentInfo = this._currentContentInfo;
|
|
301
|
+
if (reloadingContentInfo === null) {
|
|
302
|
+
log.warn("Init", "Asked to reload when no content is loaded.");
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const lastObservation = playbackObserver.getReference().getValue();
|
|
306
|
+
const currentPosition = lastObservation.position.getWanted();
|
|
307
|
+
const isPaused = ((_a = reloadingContentInfo.initialPlayPerformed) === null || _a === void 0 ? void 0 : _a.getValue()) === true ||
|
|
308
|
+
reloadingContentInfo.autoPlay === undefined
|
|
309
|
+
? lastObservation.paused
|
|
310
|
+
: !reloadingContentInfo.autoPlay;
|
|
311
|
+
let position = currentPosition + deltaPosition;
|
|
312
|
+
if (minimumPosition !== undefined) {
|
|
313
|
+
position = Math.max(minimumPosition, position);
|
|
314
|
+
}
|
|
315
|
+
if (maximumPosition !== undefined) {
|
|
316
|
+
position = Math.min(maximumPosition, position);
|
|
317
|
+
}
|
|
318
|
+
this._reload(mediaElement, textDisplayer, playbackObserver, mediaSourceStatus, position, !isPaused);
|
|
319
|
+
};
|
|
320
|
+
const onmessage = (msgData) => {
|
|
321
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28;
|
|
322
|
+
switch (msgData.type) {
|
|
323
|
+
case "attach-media-source" /* CoreMessageType.AttachMediaSource */: {
|
|
324
|
+
if (((_a = this._currentContentInfo) === null || _a === void 0 ? void 0 : _a.contentId) !== msgData.contentId) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
if (this._currentContentInfo !== null) {
|
|
328
|
+
if (((_b = this._currentContentInfo.mediaSourceInfo) === null || _b === void 0 ? void 0 : _b.type) === "main") {
|
|
329
|
+
this._currentContentInfo.mediaSourceInfo.mediaSource.dispose();
|
|
330
|
+
}
|
|
331
|
+
this._currentContentInfo.mediaSourceInfo = {
|
|
332
|
+
type: "core",
|
|
333
|
+
mediaSourceId: msgData.mediaSourceId,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
const mediaSourceLink = msgData.value;
|
|
337
|
+
mediaSourceStatus.onUpdate((currStatus, stopListening) => {
|
|
338
|
+
if (currStatus === 1 /* MediaSourceInitializationStatus.AttachNow */) {
|
|
339
|
+
stopListening();
|
|
340
|
+
log.info("media", "Attaching MediaSource URL to the media element");
|
|
341
|
+
if (mediaSourceLink.type === "handle") {
|
|
342
|
+
mediaElement.srcObject = mediaSourceLink.value;
|
|
343
|
+
this._currentMediaSourceCanceller.signal.register(() => {
|
|
344
|
+
mediaElement.srcObject = null;
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
mediaElement.src = mediaSourceLink.value;
|
|
349
|
+
this._currentMediaSourceCanceller.signal.register(() => {
|
|
350
|
+
resetMediaElement(mediaElement, mediaSourceLink.value);
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
disableRemotePlaybackOnManagedMediaSource(mediaElement, this._currentMediaSourceCanceller.signal);
|
|
354
|
+
mediaSourceStatus.setValue(2 /* MediaSourceInitializationStatus.Attached */);
|
|
355
|
+
}
|
|
356
|
+
}, { emitCurrentValue: true, clearSignal: this._initCanceller.signal });
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
case "warning" /* CoreMessageType.Warning */:
|
|
360
|
+
if (((_c = this._currentContentInfo) === null || _c === void 0 ? void 0 : _c.contentId) !== msgData.contentId) {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
this.trigger("warning", formatCoreError(msgData.value));
|
|
364
|
+
break;
|
|
365
|
+
case "error" /* CoreMessageType.Error */:
|
|
366
|
+
if (((_d = this._currentContentInfo) === null || _d === void 0 ? void 0 : _d.contentId) !== msgData.contentId) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
this._onFatalError(formatCoreError(msgData.value));
|
|
370
|
+
break;
|
|
371
|
+
case "create-media-source" /* CoreMessageType.CreateMediaSource */:
|
|
372
|
+
this._onCreateMediaSourceMessage(msgData, mediaElement, mediaSourceStatus, this._settings.coreInterface);
|
|
373
|
+
break;
|
|
374
|
+
case "add-source-buffer" /* CoreMessageType.AddSourceBuffer */:
|
|
375
|
+
{
|
|
376
|
+
if (((_f = (_e = this._currentContentInfo) === null || _e === void 0 ? void 0 : _e.mediaSourceInfo) === null || _f === void 0 ? void 0 : _f.type) !== "main" ||
|
|
377
|
+
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
378
|
+
msgData.mediaSourceId) {
|
|
164
379
|
return;
|
|
165
380
|
}
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
381
|
+
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
382
|
+
mediaSource.addSourceBuffer(msgData.value.sourceBufferType, msgData.value.codec);
|
|
383
|
+
}
|
|
384
|
+
break;
|
|
385
|
+
case "source-buffer-append" /* CoreMessageType.SourceBufferAppend */:
|
|
386
|
+
{
|
|
387
|
+
if (((_h = (_g = this._currentContentInfo) === null || _g === void 0 ? void 0 : _g.mediaSourceInfo) === null || _h === void 0 ? void 0 : _h.type) !== "main" ||
|
|
388
|
+
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
389
|
+
msgData.mediaSourceId) {
|
|
175
390
|
return;
|
|
176
391
|
}
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
392
|
+
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
393
|
+
const sourceBuffer = arrayFind(mediaSource.sourceBuffers, (s) => s.type === msgData.sourceBufferType);
|
|
394
|
+
if (sourceBuffer === undefined) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
sourceBuffer
|
|
398
|
+
.appendBuffer(msgData.value.data, msgData.value.params)
|
|
399
|
+
.then((buffered) => {
|
|
400
|
+
this._settings.coreInterface.sendMessage({
|
|
401
|
+
type: "sb-success" /* MainThreadMessageType.SourceBufferSuccess */,
|
|
402
|
+
mediaSourceId: mediaSource.id,
|
|
403
|
+
sourceBufferType: sourceBuffer.type,
|
|
404
|
+
operationId: msgData.operationId,
|
|
405
|
+
value: { buffered },
|
|
406
|
+
});
|
|
407
|
+
})
|
|
408
|
+
.catch((error) => {
|
|
409
|
+
this._settings.coreInterface.sendMessage({
|
|
410
|
+
type: "sb-error" /* MainThreadMessageType.SourceBufferError */,
|
|
411
|
+
mediaSourceId: mediaSource.id,
|
|
412
|
+
sourceBufferType: sourceBuffer.type,
|
|
413
|
+
operationId: msgData.operationId,
|
|
414
|
+
value: error instanceof CancellationError
|
|
415
|
+
? { errorName: "CancellationError" }
|
|
416
|
+
: formatSourceBufferError(error).serialize(),
|
|
417
|
+
});
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
break;
|
|
421
|
+
case "source-buffer-remove" /* CoreMessageType.SourceBufferRemove */:
|
|
422
|
+
{
|
|
423
|
+
if (((_k = (_j = this._currentContentInfo) === null || _j === void 0 ? void 0 : _j.mediaSourceInfo) === null || _k === void 0 ? void 0 : _k.type) !== "main" ||
|
|
424
|
+
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
425
|
+
msgData.mediaSourceId) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
429
|
+
const sourceBuffer = arrayFind(mediaSource.sourceBuffers, (s) => s.type === msgData.sourceBufferType);
|
|
430
|
+
if (sourceBuffer === undefined) {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
sourceBuffer
|
|
434
|
+
.remove(msgData.value.start, msgData.value.end)
|
|
435
|
+
.then((buffered) => {
|
|
436
|
+
this._settings.coreInterface.sendMessage({
|
|
437
|
+
type: "sb-success" /* MainThreadMessageType.SourceBufferSuccess */,
|
|
438
|
+
mediaSourceId: mediaSource.id,
|
|
439
|
+
sourceBufferType: sourceBuffer.type,
|
|
440
|
+
operationId: msgData.operationId,
|
|
441
|
+
value: { buffered },
|
|
442
|
+
});
|
|
443
|
+
})
|
|
444
|
+
.catch((error) => {
|
|
445
|
+
this._settings.coreInterface.sendMessage({
|
|
446
|
+
type: "sb-error" /* MainThreadMessageType.SourceBufferError */,
|
|
447
|
+
mediaSourceId: mediaSource.id,
|
|
448
|
+
sourceBufferType: sourceBuffer.type,
|
|
449
|
+
operationId: msgData.operationId,
|
|
450
|
+
value: error instanceof CancellationError
|
|
451
|
+
? { errorName: "CancellationError" }
|
|
452
|
+
: formatSourceBufferError(error).serialize(),
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
break;
|
|
457
|
+
case "abort-source-buffer" /* CoreMessageType.AbortSourceBuffer */:
|
|
458
|
+
{
|
|
459
|
+
if (((_m = (_l = this._currentContentInfo) === null || _l === void 0 ? void 0 : _l.mediaSourceInfo) === null || _m === void 0 ? void 0 : _m.type) !== "main" ||
|
|
460
|
+
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
461
|
+
msgData.mediaSourceId) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
465
|
+
const sourceBuffer = arrayFind(mediaSource.sourceBuffers, (s) => s.type === msgData.sourceBufferType);
|
|
466
|
+
if (sourceBuffer === undefined) {
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
sourceBuffer.abort();
|
|
470
|
+
}
|
|
471
|
+
break;
|
|
472
|
+
case "update-media-source-duration" /* CoreMessageType.UpdateMediaSourceDuration */:
|
|
473
|
+
{
|
|
474
|
+
if (((_p = (_o = this._currentContentInfo) === null || _o === void 0 ? void 0 : _o.mediaSourceInfo) === null || _p === void 0 ? void 0 : _p.type) !== "main" ||
|
|
475
|
+
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
476
|
+
msgData.mediaSourceId) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
480
|
+
if ((mediaSource === null || mediaSource === void 0 ? void 0 : mediaSource.id) !== msgData.mediaSourceId) {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
mediaSource.setDuration(msgData.value.duration, msgData.value.isRealEndKnown);
|
|
484
|
+
}
|
|
485
|
+
break;
|
|
486
|
+
case "stop-media-source-duration" /* CoreMessageType.InterruptMediaSourceDurationUpdate */:
|
|
487
|
+
{
|
|
488
|
+
if (((_r = (_q = this._currentContentInfo) === null || _q === void 0 ? void 0 : _q.mediaSourceInfo) === null || _r === void 0 ? void 0 : _r.type) !== "main" ||
|
|
489
|
+
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
490
|
+
msgData.mediaSourceId) {
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
494
|
+
if ((mediaSource === null || mediaSource === void 0 ? void 0 : mediaSource.id) !== msgData.mediaSourceId) {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
mediaSource.interruptDurationSetting();
|
|
498
|
+
}
|
|
499
|
+
break;
|
|
500
|
+
case "end-of-stream" /* CoreMessageType.EndOfStream */:
|
|
501
|
+
{
|
|
502
|
+
if (((_t = (_s = this._currentContentInfo) === null || _s === void 0 ? void 0 : _s.mediaSourceInfo) === null || _t === void 0 ? void 0 : _t.type) !== "main" ||
|
|
503
|
+
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
504
|
+
msgData.mediaSourceId) {
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
508
|
+
mediaSource.maintainEndOfStream();
|
|
509
|
+
}
|
|
510
|
+
break;
|
|
511
|
+
case "stop-end-of-stream" /* CoreMessageType.InterruptEndOfStream */:
|
|
512
|
+
{
|
|
513
|
+
if (((_v = (_u = this._currentContentInfo) === null || _u === void 0 ? void 0 : _u.mediaSourceInfo) === null || _v === void 0 ? void 0 : _v.type) !== "main" ||
|
|
514
|
+
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
515
|
+
msgData.mediaSourceId) {
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
519
|
+
mediaSource.stopEndOfStream();
|
|
520
|
+
}
|
|
521
|
+
break;
|
|
522
|
+
case "dispose-media-source" /* CoreMessageType.DisposeMediaSource */:
|
|
523
|
+
{
|
|
524
|
+
if (((_x = (_w = this._currentContentInfo) === null || _w === void 0 ? void 0 : _w.mediaSourceInfo) === null || _x === void 0 ? void 0 : _x.type) !== "main" ||
|
|
525
|
+
this._currentContentInfo.mediaSourceInfo.mediaSource.id !==
|
|
526
|
+
msgData.mediaSourceId) {
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
const { mediaSource } = this._currentContentInfo.mediaSourceInfo;
|
|
530
|
+
mediaSource.dispose();
|
|
531
|
+
}
|
|
532
|
+
break;
|
|
533
|
+
case "needs-buffer-flush" /* CoreMessageType.NeedsBufferFlush */: {
|
|
534
|
+
if (((_y = this._currentContentInfo) === null || _y === void 0 ? void 0 : _y.contentId) !== msgData.contentId) {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
const lastObservation = playbackObserver.getReference().getValue();
|
|
538
|
+
const currentTime = lastObservation.position.isAwaitingFuturePosition()
|
|
539
|
+
? lastObservation.position.getWanted()
|
|
540
|
+
: mediaElement.currentTime;
|
|
541
|
+
const relativeResumingPosition = (_0 = (_z = msgData.value) === null || _z === void 0 ? void 0 : _z.relativeResumingPosition) !== null && _0 !== void 0 ? _0 : 0;
|
|
542
|
+
const canBeApproximateSeek = Boolean((_1 = msgData.value) === null || _1 === void 0 ? void 0 : _1.relativePosHasBeenDefaulted);
|
|
543
|
+
let wantedSeekingTime;
|
|
544
|
+
if (relativeResumingPosition === 0 && canBeApproximateSeek) {
|
|
545
|
+
// in case relativeResumingPosition is 0, we still perform
|
|
546
|
+
// a tiny seek to be sure that the browser will correclty reload the video.
|
|
547
|
+
wantedSeekingTime = currentTime + 0.001;
|
|
193
548
|
}
|
|
194
549
|
else {
|
|
195
|
-
|
|
550
|
+
wantedSeekingTime = currentTime + relativeResumingPosition;
|
|
196
551
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
drmInitRef.onUpdate((drmStatus, stopListeningToDrmUpdates) => {
|
|
212
|
-
if (drmStatus.initializationState.type === "uninitialized") {
|
|
213
|
-
return;
|
|
552
|
+
playbackObserver.setCurrentTime(wantedSeekingTime);
|
|
553
|
+
break;
|
|
554
|
+
}
|
|
555
|
+
case "active-period-changed" /* CoreMessageType.ActivePeriodChanged */: {
|
|
556
|
+
if (((_2 = this._currentContentInfo) === null || _2 === void 0 ? void 0 : _2.contentId) !== msgData.contentId ||
|
|
557
|
+
this._currentContentInfo.manifest === null) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
const period = arrayFind(this._currentContentInfo.manifest.periods, (p) => p.id === msgData.value.periodId);
|
|
561
|
+
if (period !== undefined) {
|
|
562
|
+
this.trigger("activePeriodChanged", { period });
|
|
563
|
+
}
|
|
564
|
+
break;
|
|
214
565
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
if (
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
566
|
+
case "adaptation-changed" /* CoreMessageType.AdaptationChanged */: {
|
|
567
|
+
if (((_3 = this._currentContentInfo) === null || _3 === void 0 ? void 0 : _3.contentId) !== msgData.contentId ||
|
|
568
|
+
this._currentContentInfo.manifest === null) {
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
const period = arrayFind(this._currentContentInfo.manifest.periods, (p) => p.id === msgData.value.periodId);
|
|
572
|
+
if (period === undefined) {
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
if (msgData.value.adaptationId === null) {
|
|
576
|
+
this.trigger("adaptationChange", {
|
|
577
|
+
period,
|
|
578
|
+
adaptation: null,
|
|
579
|
+
type: msgData.value.type,
|
|
580
|
+
});
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
const adaptations = (_4 = period.adaptations[msgData.value.type]) !== null && _4 !== void 0 ? _4 : [];
|
|
584
|
+
const adaptation = arrayFind(adaptations, (a) => a.id === msgData.value.adaptationId);
|
|
585
|
+
if (adaptation !== undefined) {
|
|
586
|
+
this.trigger("adaptationChange", {
|
|
587
|
+
period,
|
|
588
|
+
adaptation,
|
|
589
|
+
type: msgData.value.type,
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
break;
|
|
593
|
+
}
|
|
594
|
+
case "representation-changed" /* CoreMessageType.RepresentationChanged */: {
|
|
595
|
+
if (((_5 = this._currentContentInfo) === null || _5 === void 0 ? void 0 : _5.contentId) !== msgData.contentId ||
|
|
596
|
+
this._currentContentInfo.manifest === null) {
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
const period = arrayFind(this._currentContentInfo.manifest.periods, (p) => p.id === msgData.value.periodId);
|
|
600
|
+
if (period === undefined) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
if (msgData.value.representationId === null) {
|
|
604
|
+
this.trigger("representationChange", {
|
|
605
|
+
period,
|
|
606
|
+
type: msgData.value.type,
|
|
607
|
+
representation: null,
|
|
608
|
+
});
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
const adaptations = (_6 = period.adaptations[msgData.value.type]) !== null && _6 !== void 0 ? _6 : [];
|
|
612
|
+
const adaptation = arrayFind(adaptations, (a) => a.id === msgData.value.adaptationId);
|
|
613
|
+
if (adaptation === undefined) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
const representation = arrayFind(adaptation.representations, (r) => r.id === msgData.value.representationId);
|
|
617
|
+
if (representation !== undefined) {
|
|
618
|
+
this.trigger("representationChange", {
|
|
619
|
+
period,
|
|
620
|
+
type: msgData.value.type,
|
|
621
|
+
representation,
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
case "encryption-data-encountered" /* CoreMessageType.EncryptionDataEncountered */:
|
|
627
|
+
if (((_7 = this._currentContentInfo) === null || _7 === void 0 ? void 0 : _7.contentId) !== msgData.contentId) {
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
lastContentProtection.setValue(msgData.value);
|
|
631
|
+
break;
|
|
632
|
+
case "manifest-ready" /* CoreMessageType.ManifestReady */: {
|
|
633
|
+
if (((_8 = this._currentContentInfo) === null || _8 === void 0 ? void 0 : _8.contentId) !== msgData.contentId) {
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
const manifest = msgData.value.manifest;
|
|
637
|
+
this._currentContentInfo.manifest = manifest;
|
|
638
|
+
this._updateCodecSupport(manifest, mediaElement);
|
|
639
|
+
this._startPlaybackIfReady(playbackStartParams);
|
|
640
|
+
break;
|
|
641
|
+
}
|
|
642
|
+
case "manifest-update" /* CoreMessageType.ManifestUpdate */: {
|
|
643
|
+
if (((_9 = this._currentContentInfo) === null || _9 === void 0 ? void 0 : _9.contentId) !== msgData.contentId) {
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
const manifest = (_10 = this._currentContentInfo) === null || _10 === void 0 ? void 0 : _10.manifest;
|
|
647
|
+
if (isNullOrUndefined(manifest)) {
|
|
648
|
+
log.error("Init", "Manifest update but no Manifest loaded");
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
replicateUpdatesOnManifestMetadata(manifest, msgData.value.manifest, msgData.value.updates);
|
|
652
|
+
(_12 = (_11 = this._currentContentInfo) === null || _11 === void 0 ? void 0 : _11.streamEventsEmitter) === null || _12 === void 0 ? void 0 : _12.onManifestUpdate(manifest);
|
|
653
|
+
this._updateCodecSupport(manifest, mediaElement);
|
|
654
|
+
this.trigger("manifestUpdate", msgData.value.updates);
|
|
655
|
+
break;
|
|
656
|
+
}
|
|
657
|
+
case "update-playback-rate" /* CoreMessageType.UpdatePlaybackRate */:
|
|
658
|
+
if (((_13 = this._currentContentInfo) === null || _13 === void 0 ? void 0 : _13.contentId) !== msgData.contentId) {
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
playbackObserver.setPlaybackRate(msgData.value);
|
|
662
|
+
break;
|
|
663
|
+
case "bitrate-estimate-change" /* CoreMessageType.BitrateEstimateChange */:
|
|
664
|
+
if (((_14 = this._currentContentInfo) === null || _14 === void 0 ? void 0 : _14.contentId) !== msgData.contentId) {
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
this.trigger("bitrateEstimateChange", {
|
|
668
|
+
type: msgData.value.bufferType,
|
|
669
|
+
bitrate: msgData.value.bitrate,
|
|
670
|
+
});
|
|
671
|
+
break;
|
|
672
|
+
case "inband-event" /* CoreMessageType.InbandEvent */:
|
|
673
|
+
if (((_15 = this._currentContentInfo) === null || _15 === void 0 ? void 0 : _15.contentId) !== msgData.contentId) {
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
this.trigger("inbandEvents", msgData.value);
|
|
677
|
+
break;
|
|
678
|
+
case "locked-stream" /* CoreMessageType.LockedStream */: {
|
|
679
|
+
if (((_16 = this._currentContentInfo) === null || _16 === void 0 ? void 0 : _16.contentId) !== msgData.contentId ||
|
|
680
|
+
this._currentContentInfo.manifest === null) {
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
const period = arrayFind(this._currentContentInfo.manifest.periods, (p) => p.id === msgData.value.periodId);
|
|
684
|
+
if (period === undefined) {
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
(_17 = this._currentContentInfo.rebufferingController) === null || _17 === void 0 ? void 0 : _17.onLockedStream(msgData.value.bufferType, period);
|
|
688
|
+
break;
|
|
689
|
+
}
|
|
690
|
+
case "period-stream-ready" /* CoreMessageType.PeriodStreamReady */: {
|
|
691
|
+
if (((_18 = this._currentContentInfo) === null || _18 === void 0 ? void 0 : _18.contentId) !== msgData.contentId ||
|
|
692
|
+
this._currentContentInfo.manifest === null) {
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
const period = arrayFind(this._currentContentInfo.manifest.periods, (p) => p.id === msgData.value.periodId);
|
|
696
|
+
if (period === undefined) {
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
const ref = new SharedReference(undefined);
|
|
700
|
+
ref.onUpdate((adapChoice) => {
|
|
701
|
+
if (this._currentContentInfo === null) {
|
|
702
|
+
ref.finish();
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
if (!isNullOrUndefined(adapChoice)) {
|
|
706
|
+
adapChoice.representations.onUpdate((repChoice, stopListening) => {
|
|
707
|
+
if (this._currentContentInfo === null) {
|
|
708
|
+
stopListening();
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
this._settings.coreInterface.sendMessage({
|
|
712
|
+
type: "rep-update" /* MainThreadMessageType.RepresentationUpdate */,
|
|
713
|
+
contentId: this._currentContentInfo.contentId,
|
|
714
|
+
value: {
|
|
715
|
+
periodId: msgData.value.periodId,
|
|
716
|
+
adaptationId: adapChoice.adaptationId,
|
|
717
|
+
bufferType: msgData.value.bufferType,
|
|
718
|
+
choice: repChoice,
|
|
719
|
+
},
|
|
230
720
|
});
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
721
|
+
}, { clearSignal: this._initCanceller.signal });
|
|
722
|
+
}
|
|
723
|
+
this._settings.coreInterface.sendMessage({
|
|
724
|
+
type: "track-update" /* MainThreadMessageType.TrackUpdate */,
|
|
725
|
+
contentId: this._currentContentInfo.contentId,
|
|
726
|
+
value: {
|
|
727
|
+
periodId: msgData.value.periodId,
|
|
728
|
+
bufferType: msgData.value.bufferType,
|
|
729
|
+
choice: isNullOrUndefined(adapChoice)
|
|
730
|
+
? adapChoice
|
|
731
|
+
: {
|
|
732
|
+
adaptationId: adapChoice.adaptationId,
|
|
733
|
+
switchingMode: adapChoice.switchingMode,
|
|
734
|
+
initialRepresentations: adapChoice.representations.getValue(),
|
|
735
|
+
relativeResumingPosition: adapChoice.relativeResumingPosition,
|
|
736
|
+
},
|
|
737
|
+
},
|
|
738
|
+
});
|
|
739
|
+
}, { clearSignal: this._initCanceller.signal });
|
|
740
|
+
this.trigger("periodStreamReady", {
|
|
741
|
+
period,
|
|
742
|
+
type: msgData.value.bufferType,
|
|
743
|
+
adaptationRef: ref,
|
|
744
|
+
});
|
|
745
|
+
break;
|
|
746
|
+
}
|
|
747
|
+
case "period-stream-cleared" /* CoreMessageType.PeriodStreamCleared */: {
|
|
748
|
+
if (((_19 = this._currentContentInfo) === null || _19 === void 0 ? void 0 : _19.contentId) !== msgData.contentId ||
|
|
749
|
+
this._currentContentInfo.manifest === null) {
|
|
750
|
+
return;
|
|
234
751
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
752
|
+
this.trigger("periodStreamCleared", {
|
|
753
|
+
periodId: msgData.value.periodId,
|
|
754
|
+
type: msgData.value.bufferType,
|
|
755
|
+
});
|
|
756
|
+
break;
|
|
757
|
+
}
|
|
758
|
+
case "discontinuity-update" /* CoreMessageType.DiscontinuityUpdate */: {
|
|
759
|
+
if (((_20 = this._currentContentInfo) === null || _20 === void 0 ? void 0 : _20.contentId) !== msgData.contentId ||
|
|
760
|
+
this._currentContentInfo.manifest === null) {
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
const period = arrayFind(this._currentContentInfo.manifest.periods, (p) => p.id === msgData.value.periodId);
|
|
764
|
+
if (period === undefined) {
|
|
765
|
+
log.warn("Init", "Discontinuity's Period not found", {
|
|
766
|
+
periodId: msgData.value.periodId,
|
|
240
767
|
});
|
|
241
768
|
return;
|
|
242
769
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
770
|
+
(_21 = this._currentContentInfo.rebufferingController) === null || _21 === void 0 ? void 0 : _21.updateDiscontinuityInfo({
|
|
771
|
+
period,
|
|
772
|
+
bufferType: msgData.value.bufferType,
|
|
773
|
+
discontinuity: msgData.value.discontinuity,
|
|
774
|
+
position: msgData.value.position,
|
|
775
|
+
});
|
|
776
|
+
break;
|
|
777
|
+
}
|
|
778
|
+
case "push-text-data" /* CoreMessageType.PushTextData */: {
|
|
779
|
+
if (((_22 = this._currentContentInfo) === null || _22 === void 0 ? void 0 : _22.contentId) !== msgData.contentId) {
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
if (textDisplayer === null) {
|
|
783
|
+
log.warn("text", "Received AddTextData message but no text displayer exists");
|
|
784
|
+
}
|
|
785
|
+
else {
|
|
786
|
+
try {
|
|
787
|
+
const ranges = textDisplayer.pushTextData(msgData.value);
|
|
788
|
+
this._settings.coreInterface.sendMessage({
|
|
789
|
+
type: "add-text-success" /* MainThreadMessageType.PushTextDataSuccess */,
|
|
790
|
+
contentId: msgData.contentId,
|
|
791
|
+
value: { ranges },
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
catch (err) {
|
|
795
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
796
|
+
this._settings.coreInterface.sendMessage({
|
|
797
|
+
type: "push-text-error" /* MainThreadMessageType.PushTextDataError */,
|
|
798
|
+
contentId: msgData.contentId,
|
|
799
|
+
value: { message },
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
break;
|
|
804
|
+
}
|
|
805
|
+
case "remove-text-data" /* CoreMessageType.RemoveTextData */: {
|
|
806
|
+
if (((_23 = this._currentContentInfo) === null || _23 === void 0 ? void 0 : _23.contentId) !== msgData.contentId) {
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
if (textDisplayer === null) {
|
|
810
|
+
log.warn("text", "Received RemoveTextData message but no text displayer exists");
|
|
811
|
+
}
|
|
812
|
+
else {
|
|
813
|
+
try {
|
|
814
|
+
const ranges = textDisplayer.removeBuffer(msgData.value.start, msgData.value.end);
|
|
815
|
+
this._settings.coreInterface.sendMessage({
|
|
816
|
+
type: "remove-text-success" /* MainThreadMessageType.RemoveTextDataSuccess */,
|
|
817
|
+
contentId: msgData.contentId,
|
|
818
|
+
value: { ranges },
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
catch (err) {
|
|
822
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
823
|
+
this._settings.coreInterface.sendMessage({
|
|
824
|
+
type: "remove-text-error" /* MainThreadMessageType.RemoveTextDataError */,
|
|
825
|
+
contentId: msgData.contentId,
|
|
826
|
+
value: { message },
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
break;
|
|
831
|
+
}
|
|
832
|
+
case "reset-text-displayer" /* CoreMessageType.ResetTextDisplayer */: {
|
|
833
|
+
if (((_24 = this._currentContentInfo) === null || _24 === void 0 ? void 0 : _24.contentId) !== msgData.contentId) {
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
if (textDisplayer === null) {
|
|
837
|
+
log.warn("text", "Received ResetTextDisplayer message but no text displayer exists");
|
|
838
|
+
}
|
|
839
|
+
else {
|
|
840
|
+
textDisplayer.reset();
|
|
841
|
+
}
|
|
842
|
+
break;
|
|
843
|
+
}
|
|
844
|
+
case "stop-text-displayer" /* CoreMessageType.StopTextDisplayer */: {
|
|
845
|
+
if (((_25 = this._currentContentInfo) === null || _25 === void 0 ? void 0 : _25.contentId) !== msgData.contentId) {
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
if (textDisplayer === null) {
|
|
849
|
+
log.warn("text", "Received StopTextDisplayer message but no text displayer exists");
|
|
850
|
+
}
|
|
851
|
+
else {
|
|
852
|
+
textDisplayer.stop();
|
|
853
|
+
}
|
|
854
|
+
break;
|
|
855
|
+
}
|
|
856
|
+
case "reloading-media-source" /* CoreMessageType.ReloadingMediaSource */:
|
|
857
|
+
{
|
|
858
|
+
if (this._currentContentInfo === null ||
|
|
859
|
+
this._currentContentInfo.mediaSourceInfo === null) {
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
const mediaSourceId = this._currentContentInfo.mediaSourceInfo.type === "main"
|
|
863
|
+
? this._currentContentInfo.mediaSourceInfo.mediaSource.id
|
|
864
|
+
: this._currentContentInfo.mediaSourceInfo.mediaSourceId;
|
|
865
|
+
if (mediaSourceId !== msgData.mediaSourceId) {
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
reloadMediaSource(msgData.value.timeOffset, msgData.value.minimumPosition, msgData.value.maximumPosition);
|
|
869
|
+
}
|
|
870
|
+
break;
|
|
871
|
+
case "needs-decipherability-flush" /* CoreMessageType.NeedsDecipherabilityFlush */:
|
|
872
|
+
{
|
|
873
|
+
if (((_26 = this._currentContentInfo) === null || _26 === void 0 ? void 0 : _26.contentId) !== msgData.contentId) {
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
const keySystem = getKeySystemConfiguration(mediaElement);
|
|
877
|
+
if (shouldReloadMediaSourceOnDecipherabilityUpdate(keySystem === null || keySystem === void 0 ? void 0 : keySystem[0])) {
|
|
878
|
+
notifyAndStartMediaSourceReload(0, undefined, undefined);
|
|
879
|
+
}
|
|
880
|
+
else {
|
|
881
|
+
const lastObservation = playbackObserver.getReference().getValue();
|
|
882
|
+
const currentPosition = lastObservation.position.getWanted();
|
|
883
|
+
// simple seek close to the current position
|
|
884
|
+
// to flush the buffers
|
|
885
|
+
if (currentPosition + 0.001 < lastObservation.duration) {
|
|
886
|
+
playbackObserver.setCurrentTime(mediaElement.currentTime + 0.001);
|
|
887
|
+
}
|
|
888
|
+
else {
|
|
889
|
+
playbackObserver.setCurrentTime(currentPosition);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
break;
|
|
894
|
+
case "segment-sink-store-update" /* CoreMessageType.SegmentSinkStoreUpdate */: {
|
|
895
|
+
if (((_27 = this._currentContentInfo) === null || _27 === void 0 ? void 0 : _27.contentId) !== msgData.contentId) {
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
const sinkObj = this._awaitingRequests.pendingSinkMetrics.get(msgData.value.requestId);
|
|
899
|
+
if (sinkObj !== undefined) {
|
|
900
|
+
sinkObj.resolve(msgData.value.segmentSinkMetrics);
|
|
901
|
+
}
|
|
902
|
+
else {
|
|
903
|
+
log.error("Init", "Failed to send segment sink store update");
|
|
904
|
+
}
|
|
905
|
+
break;
|
|
906
|
+
}
|
|
907
|
+
case "init-success" /* CoreMessageType.InitSuccess */:
|
|
908
|
+
case "init-error" /* CoreMessageType.InitError */:
|
|
909
|
+
// Should already be handled by the API
|
|
910
|
+
break;
|
|
911
|
+
case "log" /* CoreMessageType.LogMessage */:
|
|
912
|
+
// Already handled by prepare's handler
|
|
913
|
+
break;
|
|
914
|
+
case "thumbnail-response" /* CoreMessageType.ThumbnailDataResponse */: {
|
|
915
|
+
if (((_28 = this._currentContentInfo) === null || _28 === void 0 ? void 0 : _28.contentId) !== msgData.contentId) {
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
const tObj = this._awaitingRequests.pendingThumbnailFetching.get(msgData.value.requestId);
|
|
919
|
+
if (tObj !== undefined) {
|
|
920
|
+
if (msgData.value.status === "error") {
|
|
921
|
+
tObj.reject(formatCoreError(msgData.value.error));
|
|
922
|
+
}
|
|
923
|
+
else {
|
|
924
|
+
tObj.resolve(msgData.value.data);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
else {
|
|
928
|
+
log.error("Init", "Failed to send segment sink store update");
|
|
929
|
+
}
|
|
930
|
+
break;
|
|
931
|
+
}
|
|
932
|
+
default:
|
|
933
|
+
assertUnreachable(msgData);
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
log.debug("Init", "addEventListener for core message");
|
|
937
|
+
if (this._queuedCoreMessages !== null) {
|
|
938
|
+
const bufferedMessages = this._queuedCoreMessages.slice();
|
|
939
|
+
log.debug("Init", "Processing buffered messages", {
|
|
940
|
+
ammount: bufferedMessages.length,
|
|
941
|
+
});
|
|
942
|
+
for (const message of bufferedMessages) {
|
|
943
|
+
onmessage(message);
|
|
944
|
+
}
|
|
945
|
+
this._queuedCoreMessages = null;
|
|
946
|
+
}
|
|
947
|
+
this._settings.coreInterface.addMessageListener(onmessage);
|
|
948
|
+
this._initCanceller.signal.register(() => {
|
|
949
|
+
log.debug("Init", "removeEventListener for core message");
|
|
950
|
+
this._settings.coreInterface.removeMessageListener(onmessage);
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
dispose() {
|
|
954
|
+
var _a;
|
|
955
|
+
this._initCanceller.cancel();
|
|
956
|
+
if (this._currentContentInfo !== null) {
|
|
957
|
+
if (((_a = this._currentContentInfo.mediaSourceInfo) === null || _a === void 0 ? void 0 : _a.type) === "main") {
|
|
958
|
+
this._currentContentInfo.mediaSourceInfo.mediaSource.dispose();
|
|
959
|
+
}
|
|
960
|
+
this._currentContentInfo = null;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
_onFatalError(err) {
|
|
964
|
+
if (this._initCanceller.isUsed()) {
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
this._initCanceller.cancel();
|
|
968
|
+
this.trigger("error", err);
|
|
969
|
+
}
|
|
970
|
+
_initializeContentDecryption(mediaElement, lastContentProtection, mediaSourceStatus, reloadMediaSource, cancelSignal) {
|
|
971
|
+
var _a;
|
|
972
|
+
const { keySystems } = this._settings;
|
|
973
|
+
// TODO private?
|
|
974
|
+
const createEmeDisabledReference = (errMsg) => {
|
|
975
|
+
mediaSourceStatus.setValue(1 /* MediaSourceInitializationStatus.AttachNow */);
|
|
976
|
+
lastContentProtection.onUpdate((data, stopListening) => {
|
|
977
|
+
if (data === null) {
|
|
978
|
+
// initial value
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
stopListening();
|
|
982
|
+
const err = new EncryptedMediaError("MEDIA_IS_ENCRYPTED_ERROR", errMsg, {
|
|
983
|
+
keyStatuses: undefined,
|
|
984
|
+
keySystemConfiguration: undefined,
|
|
985
|
+
keySystem: undefined,
|
|
986
|
+
});
|
|
987
|
+
this._onFatalError(err);
|
|
988
|
+
}, { clearSignal: cancelSignal });
|
|
989
|
+
const ref = new SharedReference({
|
|
990
|
+
initializationState: {
|
|
991
|
+
type: "initialized",
|
|
992
|
+
value: null,
|
|
993
|
+
},
|
|
994
|
+
contentDecryptor: null,
|
|
995
|
+
drmSystemId: undefined,
|
|
996
|
+
});
|
|
997
|
+
ref.finish(); // We know that no new value will be triggered
|
|
998
|
+
return { statusRef: ref, contentDecryptor: null };
|
|
999
|
+
};
|
|
1000
|
+
if (keySystems.length === 0) {
|
|
1001
|
+
return createEmeDisabledReference("No `keySystems` option given.");
|
|
1002
|
+
}
|
|
1003
|
+
else if (features.decrypt === null) {
|
|
1004
|
+
return createEmeDisabledReference("EME feature not activated.");
|
|
1005
|
+
}
|
|
1006
|
+
const emeApi = (_a = mediaElement.FORCED_EME_API) !== null && _a !== void 0 ? _a : getEmeApiImplementation("auto");
|
|
1007
|
+
if (emeApi === null) {
|
|
1008
|
+
return createEmeDisabledReference("EME API not available on the current page.");
|
|
1009
|
+
}
|
|
1010
|
+
log.debug("Init", "Creating ContentDecryptor");
|
|
1011
|
+
const ContentDecryptor = features.decrypt;
|
|
1012
|
+
const contentDecryptor = new ContentDecryptor(emeApi, mediaElement, keySystems);
|
|
1013
|
+
const drmStatusRef = new SharedReference({
|
|
1014
|
+
initializationState: { type: "uninitialized", value: null },
|
|
1015
|
+
drmSystemId: undefined,
|
|
1016
|
+
}, cancelSignal);
|
|
1017
|
+
const updateCodecSupportOnStateChange = (state) => {
|
|
1018
|
+
var _a;
|
|
1019
|
+
if (state > ContentDecryptorState.Initializing) {
|
|
1020
|
+
const manifest = (_a = this._currentContentInfo) === null || _a === void 0 ? void 0 : _a.manifest;
|
|
1021
|
+
if (isNullOrUndefined(manifest)) {
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
this._updateCodecSupport(manifest, mediaElement);
|
|
1025
|
+
contentDecryptor.removeEventListener("stateChange", updateCodecSupportOnStateChange);
|
|
1026
|
+
}
|
|
1027
|
+
};
|
|
1028
|
+
contentDecryptor.addEventListener("stateChange", updateCodecSupportOnStateChange);
|
|
1029
|
+
contentDecryptor.addEventListener("keyIdsCompatibilityUpdate", (updates) => {
|
|
1030
|
+
if (this._currentContentInfo === null ||
|
|
1031
|
+
this._currentContentInfo.manifest === null) {
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
const manUpdates = updateDecipherabilityFromKeyIds(this._currentContentInfo.manifest, updates);
|
|
1035
|
+
if (mayMediaElementFailOnUndecipherableData() &&
|
|
1036
|
+
manUpdates.some((e) => e.representation.decipherable !== true)) {
|
|
1037
|
+
reloadMediaSource();
|
|
1038
|
+
}
|
|
1039
|
+
else {
|
|
1040
|
+
this._settings.coreInterface.sendMessage({
|
|
1041
|
+
type: "decipherability-update" /* MainThreadMessageType.DecipherabilityStatusUpdate */,
|
|
1042
|
+
contentId: this._currentContentInfo.contentId,
|
|
1043
|
+
value: manUpdates.map((s) => ({
|
|
1044
|
+
representationUniqueId: s.representation.uniqueId,
|
|
1045
|
+
decipherable: s.representation.decipherable,
|
|
1046
|
+
})),
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
this.trigger("decipherabilityUpdate", manUpdates);
|
|
1050
|
+
});
|
|
1051
|
+
contentDecryptor.addEventListener("blackListProtectionData", (protData) => {
|
|
1052
|
+
if (this._currentContentInfo === null ||
|
|
1053
|
+
this._currentContentInfo.manifest === null) {
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
const manUpdates = updateDecipherabilityFromProtectionData(this._currentContentInfo.manifest, protData);
|
|
1057
|
+
if (mayMediaElementFailOnUndecipherableData() &&
|
|
1058
|
+
manUpdates.some((e) => e.representation.decipherable !== true)) {
|
|
1059
|
+
reloadMediaSource();
|
|
1060
|
+
}
|
|
1061
|
+
else {
|
|
1062
|
+
this._settings.coreInterface.sendMessage({
|
|
1063
|
+
type: "decipherability-update" /* MainThreadMessageType.DecipherabilityStatusUpdate */,
|
|
1064
|
+
contentId: this._currentContentInfo.contentId,
|
|
1065
|
+
value: manUpdates.map((s) => ({
|
|
1066
|
+
representationUniqueId: s.representation.uniqueId,
|
|
1067
|
+
decipherable: s.representation.decipherable,
|
|
1068
|
+
})),
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
this.trigger("decipherabilityUpdate", manUpdates);
|
|
1072
|
+
});
|
|
1073
|
+
contentDecryptor.addEventListener("stateChange", (state) => {
|
|
1074
|
+
if (state === ContentDecryptorState.WaitingForAttachment) {
|
|
1075
|
+
mediaSourceStatus.onUpdate((currStatus, stopListening) => {
|
|
1076
|
+
if (currStatus === 0 /* MediaSourceInitializationStatus.Nothing */) {
|
|
1077
|
+
mediaSourceStatus.setValue(1 /* MediaSourceInitializationStatus.AttachNow */);
|
|
1078
|
+
}
|
|
1079
|
+
else if (currStatus === 2 /* MediaSourceInitializationStatus.Attached */) {
|
|
1080
|
+
stopListening();
|
|
1081
|
+
if (state === ContentDecryptorState.WaitingForAttachment) {
|
|
1082
|
+
contentDecryptor.attach();
|
|
1083
|
+
}
|
|
247
1084
|
}
|
|
248
|
-
|
|
1085
|
+
}, { clearSignal: cancelSignal, emitCurrentValue: true });
|
|
1086
|
+
}
|
|
1087
|
+
else if (state === ContentDecryptorState.ReadyForContent) {
|
|
1088
|
+
drmStatusRef.setValue({
|
|
1089
|
+
initializationState: { type: "initialized", value: null },
|
|
1090
|
+
drmSystemId: contentDecryptor.systemId,
|
|
249
1091
|
});
|
|
250
|
-
|
|
1092
|
+
contentDecryptor.removeEventListener("stateChange");
|
|
1093
|
+
}
|
|
1094
|
+
});
|
|
1095
|
+
contentDecryptor.addEventListener("error", (error) => {
|
|
1096
|
+
this._onFatalError(error);
|
|
1097
|
+
});
|
|
1098
|
+
contentDecryptor.addEventListener("warning", (error) => {
|
|
1099
|
+
this.trigger("warning", error);
|
|
251
1100
|
});
|
|
1101
|
+
lastContentProtection.onUpdate((data) => {
|
|
1102
|
+
if (data === null) {
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1105
|
+
contentDecryptor.onInitializationData(data);
|
|
1106
|
+
}, { clearSignal: cancelSignal });
|
|
1107
|
+
cancelSignal.register(() => {
|
|
1108
|
+
contentDecryptor.dispose();
|
|
1109
|
+
});
|
|
1110
|
+
return { statusRef: drmStatusRef, contentDecryptor };
|
|
252
1111
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
1112
|
+
/**
|
|
1113
|
+
* Retrieves all unknown codecs from the current manifest, checks these unknown codecs
|
|
1114
|
+
* to determine if they are supported, updates the manifest with the support
|
|
1115
|
+
* status of these codecs, and forwards the list of supported codecs to core.
|
|
1116
|
+
* @param manifest
|
|
1117
|
+
*/
|
|
1118
|
+
_updateCodecSupport(manifest, mediaElement) {
|
|
1119
|
+
var _a, _b, _c, _d;
|
|
259
1120
|
try {
|
|
260
|
-
manifest = (_a = this.
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
1121
|
+
const updatedCodecs = updateManifestCodecSupport(manifest, (_b = (_a = this._currentContentInfo) === null || _a === void 0 ? void 0 : _a.contentDecryptor) !== null && _b !== void 0 ? _b : null, mediaElement, (_d = (_c = this._currentContentInfo) === null || _c === void 0 ? void 0 : _c.useMseInWorker) !== null && _d !== void 0 ? _d : false);
|
|
1122
|
+
if (updatedCodecs.length > 0) {
|
|
1123
|
+
this._settings.coreInterface.sendMessage({
|
|
1124
|
+
type: "codec-support-update" /* MainThreadMessageType.CodecSupportUpdate */,
|
|
1125
|
+
value: updatedCodecs,
|
|
1126
|
+
});
|
|
1127
|
+
// TODO what if one day the core updates codec support by itself?
|
|
1128
|
+
// We wouldn't know...
|
|
1129
|
+
this.trigger("codecSupportUpdate", null);
|
|
1130
|
+
}
|
|
264
1131
|
}
|
|
265
|
-
|
|
266
|
-
this.
|
|
267
|
-
this._refreshManifestCodecSupport(manifest, mediaElement);
|
|
268
|
-
}, initCanceller.signal);
|
|
269
|
-
manifest.addEventListener("decipherabilityUpdate", (elts) => {
|
|
270
|
-
this.trigger("decipherabilityUpdate", elts);
|
|
271
|
-
}, initCanceller.signal);
|
|
272
|
-
manifest.addEventListener("supportUpdate", () => {
|
|
273
|
-
this.trigger("codecSupportUpdate", null);
|
|
274
|
-
}, initCanceller.signal);
|
|
275
|
-
log.debug("Init", "Calculating initial time");
|
|
276
|
-
const initialTime = getInitialTime(manifest, lowLatencyMode, startAt);
|
|
277
|
-
log.debug("Init", "Initial time calculated", { initialTime });
|
|
278
|
-
/** Choose the right "Representation" for a given "Adaptation". */
|
|
279
|
-
const representationEstimator = AdaptiveRepresentationSelector(adaptiveOptions);
|
|
280
|
-
const subBufferOptions = objectAssign({ textTrackOptions, drmSystemId }, bufferOptions);
|
|
281
|
-
const cdnPrioritizer = new CdnPrioritizer(initCanceller.signal);
|
|
282
|
-
const segmentQueueCreator = new SegmentQueueCreator(transport, cdnPrioritizer, this._cmcdDataBuilder, segmentRequestOptions);
|
|
283
|
-
this._refreshManifestCodecSupport(manifest, mediaElement);
|
|
284
|
-
this.trigger("manifestReady", manifest);
|
|
285
|
-
if (initCanceller.isUsed()) {
|
|
286
|
-
return;
|
|
1132
|
+
catch (err) {
|
|
1133
|
+
this._onFatalError(err);
|
|
287
1134
|
}
|
|
288
|
-
// handle initial load and reloads
|
|
289
|
-
this._setupContentWithNewMediaSource({
|
|
290
|
-
mediaElement,
|
|
291
|
-
playbackObserver,
|
|
292
|
-
mediaSource: initialMediaSource,
|
|
293
|
-
initialTime,
|
|
294
|
-
autoPlay,
|
|
295
|
-
manifest,
|
|
296
|
-
representationEstimator,
|
|
297
|
-
cdnPrioritizer,
|
|
298
|
-
segmentQueueCreator,
|
|
299
|
-
speed,
|
|
300
|
-
bufferOptions: subBufferOptions,
|
|
301
|
-
}, initialMediaSourceCanceller);
|
|
302
1135
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
* wanted.
|
|
308
|
-
* @param {Object} args
|
|
309
|
-
* @param {Object} currentCanceller
|
|
310
|
-
*/
|
|
311
|
-
_setupContentWithNewMediaSource(args, currentCanceller) {
|
|
312
|
-
this._startLoadingContentOnMediaSource(args, this._createReloadMediaSourceCallback(args, currentCanceller), currentCanceller.signal);
|
|
1136
|
+
_hasTextBufferFeature() {
|
|
1137
|
+
return ((this._settings.textTrackOptions.textTrackMode === "html" &&
|
|
1138
|
+
features.htmlTextDisplayer !== null) ||
|
|
1139
|
+
features.nativeTextDisplayer !== null);
|
|
313
1140
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
currentCanceller.cancel();
|
|
323
|
-
if (initCanceller.isUsed()) {
|
|
1141
|
+
_reload(mediaElement, textDisplayer, playbackObserver, mediaSourceStatus, position, autoPlay) {
|
|
1142
|
+
this._currentMediaSourceCanceller.cancel();
|
|
1143
|
+
this._currentMediaSourceCanceller = new TaskCanceller();
|
|
1144
|
+
this._currentMediaSourceCanceller.linkToSignal(this._initCanceller.signal);
|
|
1145
|
+
mediaSourceStatus.setValue(1 /* MediaSourceInitializationStatus.AttachNow */);
|
|
1146
|
+
this.trigger("reloadingMediaSource", { position, autoPlay });
|
|
1147
|
+
mediaSourceStatus.onUpdate((status, stopListeningMSStatusUpdates) => {
|
|
1148
|
+
if (status !== 2 /* MediaSourceInitializationStatus.Attached */) {
|
|
324
1149
|
return;
|
|
325
1150
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
1151
|
+
stopListeningMSStatusUpdates();
|
|
1152
|
+
const corePlaybackObserver = this._setUpModulesOnNewMediaSource({
|
|
1153
|
+
initialTime: position,
|
|
1154
|
+
autoPlay,
|
|
1155
|
+
mediaElement,
|
|
1156
|
+
textDisplayer,
|
|
1157
|
+
playbackObserver,
|
|
1158
|
+
}, this._currentMediaSourceCanceller.signal);
|
|
1159
|
+
if (!this._currentMediaSourceCanceller.isUsed() &&
|
|
1160
|
+
corePlaybackObserver !== null &&
|
|
1161
|
+
this._currentContentInfo !== null) {
|
|
1162
|
+
const contentId = this._currentContentInfo.contentId;
|
|
1163
|
+
corePlaybackObserver.listen((obs) => {
|
|
1164
|
+
this._settings.coreInterface.sendMessage({
|
|
1165
|
+
type: "observation" /* MainThreadMessageType.PlaybackObservation */,
|
|
1166
|
+
contentId,
|
|
1167
|
+
value: objectAssign(obs, {
|
|
1168
|
+
position: obs.position.serialize(),
|
|
1169
|
+
}),
|
|
1170
|
+
});
|
|
1171
|
+
}, {
|
|
1172
|
+
includeLastObservation: true,
|
|
1173
|
+
clearSignal: this._currentMediaSourceCanceller.signal,
|
|
1174
|
+
});
|
|
329
1175
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
this._setupContentWithNewMediaSource(Object.assign(Object.assign({}, args), { mediaSource: newMediaSource, initialTime: reloadOrder.position, autoPlay: reloadOrder.autoPlay }), newCanceller);
|
|
335
|
-
})
|
|
336
|
-
.catch((err) => {
|
|
337
|
-
if (newCanceller.isUsed()) {
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
this._onFatalError(err);
|
|
341
|
-
});
|
|
342
|
-
};
|
|
1176
|
+
}, {
|
|
1177
|
+
clearSignal: this._currentMediaSourceCanceller.signal,
|
|
1178
|
+
emitCurrentValue: true,
|
|
1179
|
+
});
|
|
343
1180
|
}
|
|
344
1181
|
/**
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
1182
|
+
* Start-up modules and mechanisms (initial seek, auto-play etc.) needed each
|
|
1183
|
+
* time a content is loaded AND re-loaded on a `HTMLMediaElement`, when the
|
|
1184
|
+
* manifest is known.
|
|
1185
|
+
*
|
|
1186
|
+
* Note that this does not include reacting to incoming core messages nor
|
|
1187
|
+
* sending them, those actions have to be handled separately.
|
|
1188
|
+
*
|
|
1189
|
+
* @param {Object} parameters
|
|
348
1190
|
* @param {Object} cancelSignal
|
|
1191
|
+
* @returns {Object|null} - Playback Observer created for this content. `null`
|
|
1192
|
+
* only if playback initialization failed (most likely because it has been
|
|
1193
|
+
* cancelled).
|
|
349
1194
|
*/
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const { transport } = this._initSettings;
|
|
354
|
-
const initialPeriod = (_a = manifest.getPeriodForTime(initialTime)) !== null && _a !== void 0 ? _a : manifest.getNextPeriod(initialTime);
|
|
355
|
-
if (initialPeriod === undefined) {
|
|
356
|
-
const error = new MediaError("MEDIA_STARTING_TIME_NOT_FOUND", "Wanted starting time not found in the Manifest.");
|
|
357
|
-
return this._onFatalError(error);
|
|
1195
|
+
_setUpModulesOnNewMediaSource(parameters, cancelSignal) {
|
|
1196
|
+
if (cancelSignal.isCancelled()) {
|
|
1197
|
+
return null;
|
|
358
1198
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
const sender = new MainThreadTextDisplayerInterface(textDisplayer);
|
|
363
|
-
textDisplayerInterface = sender;
|
|
364
|
-
cancelSignal.register(() => {
|
|
365
|
-
sender.stop();
|
|
366
|
-
textDisplayer === null || textDisplayer === void 0 ? void 0 : textDisplayer.stop();
|
|
367
|
-
});
|
|
1199
|
+
if (this._currentContentInfo === null) {
|
|
1200
|
+
log.error("Init", "Setting up modules without a contentId");
|
|
1201
|
+
return null;
|
|
368
1202
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
}
|
|
1203
|
+
if (this._currentContentInfo.manifest === null) {
|
|
1204
|
+
log.error("Init", "Setting up modules without a loaded Manifest");
|
|
1205
|
+
return null;
|
|
1206
|
+
}
|
|
1207
|
+
const { manifest, mediaSourceInfo } = this._currentContentInfo;
|
|
1208
|
+
const { speed } = this._settings;
|
|
1209
|
+
const { initialTime, autoPlay, mediaElement, textDisplayer, playbackObserver } = parameters;
|
|
1210
|
+
this._currentContentInfo.initialTime = initialTime;
|
|
1211
|
+
this._currentContentInfo.autoPlay = autoPlay;
|
|
374
1212
|
const { autoPlayResult, initialPlayPerformed } = performInitialSeekAndPlay({
|
|
375
1213
|
mediaElement,
|
|
376
1214
|
playbackObserver,
|
|
377
1215
|
startTime: initialTime,
|
|
378
1216
|
mustAutoPlay: autoPlay,
|
|
379
|
-
onWarning: (err) =>
|
|
380
|
-
this.trigger("warning", err);
|
|
381
|
-
},
|
|
1217
|
+
onWarning: (err) => this.trigger("warning", err),
|
|
382
1218
|
isDirectfile: false,
|
|
383
1219
|
}, cancelSignal);
|
|
1220
|
+
this._currentContentInfo.initialPlayPerformed = initialPlayPerformed;
|
|
1221
|
+
const corePlaybackObserver = createCorePlaybackObserver(playbackObserver, {
|
|
1222
|
+
autoPlay,
|
|
1223
|
+
initialPlayPerformed,
|
|
1224
|
+
manifest,
|
|
1225
|
+
mediaSource: (mediaSourceInfo === null || mediaSourceInfo === void 0 ? void 0 : mediaSourceInfo.type) === "main" ? mediaSourceInfo.mediaSource : null,
|
|
1226
|
+
speed,
|
|
1227
|
+
textDisplayer,
|
|
1228
|
+
}, cancelSignal);
|
|
384
1229
|
if (cancelSignal.isCancelled()) {
|
|
385
|
-
return;
|
|
1230
|
+
return null;
|
|
386
1231
|
}
|
|
1232
|
+
/**
|
|
1233
|
+
* Class trying to avoid various stalling situations, emitting "stalled"
|
|
1234
|
+
* events when it cannot, as well as "unstalled" events when it get out of one.
|
|
1235
|
+
*/
|
|
1236
|
+
const rebufferingController = new RebufferingController(playbackObserver, manifest, speed);
|
|
1237
|
+
rebufferingController.addEventListener("stalled", (evt) => this.trigger("stalled", evt));
|
|
1238
|
+
rebufferingController.addEventListener("unstalled", () => this.trigger("unstalled", null));
|
|
1239
|
+
rebufferingController.addEventListener("warning", (err) => this.trigger("warning", err));
|
|
1240
|
+
cancelSignal.register(() => {
|
|
1241
|
+
rebufferingController.destroy();
|
|
1242
|
+
});
|
|
1243
|
+
rebufferingController.start();
|
|
1244
|
+
this._currentContentInfo.rebufferingController = rebufferingController;
|
|
1245
|
+
const currentContentInfo = this._currentContentInfo;
|
|
387
1246
|
initialPlayPerformed.onUpdate((isPerformed, stopListening) => {
|
|
388
1247
|
if (isPerformed) {
|
|
389
1248
|
stopListening();
|
|
390
1249
|
const streamEventsEmitter = new StreamEventsEmitter(manifest, playbackObserver);
|
|
391
|
-
|
|
392
|
-
streamEventsEmitter.onManifestUpdate(manifest);
|
|
393
|
-
}, cancelSignal);
|
|
1250
|
+
currentContentInfo.streamEventsEmitter = streamEventsEmitter;
|
|
394
1251
|
streamEventsEmitter.addEventListener("event", (payload) => {
|
|
395
1252
|
this.trigger("streamEvent", payload);
|
|
396
1253
|
}, cancelSignal);
|
|
@@ -403,59 +1260,62 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
403
1260
|
});
|
|
404
1261
|
}
|
|
405
1262
|
}, { clearSignal: cancelSignal, emitCurrentValue: true });
|
|
406
|
-
const
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
if (freezeResolution === null) {
|
|
433
|
-
return;
|
|
1263
|
+
const _getSegmentSinkMetrics = async () => {
|
|
1264
|
+
this._awaitingRequests.nextRequestId++;
|
|
1265
|
+
const requestId = this._awaitingRequests.nextRequestId;
|
|
1266
|
+
this._settings.coreInterface.sendMessage({
|
|
1267
|
+
type: "pull-segment-sink-store-infos" /* MainThreadMessageType.PullSegmentSinkStoreInfos */,
|
|
1268
|
+
value: { requestId },
|
|
1269
|
+
});
|
|
1270
|
+
return new Promise((resolve, reject) => {
|
|
1271
|
+
const rejectFn = (err) => {
|
|
1272
|
+
cancelSignal.deregister(rejectFn);
|
|
1273
|
+
this._awaitingRequests.pendingSinkMetrics.delete(requestId);
|
|
1274
|
+
return reject(err);
|
|
1275
|
+
};
|
|
1276
|
+
this._awaitingRequests.pendingSinkMetrics.set(requestId, {
|
|
1277
|
+
resolve: (value) => {
|
|
1278
|
+
cancelSignal.deregister(rejectFn);
|
|
1279
|
+
this._awaitingRequests.pendingSinkMetrics.delete(requestId);
|
|
1280
|
+
resolve(value);
|
|
1281
|
+
},
|
|
1282
|
+
});
|
|
1283
|
+
cancelSignal.register(rejectFn);
|
|
1284
|
+
});
|
|
1285
|
+
};
|
|
1286
|
+
const _getThumbnailsData = async (periodId, thumbnailTrackId, time) => {
|
|
1287
|
+
if (this._currentContentInfo === null) {
|
|
1288
|
+
return Promise.reject(new Error("Cannot fetch thumbnails: No content loaded."));
|
|
434
1289
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
? lastObservation.position.getWanted()
|
|
442
|
-
: ((_a = coreObserver.getCurrentTime()) !== null && _a !== void 0 ? _a : lastObservation.position.getPolled());
|
|
443
|
-
const autoplay = initialPlayPerformed.getValue()
|
|
444
|
-
? !playbackObserver.getIsPaused()
|
|
445
|
-
: autoPlay;
|
|
446
|
-
onReloadOrder({ position, autoPlay: autoplay });
|
|
447
|
-
};
|
|
448
|
-
handleFreezeResolution(freezeResolution, {
|
|
449
|
-
enableRepresentationAvoidance: this._initSettings.enableRepresentationAvoidance,
|
|
450
|
-
manifest,
|
|
451
|
-
triggerReload,
|
|
452
|
-
playbackObserver,
|
|
1290
|
+
this._awaitingRequests.nextRequestId++;
|
|
1291
|
+
const requestId = this._awaitingRequests.nextRequestId;
|
|
1292
|
+
this._settings.coreInterface.sendMessage({
|
|
1293
|
+
type: "thumbnail-request" /* MainThreadMessageType.ThumbnailDataRequest */,
|
|
1294
|
+
contentId: this._currentContentInfo.contentId,
|
|
1295
|
+
value: { requestId, periodId, thumbnailTrackId, time },
|
|
453
1296
|
});
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
1297
|
+
return new Promise((resolve, reject) => {
|
|
1298
|
+
const rejectFn = (err) => {
|
|
1299
|
+
cleanUp();
|
|
1300
|
+
reject(err);
|
|
1301
|
+
};
|
|
1302
|
+
const cleanUp = () => {
|
|
1303
|
+
cancelSignal.deregister(rejectFn);
|
|
1304
|
+
this._awaitingRequests.pendingThumbnailFetching.delete(requestId);
|
|
1305
|
+
};
|
|
1306
|
+
this._awaitingRequests.pendingThumbnailFetching.set(requestId, {
|
|
1307
|
+
resolve: (value) => {
|
|
1308
|
+
cleanUp();
|
|
1309
|
+
resolve(value);
|
|
1310
|
+
},
|
|
1311
|
+
reject: (value) => {
|
|
1312
|
+
cleanUp();
|
|
1313
|
+
reject(value);
|
|
1314
|
+
},
|
|
1315
|
+
});
|
|
1316
|
+
cancelSignal.register(rejectFn);
|
|
1317
|
+
});
|
|
1318
|
+
};
|
|
459
1319
|
/**
|
|
460
1320
|
* Emit a "loaded" events once the initial play has been performed and the
|
|
461
1321
|
* media can begin playback.
|
|
@@ -465,452 +1325,237 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
465
1325
|
.then(() => {
|
|
466
1326
|
getLoadedReference(playbackObserver, false, cancelSignal).onUpdate((isLoaded, stopListening) => {
|
|
467
1327
|
if (isLoaded) {
|
|
468
|
-
const fetchThumbnails = createThumbnailFetcher(transport.thumbnails, cdnPrioritizer);
|
|
469
1328
|
stopListening();
|
|
470
1329
|
this.trigger("loaded", {
|
|
471
|
-
getSegmentSinkMetrics:
|
|
472
|
-
|
|
473
|
-
},
|
|
474
|
-
getThumbnailData: async (periodId, thumbnailTrackId, time) => {
|
|
475
|
-
return getThumbnailData(fetchThumbnails, manifest, periodId, thumbnailTrackId, time);
|
|
476
|
-
},
|
|
1330
|
+
getSegmentSinkMetrics: _getSegmentSinkMetrics,
|
|
1331
|
+
getThumbnailData: _getThumbnailsData,
|
|
477
1332
|
});
|
|
478
1333
|
}
|
|
479
1334
|
}, { emitCurrentValue: true, clearSignal: cancelSignal });
|
|
480
1335
|
})
|
|
481
1336
|
.catch((err) => {
|
|
482
1337
|
if (cancelSignal.isCancelled()) {
|
|
483
|
-
return;
|
|
1338
|
+
return;
|
|
484
1339
|
}
|
|
485
1340
|
this._onFatalError(err);
|
|
486
1341
|
});
|
|
487
|
-
|
|
488
|
-
const self = this;
|
|
489
|
-
StreamOrchestrator({ manifest, initialPeriod }, coreObserver, representationEstimator, segmentSinksStore, segmentQueueCreator, bufferOptions, handleStreamOrchestratorCallbacks(), cancelSignal);
|
|
490
|
-
/**
|
|
491
|
-
* Returns Object handling the callbacks from a `StreamOrchestrator`, which
|
|
492
|
-
* are basically how it communicates about events.
|
|
493
|
-
* @returns {Object}
|
|
494
|
-
*/
|
|
495
|
-
function handleStreamOrchestratorCallbacks() {
|
|
496
|
-
return {
|
|
497
|
-
needsBufferFlush: (payload) => {
|
|
498
|
-
var _a;
|
|
499
|
-
let wantedSeekingTime;
|
|
500
|
-
const lastObservation = playbackObserver.getReference().getValue();
|
|
501
|
-
const currentTime = lastObservation.position.isAwaitingFuturePosition()
|
|
502
|
-
? lastObservation.position.getWanted()
|
|
503
|
-
: mediaElement.currentTime;
|
|
504
|
-
const relativeResumingPosition = (_a = payload === null || payload === void 0 ? void 0 : payload.relativeResumingPosition) !== null && _a !== void 0 ? _a : 0;
|
|
505
|
-
const canBeApproximateSeek = Boolean(payload === null || payload === void 0 ? void 0 : payload.relativePosHasBeenDefaulted);
|
|
506
|
-
if (relativeResumingPosition === 0 && canBeApproximateSeek) {
|
|
507
|
-
// in case relativeResumingPosition is 0, we still perform
|
|
508
|
-
// a tiny seek to be sure that the browser will correclty reload the video.
|
|
509
|
-
wantedSeekingTime = currentTime + 0.001;
|
|
510
|
-
}
|
|
511
|
-
else {
|
|
512
|
-
wantedSeekingTime = currentTime + relativeResumingPosition;
|
|
513
|
-
}
|
|
514
|
-
playbackObserver.setCurrentTime(wantedSeekingTime);
|
|
515
|
-
// Seek again once data begins to be buffered.
|
|
516
|
-
// This is sadly necessary on some browsers to avoid decoding
|
|
517
|
-
// issues after a flush.
|
|
518
|
-
//
|
|
519
|
-
// NOTE: there's in theory a potential race condition in the following
|
|
520
|
-
// logic as the callback could be called when media data is still
|
|
521
|
-
// being removed by the browser - which is an asynchronous process.
|
|
522
|
-
// The following condition checking for buffered data could thus lead
|
|
523
|
-
// to a false positive where we're actually checking previous data.
|
|
524
|
-
// For now, such scenario is avoided by setting the
|
|
525
|
-
// `includeLastObservation` option to `false` and calling
|
|
526
|
-
// `needsBufferFlush` once MSE media removal operations have been
|
|
527
|
-
// explicitely validated by the browser, but that's a complex and easy
|
|
528
|
-
// to break system.
|
|
529
|
-
playbackObserver.listen((obs, stopListening) => {
|
|
530
|
-
if (
|
|
531
|
-
// Data is buffered around the current position
|
|
532
|
-
obs.currentRange !== null ||
|
|
533
|
-
// Or, for whatever reason, we have no buffer but we're already advancing
|
|
534
|
-
obs.position.getPolled() > wantedSeekingTime + 0.1) {
|
|
535
|
-
stopListening();
|
|
536
|
-
playbackObserver.setCurrentTime(obs.position.getWanted() + 0.001);
|
|
537
|
-
}
|
|
538
|
-
}, { includeLastObservation: false, clearSignal: cancelSignal });
|
|
539
|
-
},
|
|
540
|
-
streamStatusUpdate(value) {
|
|
541
|
-
// Announce discontinuities if found
|
|
542
|
-
const { period, bufferType, imminentDiscontinuity, position } = value;
|
|
543
|
-
rebufferingController.updateDiscontinuityInfo({
|
|
544
|
-
period,
|
|
545
|
-
bufferType,
|
|
546
|
-
discontinuity: imminentDiscontinuity,
|
|
547
|
-
position,
|
|
548
|
-
});
|
|
549
|
-
if (cancelSignal.isCancelled()) {
|
|
550
|
-
return; // Previous call has stopped streams due to a side-effect
|
|
551
|
-
}
|
|
552
|
-
// If the status for the last Period indicates that segments are all loaded
|
|
553
|
-
// or on the contrary that the loading resumed, announce it to the
|
|
554
|
-
// ContentTimeBoundariesObserver.
|
|
555
|
-
if (manifest.isLastPeriodKnown &&
|
|
556
|
-
value.period.id === manifest.periods[manifest.periods.length - 1].id) {
|
|
557
|
-
const hasFinishedLoadingLastPeriod = value.hasFinishedLoading || value.isEmptyStream;
|
|
558
|
-
if (hasFinishedLoadingLastPeriod) {
|
|
559
|
-
contentTimeBoundariesObserver.onLastSegmentFinishedLoading(value.bufferType);
|
|
560
|
-
}
|
|
561
|
-
else {
|
|
562
|
-
contentTimeBoundariesObserver.onLastSegmentLoadingResume(value.bufferType);
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
},
|
|
566
|
-
needsManifestRefresh: () => self._manifestFetcher.scheduleManualRefresh({
|
|
567
|
-
enablePartialRefresh: true,
|
|
568
|
-
canUseUnsafeMode: true,
|
|
569
|
-
}),
|
|
570
|
-
manifestMightBeOufOfSync: () => {
|
|
571
|
-
const { OUT_OF_SYNC_MANIFEST_REFRESH_DELAY } = config.getCurrent();
|
|
572
|
-
self._manifestFetcher.scheduleManualRefresh({
|
|
573
|
-
enablePartialRefresh: false,
|
|
574
|
-
canUseUnsafeMode: false,
|
|
575
|
-
delay: OUT_OF_SYNC_MANIFEST_REFRESH_DELAY,
|
|
576
|
-
});
|
|
577
|
-
},
|
|
578
|
-
lockedStream: (value) => rebufferingController.onLockedStream(value.bufferType, value.period),
|
|
579
|
-
adaptationChange: (value) => {
|
|
580
|
-
self.trigger("adaptationChange", value);
|
|
581
|
-
if (cancelSignal.isCancelled()) {
|
|
582
|
-
return; // Previous call has stopped streams due to a side-effect
|
|
583
|
-
}
|
|
584
|
-
contentTimeBoundariesObserver.onAdaptationChange(value.type, value.period, value.adaptation);
|
|
585
|
-
},
|
|
586
|
-
representationChange: (value) => {
|
|
587
|
-
self.trigger("representationChange", value);
|
|
588
|
-
if (cancelSignal.isCancelled()) {
|
|
589
|
-
return; // Previous call has stopped streams due to a side-effect
|
|
590
|
-
}
|
|
591
|
-
contentTimeBoundariesObserver.onRepresentationChange(value.type, value.period);
|
|
592
|
-
},
|
|
593
|
-
inbandEvent: (value) => self.trigger("inbandEvents", value),
|
|
594
|
-
warning: (value) => self.trigger("warning", value),
|
|
595
|
-
periodStreamReady: (value) => self.trigger("periodStreamReady", value),
|
|
596
|
-
periodStreamCleared: (value) => {
|
|
597
|
-
contentTimeBoundariesObserver.onPeriodCleared(value.type, value.period);
|
|
598
|
-
if (cancelSignal.isCancelled()) {
|
|
599
|
-
return; // Previous call has stopped streams due to a side-effect
|
|
600
|
-
}
|
|
601
|
-
self.trigger("periodStreamCleared", {
|
|
602
|
-
type: value.type,
|
|
603
|
-
periodId: value.period.id,
|
|
604
|
-
});
|
|
605
|
-
},
|
|
606
|
-
bitrateEstimateChange: (value) => {
|
|
607
|
-
var _a;
|
|
608
|
-
(_a = self._cmcdDataBuilder) === null || _a === void 0 ? void 0 : _a.updateThroughput(value.type, value.bitrate);
|
|
609
|
-
self.trigger("bitrateEstimateChange", value);
|
|
610
|
-
},
|
|
611
|
-
needsMediaSourceReload: (payload) => {
|
|
612
|
-
reloadMediaSource(payload.timeOffset, payload.minimumPosition, payload.maximumPosition);
|
|
613
|
-
},
|
|
614
|
-
needsDecipherabilityFlush() {
|
|
615
|
-
var _a, _b, _c, _d;
|
|
616
|
-
const keySystem = getKeySystemConfiguration(mediaElement);
|
|
617
|
-
if (shouldReloadMediaSourceOnDecipherabilityUpdate(keySystem === null || keySystem === void 0 ? void 0 : keySystem[0])) {
|
|
618
|
-
const lastObservation = coreObserver.getReference().getValue();
|
|
619
|
-
const position = lastObservation.position.isAwaitingFuturePosition()
|
|
620
|
-
? lastObservation.position.getWanted()
|
|
621
|
-
: ((_a = coreObserver.getCurrentTime()) !== null && _a !== void 0 ? _a : lastObservation.position.getPolled());
|
|
622
|
-
const isPaused = (_c = (_b = lastObservation.paused.pending) !== null && _b !== void 0 ? _b : coreObserver.getIsPaused()) !== null && _c !== void 0 ? _c : lastObservation.paused.last;
|
|
623
|
-
onReloadOrder({ position, autoPlay: !isPaused });
|
|
624
|
-
}
|
|
625
|
-
else {
|
|
626
|
-
const lastObservation = coreObserver.getReference().getValue();
|
|
627
|
-
const position = lastObservation.position.isAwaitingFuturePosition()
|
|
628
|
-
? lastObservation.position.getWanted()
|
|
629
|
-
: ((_d = coreObserver.getCurrentTime()) !== null && _d !== void 0 ? _d : lastObservation.position.getPolled());
|
|
630
|
-
// simple seek close to the current position
|
|
631
|
-
// to flush the buffers
|
|
632
|
-
if (position + 0.001 < lastObservation.duration) {
|
|
633
|
-
playbackObserver.setCurrentTime(mediaElement.currentTime + 0.001);
|
|
634
|
-
}
|
|
635
|
-
else {
|
|
636
|
-
playbackObserver.setCurrentTime(position);
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
},
|
|
640
|
-
encryptionDataEncountered: (value) => {
|
|
641
|
-
if (self._decryptionCapabilities.status === "disabled") {
|
|
642
|
-
self._onFatalError(self._decryptionCapabilities.value);
|
|
643
|
-
return;
|
|
644
|
-
}
|
|
645
|
-
else if (self._decryptionCapabilities.status === "uninitialized") {
|
|
646
|
-
// Should never happen
|
|
647
|
-
log.error("Init", "received encryption data without known decryption capabilities");
|
|
648
|
-
return;
|
|
649
|
-
}
|
|
650
|
-
for (const protectionData of value) {
|
|
651
|
-
self._decryptionCapabilities.value.onInitializationData(protectionData);
|
|
652
|
-
if (cancelSignal.isCancelled()) {
|
|
653
|
-
return; // Previous call has stopped streams due to a side-effect
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
},
|
|
657
|
-
error: (err) => self._onFatalError(err),
|
|
658
|
-
};
|
|
659
|
-
}
|
|
660
|
-
/**
|
|
661
|
-
* Callback allowing to reload the current content.
|
|
662
|
-
* @param {number} deltaPosition - Position you want to seek to after
|
|
663
|
-
* reloading, as a delta in seconds from the last polled playing position.
|
|
664
|
-
* @param {number|undefined} minimumPosition - If set, minimum time bound
|
|
665
|
-
* in seconds after `deltaPosition` has been applied.
|
|
666
|
-
* @param {number|undefined} maximumPosition - If set, minimum time bound
|
|
667
|
-
* in seconds after `deltaPosition` has been applied.
|
|
668
|
-
*/
|
|
669
|
-
function reloadMediaSource(deltaPosition, minimumPosition, maximumPosition) {
|
|
670
|
-
var _a, _b, _c;
|
|
671
|
-
const lastObservation = coreObserver.getReference().getValue();
|
|
672
|
-
const currentPosition = lastObservation.position.isAwaitingFuturePosition()
|
|
673
|
-
? lastObservation.position.getWanted()
|
|
674
|
-
: ((_a = coreObserver.getCurrentTime()) !== null && _a !== void 0 ? _a : lastObservation.position.getPolled());
|
|
675
|
-
const isPaused = (_c = (_b = lastObservation.paused.pending) !== null && _b !== void 0 ? _b : coreObserver.getIsPaused()) !== null && _c !== void 0 ? _c : lastObservation.paused.last;
|
|
676
|
-
let position = currentPosition + deltaPosition;
|
|
677
|
-
if (minimumPosition !== undefined) {
|
|
678
|
-
position = Math.max(minimumPosition, position);
|
|
679
|
-
}
|
|
680
|
-
if (maximumPosition !== undefined) {
|
|
681
|
-
position = Math.min(maximumPosition, position);
|
|
682
|
-
}
|
|
683
|
-
onReloadOrder({ position, autoPlay: !isPaused });
|
|
684
|
-
}
|
|
1342
|
+
return corePlaybackObserver;
|
|
685
1343
|
}
|
|
686
1344
|
/**
|
|
687
|
-
*
|
|
688
|
-
*
|
|
1345
|
+
* Initialize content playback if and only if those conditions are filled:
|
|
1346
|
+
* - The Manifest is fetched and stored in `this._currentContentInfo`.
|
|
1347
|
+
* - `drmInitializationStatus` indicates that DRM matters are initialized.
|
|
1348
|
+
* - `mediaSourceStatus` indicates that the MediaSource is attached to the
|
|
1349
|
+
* `mediaElement`.
|
|
689
1350
|
*
|
|
690
|
-
*
|
|
691
|
-
* (see `RebufferingController` definition).
|
|
1351
|
+
* In other cases, this method will do nothing.
|
|
692
1352
|
*
|
|
693
|
-
*
|
|
694
|
-
*
|
|
695
|
-
* - emit "unstalled" events when we could get out of one,
|
|
696
|
-
* - emit "warning" on various rebuffering-related minor issues
|
|
697
|
-
* like discontinuity skipping.
|
|
698
|
-
* @param {Object} playbackObserver
|
|
699
|
-
* @param {Object} manifest
|
|
700
|
-
* @param {Object} speed
|
|
701
|
-
* @param {Object} cancelSignal
|
|
702
|
-
* @returns {Object}
|
|
703
|
-
*/
|
|
704
|
-
_createRebufferingController(playbackObserver, manifest, speed, cancelSignal) {
|
|
705
|
-
const rebufferingController = new RebufferingController(playbackObserver, manifest, speed);
|
|
706
|
-
// Bubble-up events
|
|
707
|
-
rebufferingController.addEventListener("stalled", (evt) => this.trigger("stalled", evt));
|
|
708
|
-
rebufferingController.addEventListener("unstalled", () => this.trigger("unstalled", null));
|
|
709
|
-
rebufferingController.addEventListener("warning", (err) => this.trigger("warning", err));
|
|
710
|
-
cancelSignal.register(() => rebufferingController.destroy());
|
|
711
|
-
rebufferingController.start();
|
|
712
|
-
return rebufferingController;
|
|
713
|
-
}
|
|
714
|
-
/**
|
|
715
|
-
* Evaluates a list of codecs to determine their support status.
|
|
1353
|
+
* To call when any of those conditions might become `true`, to start-up
|
|
1354
|
+
* playback.
|
|
716
1355
|
*
|
|
717
|
-
* @param {
|
|
718
|
-
* @returns {
|
|
1356
|
+
* @param {Object} parameters
|
|
1357
|
+
* @returns {boolean} - Returns `true` if all conditions where met for
|
|
1358
|
+
* playback start.
|
|
719
1359
|
*/
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
}
|
|
1360
|
+
_startPlaybackIfReady(parameters) {
|
|
1361
|
+
if (this._currentContentInfo === null || this._currentContentInfo.manifest === null) {
|
|
1362
|
+
return false;
|
|
1363
|
+
}
|
|
1364
|
+
const drmInitStatus = parameters.drmInitializationStatus.getValue();
|
|
1365
|
+
if (drmInitStatus.initializationState.type !== "initialized") {
|
|
1366
|
+
return false;
|
|
1367
|
+
}
|
|
1368
|
+
const msInitStatus = parameters.mediaSourceStatus.getValue();
|
|
1369
|
+
if (msInitStatus !== 2 /* MediaSourceInitializationStatus.Attached */) {
|
|
1370
|
+
return false;
|
|
1371
|
+
}
|
|
1372
|
+
const { contentId, manifest } = this._currentContentInfo;
|
|
1373
|
+
log.debug("Init", "Calculating initial time");
|
|
1374
|
+
const initialTime = getInitialTime(manifest, this._settings.lowLatencyMode, this._settings.startAt);
|
|
1375
|
+
log.debug("Init", "Initial time calculated", { initialTime });
|
|
1376
|
+
const { enableFastSwitching, onCodecSwitch } = this._settings.bufferOptions;
|
|
1377
|
+
const corePlaybackObserver = this._setUpModulesOnNewMediaSource({
|
|
1378
|
+
initialTime,
|
|
1379
|
+
autoPlay: this._settings.autoPlay,
|
|
1380
|
+
mediaElement: parameters.mediaElement,
|
|
1381
|
+
textDisplayer: parameters.textDisplayer,
|
|
1382
|
+
playbackObserver: parameters.playbackObserver,
|
|
1383
|
+
}, this._currentMediaSourceCanceller.signal);
|
|
1384
|
+
if (this._currentMediaSourceCanceller.isUsed() || corePlaybackObserver === null) {
|
|
1385
|
+
return true;
|
|
1386
|
+
}
|
|
1387
|
+
const initialObservation = corePlaybackObserver.getReference().getValue();
|
|
1388
|
+
const sentInitialObservation = objectAssign(initialObservation, {
|
|
1389
|
+
position: initialObservation.position.serialize(),
|
|
1390
|
+
});
|
|
1391
|
+
this._settings.coreInterface.sendMessage({
|
|
1392
|
+
type: "start" /* MainThreadMessageType.StartPreparedContent */,
|
|
1393
|
+
contentId,
|
|
1394
|
+
value: {
|
|
1395
|
+
initialTime,
|
|
1396
|
+
initialObservation: sentInitialObservation,
|
|
1397
|
+
drmSystemId: drmInitStatus.drmSystemId,
|
|
1398
|
+
enableFastSwitching,
|
|
1399
|
+
onCodecSwitch,
|
|
1400
|
+
},
|
|
1401
|
+
});
|
|
1402
|
+
corePlaybackObserver.listen((obs) => {
|
|
1403
|
+
this._settings.coreInterface.sendMessage({
|
|
1404
|
+
type: "observation" /* MainThreadMessageType.PlaybackObservation */,
|
|
1405
|
+
contentId,
|
|
1406
|
+
value: objectAssign(obs, { position: obs.position.serialize() }),
|
|
1407
|
+
});
|
|
1408
|
+
}, {
|
|
1409
|
+
includeLastObservation: false,
|
|
1410
|
+
clearSignal: this._currentMediaSourceCanceller.signal,
|
|
761
1411
|
});
|
|
762
|
-
|
|
1412
|
+
this.trigger("manifestReady", manifest);
|
|
1413
|
+
return true;
|
|
763
1414
|
}
|
|
764
1415
|
/**
|
|
765
|
-
*
|
|
766
|
-
*
|
|
767
|
-
*
|
|
768
|
-
*
|
|
769
|
-
* @param {Object}
|
|
1416
|
+
* Handles core messages asking to create a MediaSource.
|
|
1417
|
+
* @param {Object} msg - The core's message received.
|
|
1418
|
+
* @param {HTMLMediaElement} mediaElement - HTMLMediaElement on which the
|
|
1419
|
+
* content plays.
|
|
1420
|
+
* @param {Object} coreInterface - The interface to the core.
|
|
770
1421
|
*/
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
1422
|
+
_onCreateMediaSourceMessage(msg, mediaElement, mediaSourceStatus, coreInterface) {
|
|
1423
|
+
var _a;
|
|
1424
|
+
if (((_a = this._currentContentInfo) === null || _a === void 0 ? void 0 : _a.contentId) !== msg.contentId) {
|
|
1425
|
+
log.info("Init", "Ignoring MediaSource attachment due to wrong `contentId`");
|
|
1426
|
+
}
|
|
1427
|
+
else {
|
|
1428
|
+
const { mediaSourceId } = msg;
|
|
775
1429
|
try {
|
|
776
|
-
|
|
1430
|
+
mediaSourceStatus.onUpdate((currStatus, stopListening) => {
|
|
1431
|
+
var _a;
|
|
1432
|
+
if (this._currentContentInfo === null) {
|
|
1433
|
+
stopListening();
|
|
1434
|
+
return;
|
|
1435
|
+
}
|
|
1436
|
+
if (currStatus === 1 /* MediaSourceInitializationStatus.AttachNow */) {
|
|
1437
|
+
stopListening();
|
|
1438
|
+
const mediaSource = new MainMediaSourceInterface(mediaSourceId, "FORCED_MEDIA_SOURCE" in mediaElement
|
|
1439
|
+
? mediaElement.FORCED_MEDIA_SOURCE
|
|
1440
|
+
: undefined);
|
|
1441
|
+
if (((_a = this._currentContentInfo.mediaSourceInfo) === null || _a === void 0 ? void 0 : _a.type) === "main") {
|
|
1442
|
+
this._currentContentInfo.mediaSourceInfo.mediaSource.dispose();
|
|
1443
|
+
}
|
|
1444
|
+
this._currentContentInfo.mediaSourceInfo = {
|
|
1445
|
+
type: "main",
|
|
1446
|
+
mediaSource,
|
|
1447
|
+
};
|
|
1448
|
+
mediaSource.addEventListener("mediaSourceOpen", () => {
|
|
1449
|
+
coreInterface.sendMessage({
|
|
1450
|
+
type: "media-source-ready-state-change" /* MainThreadMessageType.MediaSourceReadyStateChange */,
|
|
1451
|
+
mediaSourceId,
|
|
1452
|
+
value: "open",
|
|
1453
|
+
});
|
|
1454
|
+
});
|
|
1455
|
+
mediaSource.addEventListener("mediaSourceEnded", () => {
|
|
1456
|
+
coreInterface.sendMessage({
|
|
1457
|
+
type: "media-source-ready-state-change" /* MainThreadMessageType.MediaSourceReadyStateChange */,
|
|
1458
|
+
mediaSourceId,
|
|
1459
|
+
value: "ended",
|
|
1460
|
+
});
|
|
1461
|
+
});
|
|
1462
|
+
mediaSource.addEventListener("mediaSourceClose", () => {
|
|
1463
|
+
coreInterface.sendMessage({
|
|
1464
|
+
type: "media-source-ready-state-change" /* MainThreadMessageType.MediaSourceReadyStateChange */,
|
|
1465
|
+
mediaSourceId,
|
|
1466
|
+
value: "closed",
|
|
1467
|
+
});
|
|
1468
|
+
});
|
|
1469
|
+
let url = null;
|
|
1470
|
+
if (mediaSource.handle.type === "handle") {
|
|
1471
|
+
mediaElement.srcObject = mediaSource.handle.value;
|
|
1472
|
+
}
|
|
1473
|
+
else {
|
|
1474
|
+
url = URL.createObjectURL(mediaSource.handle.value);
|
|
1475
|
+
mediaElement.src = url;
|
|
1476
|
+
}
|
|
1477
|
+
this._currentMediaSourceCanceller.signal.register(() => {
|
|
1478
|
+
mediaSource.dispose();
|
|
1479
|
+
resetMediaElement(mediaElement, url);
|
|
1480
|
+
});
|
|
1481
|
+
mediaSourceStatus.setValue(2 /* MediaSourceInitializationStatus.Attached */);
|
|
1482
|
+
disableRemotePlaybackOnManagedMediaSource(mediaElement, this._currentMediaSourceCanceller.signal);
|
|
1483
|
+
}
|
|
1484
|
+
}, {
|
|
1485
|
+
emitCurrentValue: true,
|
|
1486
|
+
clearSignal: this._currentMediaSourceCanceller.signal,
|
|
1487
|
+
});
|
|
777
1488
|
}
|
|
778
|
-
catch (
|
|
779
|
-
|
|
1489
|
+
catch (_err) {
|
|
1490
|
+
const error = new OtherError("NONE", "Unknown error when creating the MediaSource");
|
|
1491
|
+
this._onFatalError(error);
|
|
780
1492
|
}
|
|
781
1493
|
}
|
|
782
1494
|
}
|
|
783
1495
|
}
|
|
784
|
-
function
|
|
785
|
-
|
|
786
|
-
|
|
1496
|
+
function bindNumberReferencesToCore(coreInterface, cancellationSignal, ...refs) {
|
|
1497
|
+
for (const ref of refs) {
|
|
1498
|
+
ref[0].onUpdate((newVal) => {
|
|
1499
|
+
// NOTE: The TypeScript checks have already been made by this function's
|
|
1500
|
+
// overload, but the body here is not aware of that.
|
|
1501
|
+
coreInterface.sendMessage({
|
|
1502
|
+
type: "ref-update" /* MainThreadMessageType.ReferenceUpdate */,
|
|
1503
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
|
|
1504
|
+
value: { name: ref[1], newVal: newVal },
|
|
1505
|
+
});
|
|
1506
|
+
}, { clearSignal: cancellationSignal, emitCurrentValue: true });
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
function formatCoreError(sentError) {
|
|
1510
|
+
switch (sentError.name) {
|
|
1511
|
+
case "NetworkError":
|
|
1512
|
+
return new NetworkError(sentError.code, new RequestError(sentError.baseError.url, sentError.baseError.status, sentError.baseError.type));
|
|
1513
|
+
case "MediaError":
|
|
1514
|
+
// eslint-disable-next-line
|
|
1515
|
+
return new MediaError(sentError.code, sentError.reason, {
|
|
1516
|
+
tracks: sentError.tracks,
|
|
1517
|
+
});
|
|
1518
|
+
case "EncryptedMediaError":
|
|
1519
|
+
// We assume that everything have already been checked Worker-side here
|
|
1520
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
1521
|
+
return new EncryptedMediaError(sentError.code, sentError.reason, {
|
|
1522
|
+
keyStatuses: sentError.keyStatuses,
|
|
1523
|
+
keySystemConfiguration: sentError.keySystemConfiguration,
|
|
1524
|
+
keySystem: sentError.keySystem,
|
|
1525
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1526
|
+
});
|
|
1527
|
+
case "OtherError":
|
|
1528
|
+
return new OtherError(sentError.code, sentError.reason);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
function formatSourceBufferError(error) {
|
|
1532
|
+
if (error instanceof SourceBufferError) {
|
|
1533
|
+
return error;
|
|
1534
|
+
}
|
|
1535
|
+
else if (error instanceof Error) {
|
|
1536
|
+
return new SourceBufferError(error.name, error.message, error.name === "QuotaExceededError");
|
|
787
1537
|
}
|
|
788
|
-
else
|
|
789
|
-
return new
|
|
1538
|
+
else {
|
|
1539
|
+
return new SourceBufferError("Error", "Unknown SourceBufferError Error", false);
|
|
790
1540
|
}
|
|
791
|
-
return null;
|
|
792
1541
|
}
|
|
793
1542
|
/**
|
|
794
|
-
*
|
|
795
|
-
*
|
|
796
|
-
*
|
|
797
|
-
* - Those who have a key id listed in `whitelistedKeyIds` will have their
|
|
798
|
-
* decipherability updated to `true`
|
|
799
|
-
*
|
|
800
|
-
* - Those who have a key id listed in `blacklistedKeyIds` will have their
|
|
801
|
-
* decipherability updated to `false`
|
|
1543
|
+
* The Core might send back logs. In that situation, the message might be
|
|
1544
|
+
* formatted slightly differently to be able to cross threads (so a
|
|
1545
|
+
* serializable format has to be sent).
|
|
802
1546
|
*
|
|
803
|
-
*
|
|
804
|
-
*
|
|
1547
|
+
* This function translates that Core format to what's expected by the
|
|
1548
|
+
* logger.
|
|
805
1549
|
*
|
|
806
|
-
* @param {
|
|
807
|
-
* @
|
|
808
|
-
* @param {Array.<Uint8Array>} blacklistedKeyIds
|
|
809
|
-
* @param {Array.<Uint8Array>} delistedKeyIds
|
|
810
|
-
*/
|
|
811
|
-
function updateKeyIdsDecipherabilityOnManifest(manifest, whitelistedKeyIds, blacklistedKeyIds, delistedKeyIds) {
|
|
812
|
-
manifest.updateRepresentationsDeciperability((ctx) => {
|
|
813
|
-
const { representation } = ctx;
|
|
814
|
-
if (representation.contentProtections === undefined) {
|
|
815
|
-
return representation.decipherable;
|
|
816
|
-
}
|
|
817
|
-
const contentKIDs = representation.contentProtections.keyIds;
|
|
818
|
-
if (contentKIDs !== undefined) {
|
|
819
|
-
for (const elt of contentKIDs) {
|
|
820
|
-
for (const blacklistedKeyId of blacklistedKeyIds) {
|
|
821
|
-
if (areArraysOfNumbersEqual(blacklistedKeyId, elt)) {
|
|
822
|
-
return false;
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
for (const whitelistedKeyId of whitelistedKeyIds) {
|
|
826
|
-
if (areArraysOfNumbersEqual(whitelistedKeyId, elt)) {
|
|
827
|
-
return true;
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
for (const delistedKeyId of delistedKeyIds) {
|
|
831
|
-
if (areArraysOfNumbersEqual(delistedKeyId, elt)) {
|
|
832
|
-
return undefined;
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
return representation.decipherable;
|
|
838
|
-
});
|
|
839
|
-
}
|
|
840
|
-
/**
|
|
841
|
-
* Update decipherability to `false` to any Representation which is linked to
|
|
842
|
-
* the given initialization data.
|
|
843
|
-
* @param {Object} manifest
|
|
844
|
-
* @param {Object} initData
|
|
1550
|
+
* @param {*} arg
|
|
1551
|
+
* @returns {*}
|
|
845
1552
|
*/
|
|
846
|
-
function
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
}
|
|
853
|
-
const segmentProtections = (_b = (_a = rep.contentProtections) === null || _a === void 0 ? void 0 : _a.initData) !== null && _b !== void 0 ? _b : [];
|
|
854
|
-
for (const protection of segmentProtections) {
|
|
855
|
-
if (initData.type === undefined || protection.type === initData.type) {
|
|
856
|
-
const containedInitData = initData.values
|
|
857
|
-
.getFormattedValues()
|
|
858
|
-
.every((undecipherableVal) => {
|
|
859
|
-
return protection.values.some((currVal) => {
|
|
860
|
-
return ((undecipherableVal.systemId === undefined ||
|
|
861
|
-
currVal.systemId === undecipherableVal.systemId) &&
|
|
862
|
-
areArraysOfNumbersEqual(currVal.data, undecipherableVal.data));
|
|
863
|
-
});
|
|
864
|
-
});
|
|
865
|
-
if (containedInitData) {
|
|
866
|
-
return false;
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
return rep.decipherable;
|
|
871
|
-
});
|
|
872
|
-
}
|
|
873
|
-
/**
|
|
874
|
-
* Handle accordingly an `IFreezeResolution` object.
|
|
875
|
-
* @param {Object|null} freezeResolution - The `IFreezeResolution` suggested.
|
|
876
|
-
* @param {Object} param - Parameters that might be needed to implement the
|
|
877
|
-
* resolution.
|
|
878
|
-
* @param {Object} param.manifest - The current content's Manifest object.
|
|
879
|
-
* @param {Object} param.playbackObserver - Object regularly emitting playback
|
|
880
|
-
* conditions.
|
|
881
|
-
* @param {Function} param.triggerReload - Function to call if we need to ask
|
|
882
|
-
* for a "MediaSource reload".
|
|
883
|
-
* @param {Boolean} param.enableRepresentationAvoidance - If `true`, this
|
|
884
|
-
* function is authorized to mark `Representation` as "to avoid" if the
|
|
885
|
-
* `IFreezeResolution` object suggest it.
|
|
886
|
-
*/
|
|
887
|
-
function handleFreezeResolution(freezeResolution, { playbackObserver, enableRepresentationAvoidance, manifest, triggerReload, }) {
|
|
888
|
-
switch (freezeResolution.type) {
|
|
889
|
-
case "reload": {
|
|
890
|
-
log.info("Init", "Planning reload due to freeze");
|
|
891
|
-
triggerReload();
|
|
892
|
-
break;
|
|
893
|
-
}
|
|
894
|
-
case "flush": {
|
|
895
|
-
log.info("Init", "Flushing buffer due to freeze");
|
|
896
|
-
const observation = playbackObserver.getReference().getValue();
|
|
897
|
-
const currentTime = observation.position.isAwaitingFuturePosition()
|
|
898
|
-
? observation.position.getWanted()
|
|
899
|
-
: playbackObserver.getCurrentTime();
|
|
900
|
-
const relativeResumingPosition = freezeResolution.value.relativeSeek;
|
|
901
|
-
const wantedSeekingTime = currentTime + relativeResumingPosition;
|
|
902
|
-
playbackObserver.setCurrentTime(wantedSeekingTime);
|
|
903
|
-
break;
|
|
904
|
-
}
|
|
905
|
-
case "avoid-representations": {
|
|
906
|
-
const contents = freezeResolution.value;
|
|
907
|
-
if (enableRepresentationAvoidance) {
|
|
908
|
-
manifest.addRepresentationsToAvoid(contents);
|
|
909
|
-
}
|
|
910
|
-
triggerReload();
|
|
911
|
-
break;
|
|
912
|
-
}
|
|
913
|
-
default:
|
|
914
|
-
assertUnreachable(freezeResolution);
|
|
1553
|
+
function formatSentLogObject(arg) {
|
|
1554
|
+
if (typeof arg !== "object") {
|
|
1555
|
+
return arg;
|
|
1556
|
+
}
|
|
1557
|
+
if ((arg === null || arg === void 0 ? void 0 : arg.isSerializedError) === true) {
|
|
1558
|
+
return formatCoreError(arg);
|
|
915
1559
|
}
|
|
1560
|
+
return arg;
|
|
916
1561
|
}
|