rx-player 4.4.1-dev.2025101500 → 4.4.1
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 +3 -1
- package/README.md +111 -50
- package/VERSION +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_dash_wasm.d.ts.map +1 -1
- package/dist/commonjs/__GENERATED_CODE/embedded_dash_wasm.js +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/{entry → main/common}/FreezeResolver.d.ts +3 -3
- package/dist/commonjs/core/main/common/FreezeResolver.d.ts.map +1 -0
- package/dist/commonjs/core/{entry → main/common}/FreezeResolver.js +3 -3
- package/dist/commonjs/core/{entry → main/common}/content_time_boundaries_observer.d.ts +5 -5
- package/dist/commonjs/core/main/common/content_time_boundaries_observer.d.ts.map +1 -0
- package/dist/commonjs/core/{entry → main/common}/content_time_boundaries_observer.js +6 -6
- package/dist/{es2017/core/entry → commonjs/core/main/common}/create_content_time_boundaries_observer.d.ts +6 -6
- package/dist/commonjs/core/main/common/create_content_time_boundaries_observer.d.ts.map +1 -0
- package/dist/commonjs/core/{entry → main/common}/create_content_time_boundaries_observer.js +1 -1
- package/dist/{es2017/core/entry → commonjs/core/main/common}/get_buffered_data_per_media_buffer.d.ts +4 -4
- package/dist/commonjs/core/main/common/get_buffered_data_per_media_buffer.d.ts.map +1 -0
- package/dist/commonjs/core/{entry → main/common}/get_buffered_data_per_media_buffer.js +1 -1
- package/dist/{es2017/core/entry → commonjs/core/main/common}/get_thumbnail_data.d.ts +3 -3
- package/dist/commonjs/core/main/common/get_thumbnail_data.d.ts.map +1 -0
- package/dist/commonjs/core/{entry → main/common}/get_thumbnail_data.js +2 -2
- package/dist/{es2017/core/entry → commonjs/core/main/common}/synchronize_sinks_on_observation.d.ts +2 -2
- package/dist/commonjs/core/main/common/synchronize_sinks_on_observation.d.ts.map +1 -0
- package/dist/{es2017/core/entry → commonjs/core/main/worker}/content_preparer.d.ts +15 -22
- package/dist/commonjs/core/main/worker/content_preparer.d.ts.map +1 -0
- package/dist/commonjs/core/{entry → main/worker}/content_preparer.js +64 -62
- package/dist/commonjs/core/main/worker/globals.d.ts +14 -0
- package/dist/commonjs/core/main/worker/globals.d.ts.map +1 -0
- package/dist/commonjs/core/main/worker/globals.js +26 -0
- package/dist/commonjs/core/main/worker/index.d.ts +3 -0
- package/dist/commonjs/core/main/worker/index.d.ts.map +1 -0
- package/dist/commonjs/core/main/worker/index.js +4 -0
- package/dist/commonjs/core/main/worker/send_message.d.ts +4 -0
- package/dist/commonjs/core/main/worker/send_message.d.ts.map +1 -0
- package/dist/commonjs/core/main/worker/send_message.js +23 -0
- package/dist/{es2017/core/entry → commonjs/core/main/worker}/track_choice_setter.d.ts +4 -4
- package/dist/commonjs/core/main/worker/track_choice_setter.d.ts.map +1 -0
- package/dist/commonjs/core/{entry → main/worker}/track_choice_setter.js +4 -4
- package/dist/commonjs/core/main/worker/worker_main.d.ts +2 -0
- package/dist/commonjs/core/main/worker/worker_main.d.ts.map +1 -0
- package/dist/commonjs/core/{entry/core_entry.js → main/worker/worker_main.js} +153 -192
- package/dist/commonjs/core/{entry/core_text_displayer_interface.d.ts → main/worker/worker_text_displayer_interface.d.ts} +11 -11
- package/dist/commonjs/core/main/worker/worker_text_displayer_interface.d.ts.map +1 -0
- package/dist/commonjs/core/{entry/core_text_displayer_interface.js → main/worker/worker_text_displayer_interface.js} +22 -22
- package/dist/commonjs/core/types.d.ts +1 -519
- package/dist/commonjs/core/types.d.ts.map +1 -1
- package/dist/commonjs/core/types.js +0 -1
- package/dist/commonjs/experimental/features/local.d.ts.map +1 -1
- package/dist/commonjs/experimental/features/local.js +1 -7
- package/dist/commonjs/experimental/features/metaplaylist.d.ts.map +1 -1
- package/dist/commonjs/experimental/features/metaplaylist.js +1 -7
- package/dist/commonjs/experimental/features/multi_thread.d.ts.map +1 -1
- package/dist/commonjs/experimental/features/multi_thread.js +2 -6
- 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 +1 -7
- package/dist/commonjs/features/list/dash_wasm.d.ts.map +1 -1
- package/dist/commonjs/features/list/dash_wasm.js +1 -7
- package/dist/commonjs/features/list/media_source_main.d.ts.map +1 -1
- package/dist/commonjs/features/list/media_source_main.js +1 -7
- package/dist/commonjs/features/list/smooth.d.ts.map +1 -1
- package/dist/commonjs/features/list/smooth.js +1 -7
- package/dist/commonjs/features/types.d.ts +4 -20
- 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 +44 -40
- package/dist/commonjs/main_thread/init/media_source_content_initializer.d.ts +108 -166
- 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 +918 -1491
- package/dist/commonjs/main_thread/init/multi_thread_content_initializer.d.ts +308 -0
- package/dist/commonjs/main_thread/init/multi_thread_content_initializer.d.ts.map +1 -0
- package/dist/commonjs/main_thread/init/multi_thread_content_initializer.js +1713 -0
- package/dist/commonjs/main_thread/init/send_message.d.ts +3 -0
- package/dist/commonjs/main_thread/init/send_message.d.ts.map +1 -0
- package/dist/commonjs/main_thread/init/send_message.js +13 -0
- 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 +1 -2
- 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 +0 -537
- 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 +4 -18
- 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/multithread_types.d.ts +915 -0
- package/dist/commonjs/multithread_types.d.ts.map +1 -0
- package/dist/commonjs/multithread_types.js +7 -0
- 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 +27 -31
- package/dist/commonjs/parsers/manifest/smooth/parse_C_nodes.d.ts +2 -3
- package/dist/commonjs/parsers/manifest/smooth/parse_C_nodes.d.ts.map +1 -1
- package/dist/commonjs/parsers/manifest/smooth/parse_C_nodes.js +7 -16
- package/dist/commonjs/parsers/manifest/smooth/parse_protection_node.d.ts +2 -3
- package/dist/commonjs/parsers/manifest/smooth/parse_protection_node.d.ts.map +1 -1
- package/dist/commonjs/parsers/manifest/smooth/parse_protection_node.js +6 -37
- 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 +2 -3
- package/dist/commonjs/parsers/manifest/smooth/utils/reduceChildren.d.ts.map +1 -1
- package/dist/commonjs/parsers/manifest/smooth/utils/reduceChildren.js +5 -28
- package/dist/commonjs/playback_observer/media_element_playback_observer.d.ts +28 -8
- package/dist/commonjs/playback_observer/media_element_playback_observer.d.ts.map +1 -1
- package/dist/commonjs/playback_observer/media_element_playback_observer.js +146 -64
- package/dist/{es2017/playback_observer/core_playback_observer.d.ts → commonjs/playback_observer/worker_playback_observer.d.ts} +8 -8
- package/dist/commonjs/playback_observer/worker_playback_observer.d.ts.map +1 -0
- package/dist/commonjs/playback_observer/{core_playback_observer.js → worker_playback_observer.js} +13 -13
- package/dist/commonjs/transports/smooth/pipelines.d.ts.map +1 -1
- package/dist/commonjs/transports/smooth/pipelines.js +3 -25
- package/dist/commonjs/worker_entry_point.js +2 -62
- package/dist/es2017/__GENERATED_CODE/embedded_dash_wasm.d.ts.map +1 -1
- package/dist/es2017/__GENERATED_CODE/embedded_dash_wasm.js +1 -1
- 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/{entry → main/common}/FreezeResolver.d.ts +3 -3
- package/dist/es2017/core/main/common/FreezeResolver.d.ts.map +1 -0
- package/dist/es2017/core/{entry → main/common}/FreezeResolver.js +3 -3
- package/dist/es2017/core/{entry → main/common}/content_time_boundaries_observer.d.ts +5 -5
- package/dist/es2017/core/main/common/content_time_boundaries_observer.d.ts.map +1 -0
- package/dist/es2017/core/{entry → main/common}/content_time_boundaries_observer.js +6 -6
- package/dist/{commonjs/core/entry → es2017/core/main/common}/create_content_time_boundaries_observer.d.ts +6 -6
- package/dist/es2017/core/main/common/create_content_time_boundaries_observer.d.ts.map +1 -0
- package/dist/es2017/core/{entry → main/common}/create_content_time_boundaries_observer.js +1 -1
- package/dist/{commonjs/core/entry → es2017/core/main/common}/get_buffered_data_per_media_buffer.d.ts +4 -4
- package/dist/es2017/core/main/common/get_buffered_data_per_media_buffer.d.ts.map +1 -0
- package/dist/es2017/core/{entry → main/common}/get_buffered_data_per_media_buffer.js +1 -1
- package/dist/{commonjs/core/entry → es2017/core/main/common}/get_thumbnail_data.d.ts +3 -3
- package/dist/es2017/core/main/common/get_thumbnail_data.d.ts.map +1 -0
- package/dist/es2017/core/{entry → main/common}/get_thumbnail_data.js +2 -2
- package/dist/{commonjs/core/entry → es2017/core/main/common}/synchronize_sinks_on_observation.d.ts +2 -2
- package/dist/es2017/core/main/common/synchronize_sinks_on_observation.d.ts.map +1 -0
- package/dist/{commonjs/core/entry → es2017/core/main/worker}/content_preparer.d.ts +15 -22
- package/dist/es2017/core/main/worker/content_preparer.d.ts.map +1 -0
- package/dist/es2017/core/{entry → main/worker}/content_preparer.js +55 -53
- package/dist/es2017/core/main/worker/globals.d.ts +14 -0
- package/dist/es2017/core/main/worker/globals.d.ts.map +1 -0
- package/dist/es2017/core/main/worker/globals.js +18 -0
- package/dist/es2017/core/main/worker/index.d.ts +3 -0
- package/dist/es2017/core/main/worker/index.d.ts.map +1 -0
- package/dist/es2017/core/main/worker/index.js +2 -0
- package/dist/es2017/core/main/worker/send_message.d.ts +4 -0
- package/dist/es2017/core/main/worker/send_message.d.ts.map +1 -0
- package/dist/es2017/core/main/worker/send_message.js +19 -0
- package/dist/{commonjs/core/entry → es2017/core/main/worker}/track_choice_setter.d.ts +4 -4
- package/dist/es2017/core/main/worker/track_choice_setter.d.ts.map +1 -0
- package/dist/es2017/core/{entry → main/worker}/track_choice_setter.js +4 -4
- package/dist/es2017/core/main/worker/worker_main.d.ts +2 -0
- package/dist/es2017/core/main/worker/worker_main.d.ts.map +1 -0
- package/dist/es2017/core/{entry/core_entry.js → main/worker/worker_main.js} +114 -153
- package/dist/es2017/core/{entry/core_text_displayer_interface.d.ts → main/worker/worker_text_displayer_interface.d.ts} +11 -11
- package/dist/es2017/core/main/worker/worker_text_displayer_interface.d.ts.map +1 -0
- package/dist/es2017/core/{entry/core_text_displayer_interface.js → main/worker/worker_text_displayer_interface.js} +10 -10
- package/dist/es2017/core/types.d.ts +1 -519
- package/dist/es2017/core/types.d.ts.map +1 -1
- package/dist/es2017/core/types.js +0 -1
- package/dist/es2017/experimental/features/local.d.ts.map +1 -1
- package/dist/es2017/experimental/features/local.js +1 -7
- package/dist/es2017/experimental/features/metaplaylist.d.ts.map +1 -1
- package/dist/es2017/experimental/features/metaplaylist.js +1 -7
- package/dist/es2017/experimental/features/multi_thread.d.ts.map +1 -1
- package/dist/es2017/experimental/features/multi_thread.js +2 -6
- 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 +1 -7
- package/dist/es2017/features/list/dash_wasm.d.ts.map +1 -1
- package/dist/es2017/features/list/dash_wasm.js +1 -7
- package/dist/es2017/features/list/media_source_main.d.ts.map +1 -1
- package/dist/es2017/features/list/media_source_main.js +1 -7
- package/dist/es2017/features/list/smooth.d.ts.map +1 -1
- package/dist/es2017/features/list/smooth.js +1 -7
- package/dist/es2017/features/types.d.ts +4 -20
- 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 +45 -41
- package/dist/es2017/main_thread/init/media_source_content_initializer.d.ts +108 -166
- 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 +760 -1405
- package/dist/es2017/main_thread/init/multi_thread_content_initializer.d.ts +308 -0
- package/dist/es2017/main_thread/init/multi_thread_content_initializer.d.ts.map +1 -0
- package/dist/es2017/main_thread/init/multi_thread_content_initializer.js +1559 -0
- package/dist/es2017/main_thread/init/send_message.d.ts +3 -0
- package/dist/es2017/main_thread/init/send_message.d.ts.map +1 -0
- package/dist/es2017/main_thread/init/send_message.js +10 -0
- 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 +1 -2
- 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 +0 -537
- 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 +4 -16
- 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/multithread_types.d.ts +915 -0
- package/dist/es2017/multithread_types.d.ts.map +1 -0
- package/dist/es2017/multithread_types.js +6 -0
- 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 +27 -31
- package/dist/es2017/parsers/manifest/smooth/parse_C_nodes.d.ts +2 -3
- package/dist/es2017/parsers/manifest/smooth/parse_C_nodes.d.ts.map +1 -1
- package/dist/es2017/parsers/manifest/smooth/parse_C_nodes.js +7 -16
- package/dist/es2017/parsers/manifest/smooth/parse_protection_node.d.ts +2 -3
- package/dist/es2017/parsers/manifest/smooth/parse_protection_node.d.ts.map +1 -1
- package/dist/es2017/parsers/manifest/smooth/parse_protection_node.js +6 -15
- 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 +2 -3
- package/dist/es2017/parsers/manifest/smooth/utils/reduceChildren.d.ts.map +1 -1
- package/dist/es2017/parsers/manifest/smooth/utils/reduceChildren.js +5 -6
- package/dist/es2017/playback_observer/media_element_playback_observer.d.ts +28 -8
- package/dist/es2017/playback_observer/media_element_playback_observer.d.ts.map +1 -1
- package/dist/es2017/playback_observer/media_element_playback_observer.js +144 -64
- package/dist/{commonjs/playback_observer/core_playback_observer.d.ts → es2017/playback_observer/worker_playback_observer.d.ts} +8 -8
- package/dist/es2017/playback_observer/worker_playback_observer.d.ts.map +1 -0
- package/dist/es2017/playback_observer/{core_playback_observer.js → worker_playback_observer.js} +2 -2
- package/dist/es2017/transports/smooth/pipelines.d.ts.map +1 -1
- package/dist/es2017/transports/smooth/pipelines.js +3 -25
- package/dist/es2017/worker_entry_point.js +2 -62
- package/dist/mpd-parser.wasm +0 -0
- package/dist/rx-player.js +19165 -21886
- package/dist/rx-player.min.js +20 -20
- package/dist/worker.js +8 -8
- package/eslint.config.mjs +647 -348
- package/package.json +6 -6
- package/src/README.md +198 -88
- package/src/__GENERATED_CODE/embedded_dash_wasm.ts +1 -1
- package/src/__GENERATED_CODE/embedded_worker.ts +1 -1
- package/src/core/{entry → main}/README.md +1 -1
- package/src/core/{entry → main/common}/FreezeResolver.ts +7 -7
- package/src/core/{entry → main/common}/content_time_boundaries_observer.ts +10 -10
- package/src/core/{entry → main/common}/create_content_time_boundaries_observer.ts +7 -7
- package/src/core/{entry → main/common}/get_buffered_data_per_media_buffer.ts +6 -6
- package/src/core/{entry → main/common}/get_thumbnail_data.ts +5 -5
- package/src/core/{entry → main/common}/synchronize_sinks_on_observation.ts +2 -2
- package/src/core/{entry → main/worker}/content_preparer.ts +76 -77
- package/src/core/main/worker/globals.ts +38 -0
- package/src/core/main/worker/index.ts +2 -0
- package/src/core/main/worker/send_message.ts +28 -0
- package/src/core/{entry → main/worker}/track_choice_setter.ts +7 -7
- package/src/core/{entry/core_entry.ts → main/worker/worker_main.ts} +149 -223
- package/src/core/{entry/core_text_displayer_interface.ts → main/worker/worker_text_displayer_interface.ts} +26 -26
- package/src/core/types.ts +3 -631
- package/src/experimental/features/__tests__/local.test.ts +2 -11
- package/src/experimental/features/__tests__/metaplaylist.test.ts +2 -11
- package/src/experimental/features/__tests__/multi_thread.test.ts +3 -8
- package/src/experimental/features/local.ts +1 -7
- package/src/experimental/features/metaplaylist.ts +1 -7
- package/src/experimental/features/multi_thread.ts +2 -6
- package/src/features/features_object.ts +1 -1
- package/src/features/list/__tests__/dash.test.ts +3 -12
- package/src/features/list/__tests__/smooth.test.ts +2 -11
- package/src/features/list/dash.ts +1 -7
- package/src/features/list/dash_wasm.ts +1 -7
- package/src/features/list/media_source_main.ts +1 -7
- package/src/features/list/smooth.ts +1 -7
- package/src/features/types.ts +4 -23
- package/src/main_thread/README.md +0 -8
- package/src/main_thread/api/public_api.ts +51 -47
- package/src/main_thread/init/media_source_content_initializer.ts +1164 -2046
- package/src/main_thread/init/multi_thread_content_initializer.ts +2330 -0
- package/src/main_thread/init/send_message.ts +15 -0
- package/src/main_thread/init/utils/create_core_playback_observer.ts +1 -2
- package/src/main_thread/init/utils/update_manifest_codec_support.ts +1 -1
- package/src/main_thread/types.ts +0 -610
- package/src/manifest/utils.ts +4 -20
- package/src/mse/worker_media_source_interface.ts +35 -35
- package/src/multithread_types.ts +1095 -0
- package/src/parsers/manifest/smooth/create_parser.ts +34 -40
- package/src/parsers/manifest/smooth/parse_C_nodes.ts +8 -19
- package/src/parsers/manifest/smooth/parse_protection_node.ts +9 -17
- package/src/parsers/manifest/smooth/utils/parseBoolean.ts +1 -1
- package/src/parsers/manifest/smooth/utils/reduceChildren.ts +7 -10
- package/src/playback_observer/media_element_playback_observer.ts +177 -73
- package/src/playback_observer/{core_playback_observer.ts → worker_playback_observer.ts} +13 -13
- package/src/transports/smooth/pipelines.ts +5 -25
- package/src/worker_entry_point.ts +2 -71
- package/dist/commonjs/core/entry/FreezeResolver.d.ts.map +0 -1
- package/dist/commonjs/core/entry/content_preparer.d.ts.map +0 -1
- package/dist/commonjs/core/entry/content_time_boundaries_observer.d.ts.map +0 -1
- package/dist/commonjs/core/entry/core_entry.d.ts +0 -36
- package/dist/commonjs/core/entry/core_entry.d.ts.map +0 -1
- package/dist/commonjs/core/entry/core_text_displayer_interface.d.ts.map +0 -1
- package/dist/commonjs/core/entry/create_content_time_boundaries_observer.d.ts.map +0 -1
- package/dist/commonjs/core/entry/get_buffered_data_per_media_buffer.d.ts.map +0 -1
- package/dist/commonjs/core/entry/get_thumbnail_data.d.ts.map +0 -1
- package/dist/commonjs/core/entry/index.d.ts +0 -5
- package/dist/commonjs/core/entry/index.d.ts.map +0 -1
- package/dist/commonjs/core/entry/index.js +0 -4
- package/dist/commonjs/core/entry/synchronize_sinks_on_observation.d.ts.map +0 -1
- package/dist/commonjs/core/entry/track_choice_setter.d.ts.map +0 -1
- package/dist/commonjs/core/entry/utils.d.ts +0 -3
- package/dist/commonjs/core/entry/utils.d.ts.map +0 -1
- package/dist/commonjs/core/entry/utils.js +0 -11
- package/dist/commonjs/main_thread/core_interface/base.d.ts +0 -13
- package/dist/commonjs/main_thread/core_interface/base.d.ts.map +0 -1
- package/dist/commonjs/main_thread/core_interface/base.js +0 -32
- package/dist/commonjs/main_thread/core_interface/monothread.d.ts +0 -13
- package/dist/commonjs/main_thread/core_interface/monothread.d.ts.map +0 -1
- package/dist/commonjs/main_thread/core_interface/monothread.js +0 -56
- package/dist/commonjs/main_thread/core_interface/multithread.d.ts +0 -25
- package/dist/commonjs/main_thread/core_interface/multithread.d.ts.map +0 -1
- package/dist/commonjs/main_thread/core_interface/multithread.js +0 -67
- package/dist/commonjs/main_thread/core_interface/types.d.ts +0 -6
- package/dist/commonjs/main_thread/core_interface/types.d.ts.map +0 -1
- package/dist/commonjs/main_thread/core_interface/types.js +0 -2
- package/dist/commonjs/playback_observer/core_playback_observer.d.ts.map +0 -1
- package/dist/es2017/core/entry/FreezeResolver.d.ts.map +0 -1
- package/dist/es2017/core/entry/content_preparer.d.ts.map +0 -1
- package/dist/es2017/core/entry/content_time_boundaries_observer.d.ts.map +0 -1
- package/dist/es2017/core/entry/core_entry.d.ts +0 -36
- package/dist/es2017/core/entry/core_entry.d.ts.map +0 -1
- package/dist/es2017/core/entry/core_text_displayer_interface.d.ts.map +0 -1
- package/dist/es2017/core/entry/create_content_time_boundaries_observer.d.ts.map +0 -1
- package/dist/es2017/core/entry/get_buffered_data_per_media_buffer.d.ts.map +0 -1
- package/dist/es2017/core/entry/get_thumbnail_data.d.ts.map +0 -1
- package/dist/es2017/core/entry/index.d.ts +0 -5
- package/dist/es2017/core/entry/index.d.ts.map +0 -1
- package/dist/es2017/core/entry/index.js +0 -2
- package/dist/es2017/core/entry/synchronize_sinks_on_observation.d.ts.map +0 -1
- package/dist/es2017/core/entry/track_choice_setter.d.ts.map +0 -1
- package/dist/es2017/core/entry/utils.d.ts +0 -3
- package/dist/es2017/core/entry/utils.d.ts.map +0 -1
- package/dist/es2017/core/entry/utils.js +0 -8
- package/dist/es2017/main_thread/core_interface/base.d.ts +0 -13
- package/dist/es2017/main_thread/core_interface/base.d.ts.map +0 -1
- package/dist/es2017/main_thread/core_interface/base.js +0 -28
- package/dist/es2017/main_thread/core_interface/monothread.d.ts +0 -13
- package/dist/es2017/main_thread/core_interface/monothread.d.ts.map +0 -1
- package/dist/es2017/main_thread/core_interface/monothread.js +0 -32
- package/dist/es2017/main_thread/core_interface/multithread.d.ts +0 -25
- package/dist/es2017/main_thread/core_interface/multithread.d.ts.map +0 -1
- package/dist/es2017/main_thread/core_interface/multithread.js +0 -45
- package/dist/es2017/main_thread/core_interface/types.d.ts +0 -6
- package/dist/es2017/main_thread/core_interface/types.d.ts.map +0 -1
- package/dist/es2017/main_thread/core_interface/types.js +0 -1
- package/dist/es2017/playback_observer/core_playback_observer.d.ts.map +0 -1
- package/src/core/entry/index.ts +0 -4
- package/src/core/entry/utils.ts +0 -11
- package/src/main_thread/core_interface/README.md +0 -22
- package/src/main_thread/core_interface/base.ts +0 -36
- package/src/main_thread/core_interface/monothread.ts +0 -46
- package/src/main_thread/core_interface/multithread.ts +0 -49
- package/src/main_thread/core_interface/types.ts +0 -5
- /package/dist/commonjs/core/{entry → main/common}/synchronize_sinks_on_observation.js +0 -0
- /package/dist/es2017/core/{entry → main/common}/synchronize_sinks_on_observation.js +0 -0
|
@@ -1,32 +1,63 @@
|
|
|
1
|
-
|
|
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";
|
|
2
17
|
import mayMediaElementFailOnUndecipherableData from "../../compat/may_media_element_fail_on_undecipherable_data";
|
|
3
18
|
import shouldReloadMediaSourceOnDecipherabilityUpdate from "../../compat/should_reload_media_source_on_decipherability_update";
|
|
4
|
-
import
|
|
19
|
+
import config from "../../config";
|
|
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";
|
|
5
30
|
import features from "../../features";
|
|
6
31
|
import log from "../../log";
|
|
7
|
-
import
|
|
8
|
-
import MainMediaSourceInterface from "../../mse/main_media_source_interface";
|
|
9
|
-
import arrayFind from "../../utils/array_find";
|
|
32
|
+
import areArraysOfNumbersEqual from "../../utils/are_arrays_of_numbers_equal";
|
|
10
33
|
import assert, { assertUnreachable } from "../../utils/assert";
|
|
11
|
-
import
|
|
34
|
+
import createCancellablePromise from "../../utils/create_cancellable_promise";
|
|
12
35
|
import isNullOrUndefined from "../../utils/is_null_or_undefined";
|
|
36
|
+
import noop from "../../utils/noop";
|
|
13
37
|
import objectAssign from "../../utils/object_assign";
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import TaskCanceller, { CancellationError } from "../../utils/task_canceller";
|
|
38
|
+
import SyncOrAsync from "../../utils/sync_or_async";
|
|
39
|
+
import TaskCanceller from "../../utils/task_canceller";
|
|
17
40
|
import { ContentDecryptorState, getKeySystemConfiguration } from "../decrypt";
|
|
18
41
|
import { ContentInitializer } from "./types";
|
|
19
42
|
import createCorePlaybackObserver from "./utils/create_core_playback_observer";
|
|
20
|
-
import
|
|
43
|
+
import createMediaSource from "./utils/create_media_source";
|
|
21
44
|
import getInitialTime from "./utils/get_initial_time";
|
|
22
45
|
import getLoadedReference from "./utils/get_loaded_reference";
|
|
23
46
|
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";
|
|
24
49
|
import RebufferingController from "./utils/rebuffering_controller";
|
|
25
|
-
import StreamEventsEmitter from "./utils/stream_events_emitter
|
|
50
|
+
import StreamEventsEmitter from "./utils/stream_events_emitter";
|
|
26
51
|
import listenToMediaError from "./utils/throw_on_media_error";
|
|
27
|
-
import { updateManifestCodecSupport } from "./utils/update_manifest_codec_support";
|
|
28
|
-
const generateContentId = idGenerator();
|
|
29
52
|
/**
|
|
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
|
+
*
|
|
30
61
|
* @class MediaSourceContentInitializer
|
|
31
62
|
*/
|
|
32
63
|
export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
@@ -37,146 +68,51 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
37
68
|
*/
|
|
38
69
|
constructor(settings) {
|
|
39
70
|
super();
|
|
40
|
-
this.
|
|
71
|
+
this._initSettings = settings;
|
|
41
72
|
this._initCanceller = new TaskCanceller();
|
|
42
|
-
this.
|
|
43
|
-
this.
|
|
44
|
-
|
|
45
|
-
this.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
pendingThumbnailFetching: new Map(),
|
|
49
|
-
};
|
|
50
|
-
this._queuedCoreMessages = null;
|
|
73
|
+
this._manifest = null;
|
|
74
|
+
this._decryptionCapabilities = { status: "uninitialized", value: null };
|
|
75
|
+
const urls = settings.url === undefined ? undefined : [settings.url];
|
|
76
|
+
this._cmcdDataBuilder =
|
|
77
|
+
settings.cmcd === undefined ? null : new CmcdDataBuilder(settings.cmcd);
|
|
78
|
+
this._manifestFetcher = new ManifestFetcher(urls, settings.transport, Object.assign(Object.assign({}, settings.manifestRequestSettings), { lowLatencyMode: settings.lowLatencyMode, cmcdDataBuilder: this._cmcdDataBuilder }));
|
|
51
79
|
}
|
|
52
80
|
/**
|
|
53
81
|
* Perform non-destructive preparation steps, to prepare a future content.
|
|
82
|
+
* For now, this mainly mean loading the Manifest document.
|
|
54
83
|
*/
|
|
55
84
|
prepare() {
|
|
56
|
-
|
|
57
|
-
if (this._currentContentInfo !== null || this._initCanceller.isUsed()) {
|
|
85
|
+
if (this._manifest !== null) {
|
|
58
86
|
return;
|
|
59
87
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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,
|
|
88
|
+
this._manifest = SyncOrAsync.createAsync(createCancellablePromise(this._initCanceller.signal, (res, rej) => {
|
|
89
|
+
this._manifestFetcher.addEventListener("warning", (err) => this.trigger("warning", err));
|
|
90
|
+
this._manifestFetcher.addEventListener("error", (err) => {
|
|
91
|
+
this.trigger("error", err);
|
|
92
|
+
rej(err);
|
|
99
93
|
});
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
this.
|
|
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);
|
|
94
|
+
this._manifestFetcher.addEventListener("manifestReady", (manifest) => {
|
|
95
|
+
res(manifest);
|
|
96
|
+
});
|
|
97
|
+
}));
|
|
98
|
+
this._manifestFetcher.start();
|
|
161
99
|
this._initCanceller.signal.register(() => {
|
|
162
|
-
|
|
163
|
-
this._settings.coreInterface.removeMessageListener(onmessage);
|
|
164
|
-
this._settings.coreInterface.removeErrorListener(onmessageerror);
|
|
100
|
+
this._manifestFetcher.dispose();
|
|
165
101
|
});
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* @param {HTMLMediaElement} mediaElement
|
|
105
|
+
* @param {Object} playbackObserver
|
|
106
|
+
*/
|
|
107
|
+
start(mediaElement, playbackObserver) {
|
|
108
|
+
this.prepare(); // Load Manifest if not already done
|
|
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);
|
|
173
115
|
});
|
|
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 });
|
|
180
116
|
}
|
|
181
117
|
/**
|
|
182
118
|
* Update URL of the Manifest.
|
|
@@ -186,1068 +122,275 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
186
122
|
* DASH's MPD) will be refreshed immediately.
|
|
187
123
|
*/
|
|
188
124
|
updateContentUrls(urls, refreshNow) {
|
|
189
|
-
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
this._settings.coreInterface.sendMessage({
|
|
193
|
-
type: "urls-update" /* MainThreadMessageType.ContentUrlsUpdate */,
|
|
194
|
-
contentId: this._currentContentInfo.contentId,
|
|
195
|
-
value: { urls, refreshNow },
|
|
196
|
-
});
|
|
125
|
+
this._manifestFetcher.updateContentUrls(urls, refreshNow);
|
|
197
126
|
}
|
|
198
127
|
/**
|
|
199
|
-
*
|
|
200
|
-
*
|
|
128
|
+
* Stop content and free all resources linked to this
|
|
129
|
+
* `MediaSourceContentInitializer`.
|
|
201
130
|
*/
|
|
202
|
-
|
|
203
|
-
this.
|
|
131
|
+
dispose() {
|
|
132
|
+
this._initCanceller.cancel();
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Callback called when an error interrupting playback arised.
|
|
136
|
+
* @param {*} err
|
|
137
|
+
*/
|
|
138
|
+
_onFatalError(err) {
|
|
204
139
|
if (this._initCanceller.isUsed()) {
|
|
205
140
|
return;
|
|
206
141
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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) {
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
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) {
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
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;
|
|
548
|
-
}
|
|
549
|
-
else {
|
|
550
|
-
wantedSeekingTime = currentTime + relativeResumingPosition;
|
|
551
|
-
}
|
|
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;
|
|
565
|
-
}
|
|
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
|
-
},
|
|
720
|
-
});
|
|
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;
|
|
751
|
-
}
|
|
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,
|
|
767
|
-
});
|
|
768
|
-
return;
|
|
769
|
-
}
|
|
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) {
|
|
142
|
+
this._initCanceller.cancel();
|
|
143
|
+
this.trigger("error", err);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Initialize decryption mechanisms if needed and begin creating and relying
|
|
147
|
+
* on the initial `MediaSourceInterface` for this content.
|
|
148
|
+
* @param {HTMLMediaElement|null} mediaElement
|
|
149
|
+
* @returns {Promise.<Object>}
|
|
150
|
+
*/
|
|
151
|
+
_setupInitialMediaSourceAndDecryption(mediaElement) {
|
|
152
|
+
const initCanceller = this._initCanceller;
|
|
153
|
+
return createCancellablePromise(initCanceller.signal, (resolve) => {
|
|
154
|
+
const { keySystems } = this._initSettings;
|
|
155
|
+
/** Initialize decryption capabilities. */
|
|
156
|
+
const { statusRef: drmInitRef, contentDecryptor } = initializeContentDecryption(mediaElement, keySystems, {
|
|
157
|
+
onWarning: (err) => this.trigger("warning", err),
|
|
158
|
+
onError: (err) => this._onFatalError(err),
|
|
159
|
+
onBlackListProtectionData: (val) => {
|
|
160
|
+
// Ugly IIFE workaround to allow async event listener
|
|
161
|
+
(async () => {
|
|
162
|
+
var _a;
|
|
163
|
+
if (this._manifest === null) {
|
|
866
164
|
return;
|
|
867
165
|
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
166
|
+
const manifest = (_a = this._manifest.syncValue) !== null && _a !== void 0 ? _a : (await this._manifest.getValueAsAsync());
|
|
167
|
+
blackListProtectionDataOnManifest(manifest, val);
|
|
168
|
+
})().catch(noop);
|
|
169
|
+
},
|
|
170
|
+
onKeyIdsCompatibilityUpdate: (updates) => {
|
|
171
|
+
// Ugly IIFE workaround to allow async event listener
|
|
172
|
+
(async () => {
|
|
173
|
+
var _a;
|
|
174
|
+
if (this._manifest === null) {
|
|
874
175
|
return;
|
|
875
176
|
}
|
|
876
|
-
const
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
playbackObserver.setCurrentTime(currentPosition);
|
|
177
|
+
const manifest = (_a = this._manifest.syncValue) !== null && _a !== void 0 ? _a : (await this._manifest.getValueAsAsync());
|
|
178
|
+
updateKeyIdsDecipherabilityOnManifest(manifest, updates.whitelistedKeyIds, updates.blacklistedKeyIds, updates.delistedKeyIds);
|
|
179
|
+
})().catch(noop);
|
|
180
|
+
},
|
|
181
|
+
onCodecSupportUpdate: () => {
|
|
182
|
+
var _a, _b;
|
|
183
|
+
const syncManifest = (_a = this._manifest) === null || _a === void 0 ? void 0 : _a.syncValue;
|
|
184
|
+
if (isNullOrUndefined(syncManifest)) {
|
|
185
|
+
// The Manifest is not yet fetched, but we will be able to check
|
|
186
|
+
// the codecs once it is the case
|
|
187
|
+
(_b = this._manifest) === null || _b === void 0 ? void 0 : _b.getValueAsAsync().then((loadedManifest) => {
|
|
188
|
+
if (this._initCanceller.isUsed()) {
|
|
189
|
+
return;
|
|
890
190
|
}
|
|
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);
|
|
191
|
+
this._refreshManifestCodecSupport(loadedManifest, mediaElement);
|
|
192
|
+
}, noop);
|
|
901
193
|
}
|
|
902
194
|
else {
|
|
903
|
-
|
|
195
|
+
this._refreshManifestCodecSupport(syncManifest, mediaElement);
|
|
904
196
|
}
|
|
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
197
|
},
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
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();
|
|
198
|
+
}, initCanceller.signal);
|
|
199
|
+
if (contentDecryptor.enabled) {
|
|
200
|
+
this._decryptionCapabilities = {
|
|
201
|
+
status: "enabled",
|
|
202
|
+
value: contentDecryptor.value,
|
|
203
|
+
};
|
|
1060
204
|
}
|
|
1061
205
|
else {
|
|
1062
|
-
this.
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
representationUniqueId: s.representation.uniqueId,
|
|
1067
|
-
decipherable: s.representation.decipherable,
|
|
1068
|
-
})),
|
|
1069
|
-
});
|
|
206
|
+
this._decryptionCapabilities = {
|
|
207
|
+
status: "disabled",
|
|
208
|
+
value: contentDecryptor.value,
|
|
209
|
+
};
|
|
1070
210
|
}
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
211
|
+
drmInitRef.onUpdate((drmStatus, stopListeningToDrmUpdates) => {
|
|
212
|
+
if (drmStatus.initializationState.type === "uninitialized") {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
stopListeningToDrmUpdates();
|
|
216
|
+
const mediaSourceCanceller = new TaskCanceller();
|
|
217
|
+
mediaSourceCanceller.linkToSignal(initCanceller.signal);
|
|
218
|
+
createMediaSource(mediaElement, mediaSourceCanceller.signal)
|
|
219
|
+
.then((mediaSource) => {
|
|
220
|
+
const lastDrmStatus = drmInitRef.getValue();
|
|
221
|
+
if (lastDrmStatus.initializationState.type === "awaiting-media-link") {
|
|
222
|
+
lastDrmStatus.initializationState.value.isMediaLinked.setValue(true);
|
|
223
|
+
drmInitRef.onUpdate((newDrmStatus, stopListeningToDrmUpdatesAgain) => {
|
|
224
|
+
if (newDrmStatus.initializationState.type === "initialized") {
|
|
225
|
+
stopListeningToDrmUpdatesAgain();
|
|
226
|
+
resolve({
|
|
227
|
+
mediaSource,
|
|
228
|
+
drmSystemId: newDrmStatus.drmSystemId,
|
|
229
|
+
unlinkMediaSource: mediaSourceCanceller,
|
|
230
|
+
});
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
}, { emitCurrentValue: true, clearSignal: initCanceller.signal });
|
|
234
|
+
}
|
|
235
|
+
else if (drmStatus.initializationState.type === "initialized") {
|
|
236
|
+
resolve({
|
|
237
|
+
mediaSource,
|
|
238
|
+
drmSystemId: drmStatus.drmSystemId,
|
|
239
|
+
unlinkMediaSource: mediaSourceCanceller,
|
|
240
|
+
});
|
|
241
|
+
return;
|
|
1078
242
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
}
|
|
243
|
+
})
|
|
244
|
+
.catch((err) => {
|
|
245
|
+
if (mediaSourceCanceller.isUsed()) {
|
|
246
|
+
return;
|
|
1084
247
|
}
|
|
1085
|
-
|
|
1086
|
-
}
|
|
1087
|
-
else if (state === ContentDecryptorState.ReadyForContent) {
|
|
1088
|
-
drmStatusRef.setValue({
|
|
1089
|
-
initializationState: { type: "initialized", value: null },
|
|
1090
|
-
drmSystemId: contentDecryptor.systemId,
|
|
248
|
+
this._onFatalError(err);
|
|
1091
249
|
});
|
|
1092
|
-
|
|
1093
|
-
}
|
|
1094
|
-
});
|
|
1095
|
-
contentDecryptor.addEventListener("error", (error) => {
|
|
1096
|
-
this._onFatalError(error);
|
|
1097
|
-
});
|
|
1098
|
-
contentDecryptor.addEventListener("warning", (error) => {
|
|
1099
|
-
this.trigger("warning", error);
|
|
250
|
+
}, { emitCurrentValue: true, clearSignal: initCanceller.signal });
|
|
1100
251
|
});
|
|
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 };
|
|
1111
252
|
}
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
_updateCodecSupport(manifest, mediaElement) {
|
|
1119
|
-
var _a, _b, _c, _d;
|
|
253
|
+
async _onInitialMediaSourceReady(mediaElement, initialMediaSource, playbackObserver, drmSystemId, initialMediaSourceCanceller) {
|
|
254
|
+
var _a;
|
|
255
|
+
const { adaptiveOptions, autoPlay, bufferOptions, lowLatencyMode, segmentRequestOptions, speed, startAt, textTrackOptions, transport, } = this._initSettings;
|
|
256
|
+
const initCanceller = this._initCanceller;
|
|
257
|
+
assert(this._manifest !== null);
|
|
258
|
+
let manifest;
|
|
1120
259
|
try {
|
|
1121
|
-
|
|
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
|
-
}
|
|
260
|
+
manifest = (_a = this._manifest.syncValue) !== null && _a !== void 0 ? _a : (await this._manifest.getValueAsAsync());
|
|
1131
261
|
}
|
|
1132
|
-
catch (
|
|
1133
|
-
|
|
262
|
+
catch (_e) {
|
|
263
|
+
return; // The error should already have been processed through an event listener
|
|
264
|
+
}
|
|
265
|
+
manifest.addEventListener("manifestUpdate", (updates) => {
|
|
266
|
+
this.trigger("manifestUpdate", updates);
|
|
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;
|
|
1134
287
|
}
|
|
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);
|
|
1135
302
|
}
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
303
|
+
/**
|
|
304
|
+
* Load the content defined by the Manifest in the mediaSource given at the
|
|
305
|
+
* given position and playing status.
|
|
306
|
+
* This function recursively re-call itself when a MediaSource reload is
|
|
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);
|
|
1140
313
|
}
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
314
|
+
/**
|
|
315
|
+
* Create `IReloadMediaSourceCallback` allowing to handle reload orders.
|
|
316
|
+
* @param {Object} args
|
|
317
|
+
* @param {Object} currentCanceller
|
|
318
|
+
*/
|
|
319
|
+
_createReloadMediaSourceCallback(args, currentCanceller) {
|
|
320
|
+
const initCanceller = this._initCanceller;
|
|
321
|
+
return (reloadOrder) => {
|
|
322
|
+
currentCanceller.cancel();
|
|
323
|
+
if (initCanceller.isUsed()) {
|
|
1149
324
|
return;
|
|
1150
325
|
}
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
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
|
-
});
|
|
326
|
+
this.trigger("reloadingMediaSource", reloadOrder);
|
|
327
|
+
if (initCanceller.isUsed()) {
|
|
328
|
+
return;
|
|
1175
329
|
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
330
|
+
const newCanceller = new TaskCanceller();
|
|
331
|
+
newCanceller.linkToSignal(initCanceller.signal);
|
|
332
|
+
createMediaSource(args.mediaElement, newCanceller.signal)
|
|
333
|
+
.then((newMediaSource) => {
|
|
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
|
+
};
|
|
1180
343
|
}
|
|
1181
344
|
/**
|
|
1182
|
-
*
|
|
1183
|
-
*
|
|
1184
|
-
*
|
|
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
|
|
345
|
+
* Buffer the content on the given MediaSource.
|
|
346
|
+
* @param {Object} args
|
|
347
|
+
* @param {function} onReloadOrder
|
|
1190
348
|
* @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).
|
|
1194
349
|
*/
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
350
|
+
_startLoadingContentOnMediaSource(args, onReloadOrder, cancelSignal) {
|
|
351
|
+
var _a, _b;
|
|
352
|
+
const { autoPlay, bufferOptions, initialTime, manifest, mediaElement, mediaSource, playbackObserver, representationEstimator, cdnPrioritizer, segmentQueueCreator, speed, } = args;
|
|
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);
|
|
1202
358
|
}
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
359
|
+
let textDisplayerInterface = null;
|
|
360
|
+
const textDisplayer = createTextDisplayer(mediaElement, this._initSettings.textTrackOptions);
|
|
361
|
+
if (textDisplayer !== null) {
|
|
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
|
+
});
|
|
1206
368
|
}
|
|
1207
|
-
|
|
1208
|
-
const
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
369
|
+
/** Interface to create media buffers. */
|
|
370
|
+
const segmentSinksStore = new SegmentSinksStore(mediaSource, mediaElement.nodeName === "VIDEO", textDisplayerInterface);
|
|
371
|
+
cancelSignal.register(() => {
|
|
372
|
+
segmentSinksStore.disposeAll();
|
|
373
|
+
});
|
|
1212
374
|
const { autoPlayResult, initialPlayPerformed } = performInitialSeekAndPlay({
|
|
1213
375
|
mediaElement,
|
|
1214
376
|
playbackObserver,
|
|
1215
377
|
startTime: initialTime,
|
|
1216
378
|
mustAutoPlay: autoPlay,
|
|
1217
|
-
onWarning: (err) =>
|
|
379
|
+
onWarning: (err) => {
|
|
380
|
+
this.trigger("warning", err);
|
|
381
|
+
},
|
|
1218
382
|
isDirectfile: false,
|
|
1219
383
|
}, 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);
|
|
1229
384
|
if (cancelSignal.isCancelled()) {
|
|
1230
|
-
return
|
|
385
|
+
return;
|
|
1231
386
|
}
|
|
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;
|
|
1246
387
|
initialPlayPerformed.onUpdate((isPerformed, stopListening) => {
|
|
1247
388
|
if (isPerformed) {
|
|
1248
389
|
stopListening();
|
|
1249
390
|
const streamEventsEmitter = new StreamEventsEmitter(manifest, playbackObserver);
|
|
1250
|
-
|
|
391
|
+
manifest.addEventListener("manifestUpdate", () => {
|
|
392
|
+
streamEventsEmitter.onManifestUpdate(manifest);
|
|
393
|
+
}, cancelSignal);
|
|
1251
394
|
streamEventsEmitter.addEventListener("event", (payload) => {
|
|
1252
395
|
this.trigger("streamEvent", payload);
|
|
1253
396
|
}, cancelSignal);
|
|
@@ -1260,62 +403,59 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
1260
403
|
});
|
|
1261
404
|
}
|
|
1262
405
|
}, { clearSignal: cancelSignal, emitCurrentValue: true });
|
|
1263
|
-
const
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
});
|
|
1285
|
-
}
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
406
|
+
const coreObserver = createCorePlaybackObserver(playbackObserver, {
|
|
407
|
+
autoPlay,
|
|
408
|
+
manifest,
|
|
409
|
+
mediaSource,
|
|
410
|
+
textDisplayer,
|
|
411
|
+
initialPlayPerformed,
|
|
412
|
+
speed,
|
|
413
|
+
}, cancelSignal);
|
|
414
|
+
(_b = this._cmcdDataBuilder) === null || _b === void 0 ? void 0 : _b.startMonitoringPlayback(coreObserver);
|
|
415
|
+
cancelSignal.register(() => {
|
|
416
|
+
var _a;
|
|
417
|
+
(_a = this._cmcdDataBuilder) === null || _a === void 0 ? void 0 : _a.stopMonitoringPlayback();
|
|
418
|
+
});
|
|
419
|
+
const rebufferingController = this._createRebufferingController(playbackObserver, manifest, speed, cancelSignal);
|
|
420
|
+
const freezeResolver = new FreezeResolver(segmentSinksStore);
|
|
421
|
+
if (mayMediaElementFailOnUndecipherableData()) {
|
|
422
|
+
// On some devices, just reload immediately when data become undecipherable
|
|
423
|
+
manifest.addEventListener("decipherabilityUpdate", (elts) => {
|
|
424
|
+
if (elts.some((e) => e.representation.decipherable !== true)) {
|
|
425
|
+
reloadMediaSource(0, undefined, undefined);
|
|
426
|
+
}
|
|
427
|
+
}, cancelSignal);
|
|
428
|
+
}
|
|
429
|
+
coreObserver.listen((observation) => {
|
|
430
|
+
synchronizeSegmentSinksOnObservation(observation, segmentSinksStore);
|
|
431
|
+
const freezeResolution = freezeResolver.onNewObservation(observation);
|
|
432
|
+
if (freezeResolution === null) {
|
|
433
|
+
return;
|
|
1289
434
|
}
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
const
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
};
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
cleanUp();
|
|
1309
|
-
resolve(value);
|
|
1310
|
-
},
|
|
1311
|
-
reject: (value) => {
|
|
1312
|
-
cleanUp();
|
|
1313
|
-
reject(value);
|
|
1314
|
-
},
|
|
1315
|
-
});
|
|
1316
|
-
cancelSignal.register(rejectFn);
|
|
435
|
+
// TODO: The following method looks generic, we may be able to factorize
|
|
436
|
+
// it with other reload handlers after some work.
|
|
437
|
+
const triggerReload = () => {
|
|
438
|
+
var _a;
|
|
439
|
+
const lastObservation = playbackObserver.getReference().getValue();
|
|
440
|
+
const position = lastObservation.position.isAwaitingFuturePosition()
|
|
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,
|
|
1317
453
|
});
|
|
1318
|
-
};
|
|
454
|
+
}, { clearSignal: cancelSignal });
|
|
455
|
+
const contentTimeBoundariesObserver = createContentTimeBoundariesObserver(manifest, mediaSource, coreObserver, segmentSinksStore, {
|
|
456
|
+
onWarning: (err) => this.trigger("warning", err),
|
|
457
|
+
onPeriodChanged: (period) => this.trigger("activePeriodChanged", { period }),
|
|
458
|
+
}, cancelSignal);
|
|
1319
459
|
/**
|
|
1320
460
|
* Emit a "loaded" events once the initial play has been performed and the
|
|
1321
461
|
* media can begin playback.
|
|
@@ -1325,237 +465,452 @@ export default class MediaSourceContentInitializer extends ContentInitializer {
|
|
|
1325
465
|
.then(() => {
|
|
1326
466
|
getLoadedReference(playbackObserver, false, cancelSignal).onUpdate((isLoaded, stopListening) => {
|
|
1327
467
|
if (isLoaded) {
|
|
468
|
+
const fetchThumbnails = createThumbnailFetcher(transport.thumbnails, cdnPrioritizer);
|
|
1328
469
|
stopListening();
|
|
1329
470
|
this.trigger("loaded", {
|
|
1330
|
-
getSegmentSinkMetrics:
|
|
1331
|
-
|
|
471
|
+
getSegmentSinkMetrics: async () => {
|
|
472
|
+
return new Promise((resolve) => resolve(segmentSinksStore.getSegmentSinksMetrics()));
|
|
473
|
+
},
|
|
474
|
+
getThumbnailData: async (periodId, thumbnailTrackId, time) => {
|
|
475
|
+
return getThumbnailData(fetchThumbnails, manifest, periodId, thumbnailTrackId, time);
|
|
476
|
+
},
|
|
1332
477
|
});
|
|
1333
478
|
}
|
|
1334
479
|
}, { emitCurrentValue: true, clearSignal: cancelSignal });
|
|
1335
480
|
})
|
|
1336
481
|
.catch((err) => {
|
|
1337
482
|
if (cancelSignal.isCancelled()) {
|
|
1338
|
-
return;
|
|
483
|
+
return; // Current loading cancelled, no need to trigger the error
|
|
1339
484
|
}
|
|
1340
485
|
this._onFatalError(err);
|
|
1341
486
|
});
|
|
1342
|
-
|
|
487
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
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
|
+
}
|
|
1343
685
|
}
|
|
1344
686
|
/**
|
|
1345
|
-
*
|
|
1346
|
-
*
|
|
1347
|
-
* - `drmInitializationStatus` indicates that DRM matters are initialized.
|
|
1348
|
-
* - `mediaSourceStatus` indicates that the MediaSource is attached to the
|
|
1349
|
-
* `mediaElement`.
|
|
687
|
+
* Creates a `RebufferingController`, a class trying to avoid various stalling
|
|
688
|
+
* situations (such as rebuffering periods), and returns it.
|
|
1350
689
|
*
|
|
1351
|
-
*
|
|
690
|
+
* Various methods from that class need then to be called at various events
|
|
691
|
+
* (see `RebufferingController` definition).
|
|
1352
692
|
*
|
|
1353
|
-
*
|
|
1354
|
-
*
|
|
693
|
+
* This function also handles the `RebufferingController`'s events:
|
|
694
|
+
* - emit "stalled" events when stalling situations cannot be prevented,
|
|
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.
|
|
1355
716
|
*
|
|
1356
|
-
* @param {
|
|
1357
|
-
* @returns {
|
|
1358
|
-
* playback start.
|
|
717
|
+
* @param {Array} codecsToCheck - The list of codecs to check.
|
|
718
|
+
* @returns {Array} - The list of evaluated codecs with their support status updated.
|
|
1359
719
|
*/
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
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,
|
|
720
|
+
getCodecsSupportInfo(codecsToCheck, mediaElement) {
|
|
721
|
+
const codecsSupportInfo = codecsToCheck.map((codecToCheck) => {
|
|
722
|
+
var _a;
|
|
723
|
+
const inputCodec = `${codecToCheck.mimeType};codecs="${codecToCheck.codec}"`;
|
|
724
|
+
const isSupported = isCodecSupported(mediaElement, inputCodec);
|
|
725
|
+
if (!isSupported) {
|
|
726
|
+
return {
|
|
727
|
+
mimeType: codecToCheck.mimeType,
|
|
728
|
+
codec: codecToCheck.codec,
|
|
729
|
+
supported: false,
|
|
730
|
+
supportedIfEncrypted: false,
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* `true` if the codec is supported when encrypted, `false` if it is not
|
|
735
|
+
* supported, or `undefined` if we cannot obtain that information.
|
|
736
|
+
*/
|
|
737
|
+
let supportedIfEncrypted;
|
|
738
|
+
if (this._decryptionCapabilities.status === "uninitialized") {
|
|
739
|
+
supportedIfEncrypted = undefined;
|
|
740
|
+
}
|
|
741
|
+
else if (this._decryptionCapabilities.status === "disabled") {
|
|
742
|
+
// It's ambiguous here, but let's say that no ContentDecryptor means that
|
|
743
|
+
// the codec is supported by it.
|
|
744
|
+
supportedIfEncrypted = true;
|
|
745
|
+
}
|
|
746
|
+
else {
|
|
747
|
+
const contentDecryptor = this._decryptionCapabilities.value;
|
|
748
|
+
if (contentDecryptor.getState() !== ContentDecryptorState.Initializing) {
|
|
749
|
+
// No information is available regarding the support status.
|
|
750
|
+
// Defaulting to assume the codec is supported.
|
|
751
|
+
supportedIfEncrypted =
|
|
752
|
+
(_a = contentDecryptor.isCodecSupported(codecToCheck.mimeType, codecToCheck.codec)) !== null && _a !== void 0 ? _a : true;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
return {
|
|
756
|
+
mimeType: codecToCheck.mimeType,
|
|
757
|
+
codec: codecToCheck.codec,
|
|
758
|
+
supported: isSupported,
|
|
759
|
+
supportedIfEncrypted,
|
|
760
|
+
};
|
|
1411
761
|
});
|
|
1412
|
-
|
|
1413
|
-
return true;
|
|
762
|
+
return codecsSupportInfo;
|
|
1414
763
|
}
|
|
1415
764
|
/**
|
|
1416
|
-
*
|
|
1417
|
-
*
|
|
1418
|
-
*
|
|
1419
|
-
*
|
|
1420
|
-
* @param {Object}
|
|
765
|
+
* Update the support status of all Representations in the Manifest.
|
|
766
|
+
*
|
|
767
|
+
* To call anytime either the Manifest is linked to new codecs or new means
|
|
768
|
+
* to test for codec support are available.
|
|
769
|
+
* @param {Object} manifest
|
|
1421
770
|
*/
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
}
|
|
1427
|
-
else {
|
|
1428
|
-
const { mediaSourceId } = msg;
|
|
771
|
+
_refreshManifestCodecSupport(manifest, mediaElement) {
|
|
772
|
+
const codecsToTest = manifest.getCodecsWithUnknownSupport();
|
|
773
|
+
const codecsSupportInfo = this.getCodecsSupportInfo(codecsToTest, mediaElement);
|
|
774
|
+
if (codecsSupportInfo.length > 0) {
|
|
1429
775
|
try {
|
|
1430
|
-
|
|
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
|
-
});
|
|
776
|
+
manifest.updateCodecSupport(codecsSupportInfo);
|
|
1488
777
|
}
|
|
1489
|
-
catch (
|
|
1490
|
-
|
|
1491
|
-
this._onFatalError(error);
|
|
778
|
+
catch (err) {
|
|
779
|
+
this._onFatalError(err);
|
|
1492
780
|
}
|
|
1493
781
|
}
|
|
1494
782
|
}
|
|
1495
783
|
}
|
|
1496
|
-
function
|
|
1497
|
-
|
|
1498
|
-
|
|
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");
|
|
784
|
+
function createTextDisplayer(mediaElement, textTrackOptions) {
|
|
785
|
+
if (textTrackOptions.textTrackMode === "html" && features.htmlTextDisplayer !== null) {
|
|
786
|
+
return new features.htmlTextDisplayer(mediaElement, textTrackOptions.textTrackElement);
|
|
1537
787
|
}
|
|
1538
|
-
else {
|
|
1539
|
-
return new
|
|
788
|
+
else if (features.nativeTextDisplayer !== null) {
|
|
789
|
+
return new features.nativeTextDisplayer(mediaElement);
|
|
1540
790
|
}
|
|
791
|
+
return null;
|
|
1541
792
|
}
|
|
1542
793
|
/**
|
|
1543
|
-
*
|
|
1544
|
-
*
|
|
1545
|
-
*
|
|
794
|
+
* Change the decipherability of Representations which have their key id in one
|
|
795
|
+
* of the given Arrays:
|
|
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`
|
|
1546
802
|
*
|
|
1547
|
-
*
|
|
1548
|
-
*
|
|
803
|
+
* - Those who have a key id listed in `delistedKeyIds` will have their
|
|
804
|
+
* decipherability updated to `undefined`.
|
|
1549
805
|
*
|
|
1550
|
-
* @param {
|
|
1551
|
-
* @
|
|
806
|
+
* @param {Object} manifest
|
|
807
|
+
* @param {Array.<Uint8Array>} whitelistedKeyIds
|
|
808
|
+
* @param {Array.<Uint8Array>} blacklistedKeyIds
|
|
809
|
+
* @param {Array.<Uint8Array>} delistedKeyIds
|
|
1552
810
|
*/
|
|
1553
|
-
function
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
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
|
|
845
|
+
*/
|
|
846
|
+
function blackListProtectionDataOnManifest(manifest, initData) {
|
|
847
|
+
manifest.updateRepresentationsDeciperability((ctx) => {
|
|
848
|
+
var _a, _b;
|
|
849
|
+
const rep = ctx.representation;
|
|
850
|
+
if (rep.decipherable === false) {
|
|
851
|
+
return false;
|
|
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);
|
|
1559
915
|
}
|
|
1560
|
-
return arg;
|
|
1561
916
|
}
|