shaka-player 3.3.2 → 4.0.0

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.
Files changed (389) hide show
  1. package/.csslintrc +11 -1
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  3. package/.github/pull_request_template.md +6 -34
  4. package/.github/workflows/build-and-test.yaml +129 -0
  5. package/.github/workflows/custom-actions/prep-for-appspot/action.yaml +56 -0
  6. package/.github/workflows/custom-actions/set-commit-status/action.yaml +41 -0
  7. package/.github/workflows/demo-version-index.yaml +37 -0
  8. package/.github/workflows/nightly-demo.yaml +42 -0
  9. package/.github/workflows/release-please.yaml +168 -0
  10. package/.github/workflows/safari-homedir-launcher.sh +18 -0
  11. package/.github/workflows/selenium-lab-tests.yaml +92 -0
  12. package/.github/workflows/sync-labels.yaml +33 -0
  13. package/.github/workflows/update-issues.yaml +29 -0
  14. package/.github/workflows/validate-pr-title.yaml +35 -0
  15. package/AUTHORS +3 -0
  16. package/CHANGELOG.md +1866 -1675
  17. package/CONTRIBUTING.md +2 -2
  18. package/CONTRIBUTORS +3 -0
  19. package/README.md +16 -13
  20. package/app-engine/README.md +9 -0
  21. package/app-engine/demo-version-index/README.md +14 -0
  22. package/app-engine/demo-version-index/app.yaml +28 -0
  23. package/app-engine/demo-version-index/generate.py +164 -0
  24. package/app-engine/demo-version-index/main.py +11 -0
  25. package/app-engine/demo-version-index/requirements.txt +5 -0
  26. package/app-engine/demo-version-index/templates/index.html +114 -0
  27. package/app-engine/shaka-player-demo/README.md +18 -0
  28. package/app-engine/shaka-player-demo/app.yaml +61 -0
  29. package/app-engine/shaka-player-demo/main.py +95 -0
  30. package/app-engine/shaka-player-demo/posters/10yo.png +0 -0
  31. package/app-engine/shaka-player-demo/posters/10yo.xcf +0 -0
  32. package/app-engine/shaka-player-demo/posters/1yo.jpg +0 -0
  33. package/app-engine/shaka-player-demo/posters/2yo.png +0 -0
  34. package/app-engine/shaka-player-demo/posters/2yo.xcf +0 -0
  35. package/app-engine/shaka-player-demo/posters/3yo.png +0 -0
  36. package/app-engine/shaka-player-demo/posters/3yo.xcf +0 -0
  37. package/app-engine/shaka-player-demo/posters/4yo.png +0 -0
  38. package/app-engine/shaka-player-demo/posters/4yo.xcf +0 -0
  39. package/app-engine/shaka-player-demo/posters/5yo.png +0 -0
  40. package/app-engine/shaka-player-demo/posters/5yo.xcf +0 -0
  41. package/app-engine/shaka-player-demo/posters/6yo.png +0 -0
  42. package/app-engine/shaka-player-demo/posters/6yo.xcf +0 -0
  43. package/app-engine/shaka-player-demo/posters/7yo.png +0 -0
  44. package/app-engine/shaka-player-demo/posters/7yo.xcf +0 -0
  45. package/app-engine/shaka-player-demo/posters/8yo.png +0 -0
  46. package/app-engine/shaka-player-demo/posters/8yo.xcf +0 -0
  47. package/app-engine/shaka-player-demo/posters/9yo.png +0 -0
  48. package/app-engine/shaka-player-demo/posters/9yo.xcf +0 -0
  49. package/app-engine/shaka-player-demo/posters/audioOnly.gif +0 -0
  50. package/app-engine/shaka-player-demo/posters/audioRickRoll.gif +0 -0
  51. package/app-engine/shaka-player-demo/posters/colorbars.gif +0 -0
  52. package/app-engine/shaka-player-demo/posters/fireworks.jpg +0 -0
  53. package/app-engine/shaka-player-demo/posters/party-hat.png +0 -0
  54. package/app-engine/shaka-player-demo/posters/sources.txt +46 -0
  55. package/app-engine/shaka-player-demo/posters/standard.png +0 -0
  56. package/app-engine/shaka-player-demo/posters/trek.jpg +0 -0
  57. package/app-engine/shaka-player-demo/posters/valentines.png +0 -0
  58. package/app-engine/shaka-player-demo/posters/zombie.jpg +0 -0
  59. package/app-engine/shaka-player-demo/posters.py +110 -0
  60. package/app-engine/shaka-player-demo/requirements.txt +5 -0
  61. package/app-engine/shaka-player-demo/time.txt +1 -0
  62. package/build/README.md +3 -3
  63. package/build/checkversion.py +1 -1
  64. package/build/compiler.py +1 -1
  65. package/build/conformance.textproto +13 -0
  66. package/build/docker/Dockerfile +20 -0
  67. package/build/docker/docker-compose.yml +10 -0
  68. package/build/gendeps.py +18 -15
  69. package/build/shaka-lab.yaml +161 -0
  70. package/build/shakaBuildHelpers.py +4 -29
  71. package/build/test.py +94 -29
  72. package/build/types/core +0 -1
  73. package/build/types/polyfill +1 -3
  74. package/build/wrapper.template.js +2 -2
  75. package/demo/TengwarTelcontar.woff2 +0 -0
  76. package/demo/asset_card.js +1 -2
  77. package/demo/cast_receiver/index.html +1 -1
  78. package/demo/cast_receiver/receiver_app.css +14 -14
  79. package/demo/common/asset.js +17 -1
  80. package/demo/common/assets.js +31 -0
  81. package/demo/common/message_ids.js +6 -3
  82. package/demo/config.js +10 -12
  83. package/demo/custom.js +39 -1
  84. package/demo/customWarning.txt +2 -2
  85. package/demo/demo.less +29 -18
  86. package/demo/demo_uncompiled.js +1 -13
  87. package/demo/demo_utils.js +0 -1
  88. package/demo/index.html +1 -1
  89. package/demo/locales/en.json +6 -3
  90. package/demo/locales/source.json +22 -10
  91. package/demo/main.js +12 -9
  92. package/demo/search.js +2 -1
  93. package/dist/controls.css +3 -3
  94. package/dist/controls.css.map +1 -1
  95. package/dist/demo.compiled.debug.js +236 -232
  96. package/dist/demo.compiled.debug.map +4 -4
  97. package/dist/demo.compiled.js +236 -232
  98. package/dist/demo.compiled.map +4 -4
  99. package/dist/demo.css +1 -1
  100. package/dist/demo.css.map +1 -1
  101. package/dist/deps.js +229 -226
  102. package/dist/locales.js +34 -32
  103. package/dist/receiver.compiled.debug.js +75 -73
  104. package/dist/receiver.compiled.debug.map +4 -4
  105. package/dist/receiver.compiled.js +75 -73
  106. package/dist/receiver.compiled.map +4 -4
  107. package/dist/shaka-player.compiled.d.ts +321 -314
  108. package/dist/shaka-player.compiled.debug.d.ts +321 -314
  109. package/dist/shaka-player.compiled.debug.externs.js +140 -129
  110. package/dist/shaka-player.compiled.debug.js +527 -592
  111. package/dist/shaka-player.compiled.debug.map +4 -4
  112. package/dist/shaka-player.compiled.externs.js +140 -129
  113. package/dist/shaka-player.compiled.js +836 -860
  114. package/dist/shaka-player.compiled.map +4 -4
  115. package/dist/shaka-player.ui.d.ts +367 -358
  116. package/dist/shaka-player.ui.debug.d.ts +367 -358
  117. package/dist/shaka-player.ui.debug.externs.js +148 -129
  118. package/dist/shaka-player.ui.debug.js +586 -649
  119. package/dist/shaka-player.ui.debug.map +4 -4
  120. package/dist/shaka-player.ui.externs.js +148 -129
  121. package/dist/shaka-player.ui.js +1008 -1028
  122. package/dist/shaka-player.ui.map +4 -4
  123. package/docs/design/REDESIGN.md +33 -33
  124. package/docs/design/bg-fetch.md +2 -2
  125. package/docs/design/codec_preferences.md +1 -1
  126. package/docs/design/dash-audio-channels.md +3 -3
  127. package/docs/design/dash-manifests.md +1 -1
  128. package/docs/design/gap-jumping.md +3 -3
  129. package/docs/design/preload.md +2 -2
  130. package/docs/tutorials/config.md +0 -2
  131. package/docs/tutorials/drm-config.md +5 -0
  132. package/docs/tutorials/fairplay.md +7 -22
  133. package/docs/tutorials/faq.md +8 -19
  134. package/docs/tutorials/index.json +3 -8
  135. package/docs/tutorials/plugins.md +4 -6
  136. package/docs/tutorials/selenium-grid-config.md +122 -0
  137. package/docs/tutorials/upgrade.md +83 -11
  138. package/docs/tutorials/welcome.md +10 -2
  139. package/externs/cmcd.js +1 -1
  140. package/externs/polyfill.js +15 -0
  141. package/externs/shaka/manifest.js +5 -1
  142. package/externs/shaka/net.js +12 -0
  143. package/externs/shaka/offline.js +5 -1
  144. package/externs/shaka/player.js +39 -32
  145. package/externs/shaka/text.js +12 -12
  146. package/externs/sourcebuffer.js +15 -0
  147. package/karma.conf.js +137 -30
  148. package/lib/abr/simple_abr_manager.js +12 -6
  149. package/lib/ads/client_side_ad.js +13 -2
  150. package/lib/ads/client_side_ad_manager.js +22 -4
  151. package/lib/cast/cast_proxy.js +3 -4
  152. package/lib/cast/cast_utils.js +0 -1
  153. package/lib/cea/cea608_data_channel.js +2 -2
  154. package/lib/cea/cea708_service.js +5 -4
  155. package/lib/cea/mp4_cea_parser.js +11 -5
  156. package/lib/cea/sei_processor.js +6 -3
  157. package/lib/dash/content_protection.js +85 -5
  158. package/lib/dash/dash_parser.js +10 -12
  159. package/lib/dash/mpd_utils.js +4 -5
  160. package/lib/dash/segment_list.js +1 -2
  161. package/lib/dash/segment_template.js +3 -3
  162. package/lib/hls/hls_parser.js +386 -749
  163. package/lib/hls/manifest_text_parser.js +5 -6
  164. package/lib/media/adaptation_set.js +1 -2
  165. package/lib/media/content_workarounds.js +2 -2
  166. package/lib/media/drm_engine.js +105 -55
  167. package/lib/media/gap_jumping_controller.js +10 -45
  168. package/lib/media/media_source_engine.js +90 -17
  169. package/lib/media/mp4_segment_index_parser.js +1 -4
  170. package/lib/media/playhead.js +4 -7
  171. package/lib/media/presentation_timeline.js +19 -10
  172. package/lib/media/segment_index.js +13 -46
  173. package/lib/media/segment_reference.js +47 -1
  174. package/lib/media/streaming_engine.js +35 -17
  175. package/lib/media/time_ranges_utils.js +5 -12
  176. package/lib/media/video_wrapper.js +1 -1
  177. package/lib/net/networking_engine.js +4 -1
  178. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  179. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  180. package/lib/offline/manifest_converter.js +1 -0
  181. package/lib/offline/storage.js +104 -136
  182. package/lib/player.js +50 -216
  183. package/lib/polyfill/all.js +2 -3
  184. package/lib/polyfill/encryption_scheme.js +1 -1
  185. package/lib/polyfill/media_capabilities.js +15 -9
  186. package/lib/polyfill/mediasource.js +0 -28
  187. package/lib/polyfill/patchedmediakeys_nop.js +2 -0
  188. package/lib/polyfill/patchedmediakeys_webkit.js +2 -0
  189. package/lib/polyfill/symbol.js +46 -0
  190. package/lib/text/cue.js +1 -7
  191. package/lib/text/lrc_text_parser.js +8 -0
  192. package/lib/text/mp4_ttml_parser.js +8 -0
  193. package/lib/text/mp4_vtt_parser.js +8 -0
  194. package/lib/text/sbv_text_parser.js +8 -0
  195. package/lib/text/simple_text_displayer.js +3 -8
  196. package/lib/text/srt_text_parser.js +8 -0
  197. package/lib/text/ssa_text_parser.js +8 -0
  198. package/lib/text/text_engine.js +19 -3
  199. package/lib/text/ttml_text_parser.js +16 -5
  200. package/lib/text/ui_text_displayer.js +2 -8
  201. package/lib/text/vtt_text_parser.js +24 -2
  202. package/lib/text/web_vtt_generator.js +1 -7
  203. package/lib/util/buffer_utils.js +1 -3
  204. package/lib/util/ebml_parser.js +3 -3
  205. package/lib/util/error.js +10 -14
  206. package/lib/util/fairplay_utils.js +109 -0
  207. package/lib/util/functional.js +0 -42
  208. package/lib/util/iterables.js +0 -46
  209. package/lib/util/mime_utils.js +2 -0
  210. package/lib/util/mp4_box_parsers.js +1 -4
  211. package/lib/util/mp4_parser.js +5 -7
  212. package/lib/util/periods.js +10 -11
  213. package/lib/util/platform.js +48 -3
  214. package/lib/util/player_configuration.js +12 -6
  215. package/lib/util/pssh.js +24 -8
  216. package/lib/util/stream_utils.js +96 -25
  217. package/lib/util/string_utils.js +3 -5
  218. package/lib/util/uint8array_utils.js +3 -21
  219. package/lib/util/xml_utils.js +16 -8
  220. package/package.json +61 -36
  221. package/roadmap.md +27 -27
  222. package/shaka-player.uncompiled.js +1 -3
  223. package/test/abr/simple_abr_manager_unit.js +3 -8
  224. package/test/ads/ad_manager_unit.js +0 -6
  225. package/test/cast/cast_proxy_unit.js +0 -8
  226. package/test/cast/cast_receiver_integration.js +1 -18
  227. package/test/cast/cast_receiver_unit.js +1 -9
  228. package/test/cast/cast_sender_unit.js +0 -6
  229. package/test/cast/cast_utils_unit.js +1 -13
  230. package/test/cea/cea608_memory_unit.js +0 -5
  231. package/test/cea/cea708_service_unit.js +0 -7
  232. package/test/cea/cea708_window_unit.js +0 -5
  233. package/test/cea/cea_decoder_unit.js +0 -6
  234. package/test/cea/dtvcc_packet_builder_unit.js +0 -3
  235. package/test/cea/dtvcc_packet_unit.js +0 -5
  236. package/test/cea/mp4_cea_parser_unit.js +0 -4
  237. package/test/dash/dash_parser_content_protection_unit.js +45 -10
  238. package/test/dash/dash_parser_live_unit.js +2 -15
  239. package/test/dash/dash_parser_manifest_unit.js +2 -40
  240. package/test/dash/dash_parser_segment_base_unit.js +1 -8
  241. package/test/dash/dash_parser_segment_list_unit.js +1 -7
  242. package/test/dash/dash_parser_segment_template_unit.js +3 -13
  243. package/test/dash/mpd_utils_unit.js +3 -11
  244. package/test/demo/demo_unit.js +2 -6
  245. package/test/deprecate/enforcer_unit.js +0 -4
  246. package/test/deprecate/version_unit.js +0 -2
  247. package/test/hls/hls_live_unit.js +101 -234
  248. package/test/hls/hls_parser_unit.js +517 -447
  249. package/test/hls/manifest_text_parser_unit.js +0 -10
  250. package/test/media/adaptation_set_criteria_unit.js +3 -7
  251. package/test/media/adaptation_set_unit.js +0 -2
  252. package/test/media/buffering_observer_unit.js +1 -4
  253. package/test/media/closed_caption_parser_unit.js +0 -3
  254. package/test/media/drm_engine_integration.js +2 -15
  255. package/test/media/drm_engine_unit.js +90 -144
  256. package/test/media/manifest_parser_unit.js +0 -4
  257. package/test/media/media_source_engine_integration.js +26 -10
  258. package/test/media/media_source_engine_unit.js +8 -20
  259. package/test/media/mp4_segment_index_parser_unit.js +0 -4
  260. package/test/media/play_rate_controller_unit.js +0 -4
  261. package/test/media/playhead_unit.js +35 -207
  262. package/test/media/presentation_timeline_unit.js +4 -7
  263. package/test/media/quality_observer_unit.js +0 -4
  264. package/test/media/region_observer_unit.js +1 -6
  265. package/test/media/region_timeline_unit.js +0 -3
  266. package/test/media/segment_index_unit.js +15 -31
  267. package/test/media/segment_reference_unit.js +0 -3
  268. package/test/media/stall_detector_unit.js +0 -5
  269. package/test/media/streaming_engine_integration.js +13 -75
  270. package/test/media/streaming_engine_unit.js +14 -37
  271. package/test/media/time_ranges_utils_unit.js +0 -7
  272. package/test/media/transmuxer_integration.js +0 -6
  273. package/test/media/webm_segment_index_parser_unit.js +0 -4
  274. package/test/net/data_uri_plugin_unit.js +0 -7
  275. package/test/net/http_plugin_unit.js +0 -9
  276. package/test/net/networking_engine_unit.js +0 -11
  277. package/test/offline/download_progress_estimator_unit.js +0 -2
  278. package/test/offline/indexeddb_storage_unit.js +0 -6
  279. package/test/offline/manifest_convert_unit.js +34 -12
  280. package/test/offline/offline_integration.js +1 -10
  281. package/test/offline/offline_manifest_parser_unit.js +1 -6
  282. package/test/offline/offline_scheme_unit.js +0 -8
  283. package/test/offline/offline_uri_unit.js +0 -2
  284. package/test/offline/storage_compatibility_unit.js +1 -14
  285. package/test/offline/storage_integration.js +6 -31
  286. package/test/player_external.js +1 -15
  287. package/test/player_integration.js +38 -28
  288. package/test/player_load_graph_integration.js +1 -6
  289. package/test/player_src_equals_external.js +3 -9
  290. package/test/player_src_equals_integration.js +0 -7
  291. package/test/player_unit.js +78 -37
  292. package/test/routing/walker_unit.js +0 -8
  293. package/test/test/assets/large_file.mpd +1 -1
  294. package/test/test/boot.js +75 -22
  295. package/test/test/externs/jasmine.js +2 -2
  296. package/test/test/externs/karma.js +4 -0
  297. package/test/test/namespace.js +10 -0
  298. package/test/test/util/canned_idb.js +0 -8
  299. package/test/test/util/cea_utils.js +0 -6
  300. package/test/test/util/dash_parser_util.js +0 -13
  301. package/test/test/util/fake_ad.js +0 -3
  302. package/test/test/util/fake_ad_manager.js +0 -9
  303. package/test/test/util/fake_demo_main.js +0 -5
  304. package/test/test/util/fake_drm_engine.js +0 -6
  305. package/test/test/util/fake_media_source_engine.js +11 -11
  306. package/test/test/util/fake_networking_engine.js +0 -5
  307. package/test/test/util/fake_text_displayer.js +0 -5
  308. package/test/test/util/indexeddb_utils.js +1 -10
  309. package/test/test/util/jasmine_fetch.js +0 -1
  310. package/test/test/util/loader.js +0 -18
  311. package/test/test/util/manifest_generator.js +12 -15
  312. package/test/test/util/manifest_parser_util.js +4 -7
  313. package/test/test/util/offline_utils.js +1 -5
  314. package/test/test/util/simple_fakes.js +9 -26
  315. package/test/test/util/stream_generator.js +0 -14
  316. package/test/test/util/streaming_engine_util.js +1 -15
  317. package/test/test/util/test_scheme.js +25 -20
  318. package/test/test/util/ttml_utils.js +0 -2
  319. package/test/test/util/ui_utils.js +0 -9
  320. package/test/test/util/util.js +9 -23
  321. package/test/test/util/waiter.js +84 -43
  322. package/test/text/cue_integration.js +2 -6
  323. package/test/text/lrc_text_parser_unit.js +6 -11
  324. package/test/text/mp4_ttml_parser_unit.js +6 -10
  325. package/test/text/mp4_vtt_parser_unit.js +7 -12
  326. package/test/text/sbv_text_parser_unit.js +5 -10
  327. package/test/text/simple_text_displayer_unit.js +1 -8
  328. package/test/text/srt_text_parser_unit.js +5 -10
  329. package/test/text/ssa_text_parser_unit.js +17 -34
  330. package/test/text/text_engine_unit.js +47 -12
  331. package/test/text/text_track_integration.js +0 -2
  332. package/test/text/ttml_text_parser_unit.js +79 -88
  333. package/test/text/ui_text_displayer_unit.js +44 -41
  334. package/test/text/vtt_text_parser_unit.js +55 -66
  335. package/test/text/web_vtt_generator_unit.js +0 -3
  336. package/test/ui/ad_ui_unit.js +0 -11
  337. package/test/ui/localization_unit.js +0 -3
  338. package/test/ui/text_displayer_layout_unit.js +1 -12
  339. package/test/ui/ui_customization_unit.js +0 -6
  340. package/test/ui/ui_integration.js +0 -32
  341. package/test/ui/ui_unit.js +28 -17
  342. package/test/util/abortable_operation_unit.js +4 -9
  343. package/test/util/array_utils_unit.js +0 -2
  344. package/test/util/buffer_utils_unit.js +0 -2
  345. package/test/util/cmcd_manager_unit.js +3 -3
  346. package/test/util/data_view_reader_unit.js +0 -4
  347. package/test/util/ebml_parser_unit.js +0 -4
  348. package/test/util/event_manager_unit.js +0 -3
  349. package/test/util/fake_event_target_unit.js +0 -5
  350. package/test/util/iterables_unit.js +0 -64
  351. package/test/util/language_utils_unit.js +0 -3
  352. package/test/util/manifest_parser_utils_unit.js +0 -2
  353. package/test/util/mp4_box_parsers_unit.js +0 -5
  354. package/test/util/mp4_parser_unit.js +0 -4
  355. package/test/util/multi_map_unit.js +0 -3
  356. package/test/util/object_utils_unit.js +0 -2
  357. package/test/util/periods_unit.js +14 -7
  358. package/test/util/pssh_unit.js +0 -5
  359. package/test/util/state_history_unit.js +0 -2
  360. package/test/util/stream_utils_unit.js +26 -15
  361. package/test/util/string_utils_unit.js +0 -6
  362. package/test/util/text_parser_unit.js +0 -2
  363. package/test/util/xml_utils_unit.js +0 -4
  364. package/ui/controls.js +65 -40
  365. package/ui/fullscreen_button.js +26 -6
  366. package/ui/less/ad_controls.less +6 -6
  367. package/ui/less/buttons.less +6 -6
  368. package/ui/less/containers.less +10 -12
  369. package/ui/less/overflow_menu.less +4 -4
  370. package/ui/less/range_elements.less +7 -2
  371. package/ui/less/tooltip.less +4 -4
  372. package/ui/locales/en.json +1 -0
  373. package/ui/locales/sjn-translations.yaml +257 -0
  374. package/ui/locales/sjn.json +42 -0
  375. package/ui/locales/source.json +5 -0
  376. package/ui/resolution_selection.js +31 -33
  377. package/ui/seek_bar.js +2 -1
  378. package/ui/ui.js +0 -17
  379. package/.github/workflows/build_and_test.yaml +0 -73
  380. package/.github/workflows/release.yaml +0 -53
  381. package/docs/tutorials/upgrade-v2-5.md +0 -441
  382. package/docs/tutorials/upgrade-v3.md +0 -38
  383. package/externs/svgelement.js +0 -18
  384. package/externs/webcrypto.js +0 -18
  385. package/lib/polyfill/mathround.js +0 -49
  386. package/lib/polyfill/patchedmediakeys_apple.js +0 -744
  387. package/lib/polyfill/patchedmediakeys_ms.js +0 -698
  388. package/lib/util/mutex.js +0 -52
  389. package/test/util/functional_unit.js +0 -82
@@ -63,9 +63,17 @@ shaka.media.MediaSourceEngine = class {
63
63
  string>} */
64
64
  this.sourceBufferTypes_ = {};
65
65
 
66
+
67
+ /** @private {!Object.<shaka.util.ManifestParserUtils.ContentType,
68
+ boolean>} */
69
+ this.expectedEncryption_ = {};
70
+
66
71
  /** @private {shaka.text.TextEngine} */
67
72
  this.textEngine_ = null;
68
73
 
74
+ /** @private {boolean} */
75
+ this.segmentRelativeVttTiming_ = false;
76
+
69
77
  const onMetadataNoOp = (metadata, timestampOffset, segmentEnd) => {};
70
78
 
71
79
  /** @private {!function(!Array.<shaka.extern.ID3Metadata>,
@@ -196,6 +204,8 @@ shaka.media.MediaSourceEngine = class {
196
204
  // TTML types
197
205
  'application/ttml+xml',
198
206
  'application/mp4; codecs="stpp"',
207
+ // Containerless types
208
+ ...shaka.media.MediaSourceEngine.RAW_FORMATS,
199
209
  ];
200
210
 
201
211
  const support = {};
@@ -310,10 +320,13 @@ shaka.media.MediaSourceEngine = class {
310
320
  * according to MediaSourceEngine.isStreamSupported.
311
321
  * @param {boolean} forceTransmuxTS
312
322
  * If true, this will transmux TS content even if it is natively supported.
323
+ * @param {boolean=} sequenceMode
324
+ * If true, the media segments are appended to the SourceBuffer in strict
325
+ * sequence.
313
326
  *
314
327
  * @return {!Promise}
315
328
  */
316
- async init(streamsByType, forceTransmuxTS) {
329
+ async init(streamsByType, forceTransmuxTS, sequenceMode=false) {
317
330
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
318
331
 
319
332
  await this.mediaSourceOpen_;
@@ -327,7 +340,7 @@ shaka.media.MediaSourceEngine = class {
327
340
  let mimeType = shaka.util.MimeUtils.getFullType(
328
341
  stream.mimeType, stream.codecs);
329
342
  if (contentType == ContentType.TEXT) {
330
- this.reinitText(mimeType);
343
+ this.reinitText(mimeType, sequenceMode);
331
344
  } else {
332
345
  if ((forceTransmuxTS || !MediaSource.isTypeSupported(mimeType)) &&
333
346
  shaka.media.Transmuxer.isSupported(mimeType, contentType)) {
@@ -336,6 +349,10 @@ shaka.media.MediaSourceEngine = class {
336
349
  shaka.media.Transmuxer.convertTsCodecs(contentType, mimeType);
337
350
  }
338
351
  const sourceBuffer = this.mediaSource_.addSourceBuffer(mimeType);
352
+ if (sequenceMode) {
353
+ sourceBuffer.mode =
354
+ shaka.media.MediaSourceEngine.SourceBufferMode_.SEQUENCE;
355
+ }
339
356
  this.eventManager_.listen(
340
357
  sourceBuffer, 'error',
341
358
  () => this.onError_(contentType));
@@ -345,6 +362,7 @@ shaka.media.MediaSourceEngine = class {
345
362
  this.sourceBuffers_[contentType] = sourceBuffer;
346
363
  this.sourceBufferTypes_[contentType] = mimeType;
347
364
  this.queues_[contentType] = [];
365
+ this.expectedEncryption_[contentType] = !!stream.drmInfos.length;
348
366
  }
349
367
  }
350
368
  }
@@ -352,12 +370,14 @@ shaka.media.MediaSourceEngine = class {
352
370
  /**
353
371
  * Reinitialize the TextEngine for a new text type.
354
372
  * @param {string} mimeType
373
+ * @param {boolean} sequenceMode
355
374
  */
356
- reinitText(mimeType) {
375
+ reinitText(mimeType, sequenceMode) {
357
376
  if (!this.textEngine_) {
358
377
  this.textEngine_ = new shaka.text.TextEngine(this.textDisplayer_);
359
378
  }
360
- this.textEngine_.initParser(mimeType);
379
+ this.textEngine_.initParser(mimeType, sequenceMode,
380
+ this.segmentRelativeVttTiming_);
361
381
  }
362
382
 
363
383
  /**
@@ -404,17 +424,15 @@ shaka.media.MediaSourceEngine = class {
404
424
  *
405
425
  * @param {shaka.util.ManifestParserUtils.ContentType} contentType
406
426
  * @param {number} time Playhead time
407
- * @param {number=} smallGapLimit
408
427
  * @return {boolean}
409
428
  */
410
- isBuffered(contentType, time, smallGapLimit) {
429
+ isBuffered(contentType, time) {
411
430
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
412
431
  if (contentType == ContentType.TEXT) {
413
432
  return this.textEngine_.isBuffered(time);
414
433
  } else {
415
434
  const buffered = this.getBuffered_(contentType);
416
- return shaka.media.TimeRangesUtils.isBuffered(
417
- buffered, time, smallGapLimit);
435
+ return shaka.media.TimeRangesUtils.isBuffered(buffered, time);
418
436
  }
419
437
  }
420
438
 
@@ -496,11 +514,27 @@ shaka.media.MediaSourceEngine = class {
496
514
  * @param {?number} endTime relative to the start of the presentation
497
515
  * @param {?boolean} hasClosedCaptions True if the buffer contains CEA closed
498
516
  * captions
517
+ * @param {boolean=} seeked True if we just seeked
518
+ * @param {boolean=} sequenceMode True if sequence mode
499
519
  * @return {!Promise}
500
520
  */
501
- async appendBuffer(contentType, data, startTime, endTime, hasClosedCaptions) {
521
+ async appendBuffer(contentType, data, startTime, endTime, hasClosedCaptions,
522
+ seeked, sequenceMode) {
502
523
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
503
524
 
525
+ if (startTime != null && sequenceMode && contentType != ContentType.TEXT) {
526
+ // If we just cleared buffer and is on an unbuffered seek, we need to set
527
+ // the new timestampOffset of the sourceBuffer.
528
+ // Don't do this for text streams, though, since they don't use
529
+ // MediaSource anyway.
530
+ if (seeked) {
531
+ const timestampOffset = /** @type {number} */ (startTime);
532
+ this.enqueueOperation_(
533
+ contentType,
534
+ () => this.setTimestampOffset_(contentType, timestampOffset));
535
+ }
536
+ }
537
+
504
538
  if (contentType == ContentType.TEXT) {
505
539
  await this.textEngine_.appendBuffer(data, startTime, endTime);
506
540
  } else if (this.transmuxers_[contentType]) {
@@ -509,7 +543,7 @@ shaka.media.MediaSourceEngine = class {
509
543
  // For HLS CEA-608/708 CLOSED-CAPTIONS, text data is embedded in
510
544
  // the video stream, so textEngine may not have been initialized.
511
545
  if (!this.textEngine_) {
512
- this.reinitText('text/vtt');
546
+ this.reinitText('text/vtt', sequenceMode || false);
513
547
  }
514
548
 
515
549
  if (transmuxedData.metadata) {
@@ -536,7 +570,7 @@ shaka.media.MediaSourceEngine = class {
536
570
  contentType, () => this.append_(contentType, transmuxedSegment));
537
571
  } else if (hasClosedCaptions) {
538
572
  if (!this.textEngine_) {
539
- this.reinitText('text/vtt');
573
+ this.reinitText('text/vtt', sequenceMode || false);
540
574
  }
541
575
  // If it is the init segment for closed captions, initialize the closed
542
576
  // caption parser.
@@ -664,13 +698,18 @@ shaka.media.MediaSourceEngine = class {
664
698
  * @param {number} appendWindowEnd The timestamp to set the append window end
665
699
  * to. For future appends, frames/samples with timestamps greater than this
666
700
  * value will be dropped.
701
+ * @param {boolean} sequenceMode If true, the timestampOffset will not be
702
+ * applied in this step.
667
703
  * @return {!Promise}
668
704
  */
669
705
  async setStreamProperties(
670
- contentType, timestampOffset, appendWindowStart, appendWindowEnd) {
706
+ contentType, timestampOffset, appendWindowStart, appendWindowEnd,
707
+ sequenceMode) {
671
708
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
672
709
  if (contentType == ContentType.TEXT) {
673
- this.textEngine_.setTimestampOffset(timestampOffset);
710
+ if (!sequenceMode) {
711
+ this.textEngine_.setTimestampOffset(timestampOffset);
712
+ }
674
713
  this.textEngine_.setAppendWindow(appendWindowStart, appendWindowEnd);
675
714
  return;
676
715
  }
@@ -687,7 +726,10 @@ shaka.media.MediaSourceEngine = class {
687
726
  this.enqueueOperation_(
688
727
  contentType,
689
728
  () => this.abort_(contentType)),
690
- this.enqueueOperation_(
729
+ // Don't set the timestampOffset here when in sequenceMode, since we
730
+ // use timestampOffset for a different purpose in that mode (e.g. to
731
+ // indicate where the current segment is).
732
+ sequenceMode ? Promise.resolve() : this.enqueueOperation_(
691
733
  contentType,
692
734
  () => this.setTimestampOffset_(contentType, timestampOffset)),
693
735
  this.enqueueOperation_(
@@ -830,7 +872,8 @@ shaka.media.MediaSourceEngine = class {
830
872
  * @private
831
873
  */
832
874
  setTimestampOffset_(contentType, timestampOffset) {
833
- // Work around for https://github.com/google/shaka-player/issues/1281:
875
+ // Work around for
876
+ // https://github.com/shaka-project/shaka-player/issues/1281:
834
877
  // TODO(https://bit.ly/2ttKiBU): follow up when this is fixed in Edge
835
878
  if (timestampOffset < 0) {
836
879
  // Try to prevent rounding errors in Edge from removing the first
@@ -1078,6 +1121,13 @@ shaka.media.MediaSourceEngine = class {
1078
1121
  }
1079
1122
  }
1080
1123
 
1124
+ /**
1125
+ * @param {boolean} segmentRelativeVttTiming
1126
+ */
1127
+ setSegmentRelativeVttTiming(segmentRelativeVttTiming) {
1128
+ this.segmentRelativeVttTiming_ = segmentRelativeVttTiming;
1129
+ }
1130
+
1081
1131
  /**
1082
1132
  * Apply platform-specific transformations to this segment to work around
1083
1133
  * issues in the platform.
@@ -1090,7 +1140,7 @@ shaka.media.MediaSourceEngine = class {
1090
1140
  */
1091
1141
  workAroundBrokenPlatforms_(segment, startTime, contentType) {
1092
1142
  const isInitSegment = startTime == null;
1093
- const encryptionExpected = this.video_.mediaKeys;
1143
+ const encryptionExpected = this.expectedEncryption_[contentType];
1094
1144
 
1095
1145
  // If:
1096
1146
  // 1. this is an init segment,
@@ -1100,7 +1150,7 @@ shaka.media.MediaSourceEngine = class {
1100
1150
  // then insert fake encryption metadata for init segments that lack it.
1101
1151
  // The MP4 requirement is because we can currently only do this
1102
1152
  // transformation on MP4 containers.
1103
- // See: https://github.com/google/shaka-player/issues/2759
1153
+ // See: https://github.com/shaka-project/shaka-player/issues/2759
1104
1154
  if (isInitSegment &&
1105
1155
  encryptionExpected &&
1106
1156
  shaka.util.Platform.requiresEncryptionInfoInAllInitSegments() &&
@@ -1138,3 +1188,26 @@ shaka.media.MediaSourceEngine.createObjectURL = window.URL.createObjectURL;
1138
1188
  * The PublicPromise which is associated with this operation.
1139
1189
  */
1140
1190
  shaka.media.MediaSourceEngine.Operation;
1191
+
1192
+
1193
+ /**
1194
+ * @enum {string}
1195
+ * @private
1196
+ */
1197
+ shaka.media.MediaSourceEngine.SourceBufferMode_ = {
1198
+ SEQUENCE: 'sequence',
1199
+ SEGMENTS: 'segments',
1200
+ };
1201
+
1202
+
1203
+ /**
1204
+ * MIME types of raw formats.
1205
+ *
1206
+ * @const {!Array.<string>}
1207
+ */
1208
+ shaka.media.MediaSourceEngine.RAW_FORMATS = [
1209
+ 'audio/aac',
1210
+ 'audio/ac3',
1211
+ 'audio/ec3',
1212
+ 'audio/mpeg',
1213
+ ];
@@ -11,8 +11,6 @@ goog.require('shaka.log');
11
11
  goog.require('shaka.media.InitSegmentReference');
12
12
  goog.require('shaka.media.SegmentReference');
13
13
  goog.require('shaka.util.Error');
14
- goog.require('shaka.util.Functional');
15
- goog.require('shaka.util.Iterables');
16
14
  goog.require('shaka.util.Mp4Parser');
17
15
 
18
16
 
@@ -123,8 +121,7 @@ shaka.media.Mp4SegmentIndexParser = class {
123
121
  let unscaledStartTime = earliestPresentationTime;
124
122
  let startByte = sidxOffset + box.size + firstOffset;
125
123
 
126
- for (const _ of shaka.util.Iterables.range(referenceCount)) {
127
- shaka.util.Functional.ignored(_);
124
+ for (let i = 0; i < referenceCount; i++) {
128
125
  // |chunk| is 1 bit for |referenceType|, and 31 bits for |referenceSize|.
129
126
  const chunk = box.reader.readUint32();
130
127
  const referenceType = (chunk & 0x80000000) >>> 31;
@@ -160,10 +160,8 @@ shaka.media.MediaSourcePlayhead = class {
160
160
  * @param {function()} onSeek
161
161
  * Called when the user agent seeks to a time within the presentation
162
162
  * timeline.
163
- * @param {function(!Event)} onEvent
164
- * Called when an event is raised to be sent to the application.
165
163
  */
166
- constructor(mediaElement, manifest, config, startTime, onSeek, onEvent) {
164
+ constructor(mediaElement, manifest, config, startTime, onSeek) {
167
165
  /**
168
166
  * The seek range must be at least this number of seconds long. If it is
169
167
  * smaller than this, change it to be this big so we don't repeatedly seek
@@ -199,8 +197,7 @@ shaka.media.MediaSourcePlayhead = class {
199
197
  mediaElement,
200
198
  manifest.presentationTimeline,
201
199
  config,
202
- this.createStallDetector_(mediaElement, config),
203
- onEvent);
200
+ this.createStallDetector_(mediaElement, config));
204
201
 
205
202
  /** @private {shaka.media.VideoWrapper} */
206
203
  this.videoWrapper_ = new shaka.media.VideoWrapper(
@@ -256,7 +253,7 @@ shaka.media.MediaSourcePlayhead = class {
256
253
  // We don't buffer when the livestream video is paused and the playhead time
257
254
  // is out of the seek range; thus, we do not clamp the current time when the
258
255
  // video is paused.
259
- // https://github.com/google/shaka-player/issues/1121
256
+ // https://github.com/shaka-project/shaka-player/issues/1121
260
257
  if (this.mediaElement_.readyState > 0 && !this.mediaElement_.paused) {
261
258
  return this.clampTime_(time);
262
259
  }
@@ -362,7 +359,7 @@ shaka.media.MediaSourcePlayhead = class {
362
359
  * presentation duration. Seeking to or starting at duration does not work
363
360
  * consistently across browsers.
364
361
  *
365
- * @see https://github.com/google/shaka-player/issues/979
362
+ * @see https://github.com/shaka-project/shaka-player/issues/979
366
363
  * @param {number} time
367
364
  * @return {number} The adjusted seek time.
368
365
  * @private
@@ -249,8 +249,7 @@ shaka.media.PresentationTimeline = class {
249
249
  * @param {number} startTime
250
250
  * @export
251
251
  */
252
- notifyMinSegmentStartTime(
253
- startTime) {
252
+ notifyMinSegmentStartTime(startTime) {
254
253
  if (this.minSegmentStartTime_ == null) {
255
254
  // No data yet, and Math.min(null, startTime) is always 0. So just store
256
255
  // startTime.
@@ -355,14 +354,23 @@ shaka.media.PresentationTimeline = class {
355
354
  * starting after this time should be assumed to be unavailable.
356
355
  *
357
356
  * @return {number} The current segment availability end time, in seconds,
358
- * relative to the start of the presentation. Always returns the
359
- * presentation's duration for video-on-demand.
357
+ * relative to the start of the presentation. For VOD, the availability
358
+ * end time is the content's duration. If the Player's playRangeEnd
359
+ * configuration is used, this can override the duration.
360
360
  * @export
361
361
  */
362
362
  getSegmentAvailabilityEnd() {
363
363
  if (!this.isLive() && !this.isInProgress()) {
364
364
  // It's a static manifest (can also be a dynamic->static conversion)
365
- return this.maxSegmentEndTime_ || this.duration_;
365
+ if (this.maxSegmentEndTime_) {
366
+ // If we know segment times, use the min of that and duration.
367
+ // Note that the playRangeEnd configuration changes this.duration_.
368
+ // See https://github.com/shaka-project/shaka-player/issues/4026
369
+ return Math.min(this.maxSegmentEndTime_, this.duration_);
370
+ } else {
371
+ // If we don't have segment times, use duration.
372
+ return this.duration_;
373
+ }
366
374
  }
367
375
  // Can be either live or "in-progress recording" (live with known duration)
368
376
  return Math.min(this.getLiveEdge_() + this.availabilityTimeOffset_,
@@ -389,10 +397,11 @@ shaka.media.PresentationTimeline = class {
389
397
  // For VOD, the offset and end time are ignored, and we just return the
390
398
  // earliest segment time. All segments are "safe" in VOD. However, we
391
399
  // should round up to the nearest millisecond to avoid issues like
392
- // https://github.com/google/shaka-player/issues/2831, in which we tried to
393
- // seek repeatedly to catch up to the seek range, and never actually
394
- // "arrived" within it. The video's currentTime is not as accurate as the
395
- // JS number representing the earliest segment time for some content.
400
+ // https://github.com/shaka-project/shaka-player/issues/2831, in which we
401
+ // tried to seek repeatedly to catch up to the seek range, and never
402
+ // actually "arrived" within it. The video's currentTime is not as
403
+ // accurate as the JS number representing the earliest segment time for
404
+ // some content.
396
405
  if (this.segmentAvailabilityDuration_ == Infinity) {
397
406
  return Math.ceil(earliestSegmentTime * 1e3) / 1e3;
398
407
  }
@@ -407,7 +416,7 @@ shaka.media.PresentationTimeline = class {
407
416
  // Add the offset to the availability start to ensure that we don't fall
408
417
  // outside the availability window while we buffer; we don't need to add the
409
418
  // offset to earliestSegmentTime since that won't change over time.
410
- // Also see: https://github.com/google/shaka-player/issues/692
419
+ // Also see: https://github.com/shaka-project/shaka-player/issues/692
411
420
  const desiredStart =
412
421
  Math.min(availabilityStart + offset, this.getSeekRangeEnd());
413
422
  return Math.max(earliestSegmentTime, desiredStart);
@@ -9,7 +9,6 @@ goog.provide('shaka.media.SegmentIndex');
9
9
  goog.provide('shaka.media.SegmentIterator');
10
10
 
11
11
  goog.require('goog.asserts');
12
- goog.require('shaka.Deprecate');
13
12
  goog.require('shaka.media.SegmentReference');
14
13
  goog.require('shaka.util.IReleasable');
15
14
  goog.require('shaka.util.Timer');
@@ -52,23 +51,6 @@ shaka.media.SegmentIndex = class {
52
51
  }
53
52
 
54
53
 
55
- /**
56
- * SegmentIndex used to be an IDestroyable. Now it is an IReleasable.
57
- * This method is provided for backward compatibility.
58
- *
59
- * @deprecated
60
- * @return {!Promise}
61
- * @export
62
- */
63
- destroy() {
64
- shaka.Deprecate.deprecateFeature(4,
65
- 'shaka.media.SegmentIndex',
66
- 'Please use release() instead of destroy().');
67
- this.release();
68
- return Promise.resolve();
69
- }
70
-
71
-
72
54
  /**
73
55
  * @override
74
56
  * @export
@@ -101,6 +83,17 @@ shaka.media.SegmentIndex = class {
101
83
  }
102
84
 
103
85
 
86
+ /**
87
+ * Iterates over all top-level segment references in this segment index.
88
+ * @param {function(!shaka.media.SegmentReference)} fn
89
+ */
90
+ forEachTopLevelReference(fn) {
91
+ for (const reference of this.references) {
92
+ fn(reference);
93
+ }
94
+ }
95
+
96
+
104
97
  /**
105
98
  * Finds the position of the segment for the given time, in seconds, relative
106
99
  * to the start of the presentation. Returns the position of the segment
@@ -191,9 +184,6 @@ shaka.media.SegmentIndex = class {
191
184
  * @param {!Array.<!shaka.media.SegmentReference>} references The list of
192
185
  * SegmentReferences, which must be sorted first by their start times
193
186
  * (ascending) and second by their end times (ascending).
194
- * @deprecated Not used directly by our own parsers, so will become private in
195
- * v4. Use mergeAndEvict() instead.
196
- * @export
197
187
  */
198
188
  merge(references) {
199
189
  if (goog.DEBUG) {
@@ -348,7 +338,8 @@ shaka.media.SegmentIndex = class {
348
338
  lastReference.appendWindowEnd,
349
339
  lastReference.partialReferences,
350
340
  lastReference.tilesLayout,
351
- lastReference.tileDuration);
341
+ lastReference.tileDuration,
342
+ lastReference.syncTime);
352
343
  }
353
344
 
354
345
 
@@ -513,30 +504,6 @@ shaka.media.SegmentIterator = class {
513
504
  this.currentPartialPosition_ = partialSegmentIndex;
514
505
  }
515
506
 
516
- /**
517
- * Move the iterator to a given timestamp in the underlying SegmentIndex.
518
- *
519
- * @param {number} time
520
- * @return {shaka.media.SegmentReference}
521
- * @deprecated Use SegmentIndex.getIteratorForTime instead
522
- * @export
523
- */
524
- seek(time) {
525
- shaka.Deprecate.deprecateFeature(
526
- 4, 'shaka.media.SegmentIterator',
527
- 'Please use SegmentIndex.getIteratorForTime instead of seek().');
528
-
529
- const iter = this.segmentIndex_.getIteratorForTime(time);
530
- if (iter) {
531
- this.currentPosition_ = iter.currentPosition_;
532
- this.currentPartialPosition_ = iter.currentPartialPosition_;
533
- } else {
534
- this.currentPosition_ = Number.MAX_VALUE;
535
- this.currentPartialPosition_ = 0;
536
- }
537
- return this.next().value;
538
- }
539
-
540
507
  /**
541
508
  * @return {shaka.media.SegmentReference}
542
509
  * @export
@@ -159,11 +159,18 @@ shaka.media.SegmentReference = class {
159
159
  * The explicit duration of an individual tile within the tiles grid.
160
160
  * If not provided, the duration should be automatically calculated based on
161
161
  * the duration of the reference.
162
+ * @param {?number=} syncTime
163
+ * A time value, expressed in the same scale as the start and end time, which
164
+ * is used to synchronize between streams.
165
+ * @param {shaka.media.SegmentReference.Status=} status
166
+ * The segment status is used to indicate that a segment does not exist or is
167
+ * not available.
162
168
  */
163
169
  constructor(
164
170
  startTime, endTime, uris, startByte, endByte, initSegmentReference,
165
171
  timestampOffset, appendWindowStart, appendWindowEnd,
166
- partialReferences = [], tilesLayout = '', tileDuration = null) {
172
+ partialReferences = [], tilesLayout = '', tileDuration = null,
173
+ syncTime = null, status = shaka.media.SegmentReference.Status.AVAILABLE) {
167
174
  // A preload hinted Partial Segment has the same startTime and endTime.
168
175
  goog.asserts.assert(startTime <= endTime,
169
176
  'startTime must be less than or equal to endTime');
@@ -213,6 +220,12 @@ shaka.media.SegmentReference = class {
213
220
 
214
221
  /** @type {?number} */
215
222
  this.tileDuration = tileDuration;
223
+
224
+ /** @type {?number} */
225
+ this.syncTime = syncTime;
226
+
227
+ /** @type {shaka.media.SegmentReference.Status} */
228
+ this.status = status;
216
229
  }
217
230
 
218
231
  /**
@@ -308,6 +321,39 @@ shaka.media.SegmentReference = class {
308
321
  getTileDuration() {
309
322
  return this.tileDuration;
310
323
  }
324
+
325
+ /**
326
+ * Returns the segment's status.
327
+ *
328
+ * @return {shaka.media.SegmentReference.Status}
329
+ * @export
330
+ */
331
+ getStatus() {
332
+ return this.status;
333
+ }
334
+
335
+ /**
336
+ * Mark the reference as unavailable.
337
+ *
338
+ * @export
339
+ */
340
+ markAsUnavailable() {
341
+ this.status = shaka.media.SegmentReference.Status.UNAVAILABLE;
342
+ }
343
+ };
344
+
345
+
346
+ /**
347
+ * Rather than using booleans to communicate what the state of the reference,
348
+ * we have this enum.
349
+ *
350
+ * @enum {number}
351
+ * @export
352
+ */
353
+ shaka.media.SegmentReference.Status = {
354
+ AVAILABLE: 0,
355
+ UNAVAILABLE: 1,
356
+ MISSING: 2,
311
357
  };
312
358
 
313
359