rx-player 3.29.0-dev.2022091500 → 3.29.0-dev.2022103100

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 (183) hide show
  1. package/CHANGELOG.md +22 -9
  2. package/MAINTAINERS.md +2 -1
  3. package/VERSION +1 -1
  4. package/dist/_esm5.processed/compat/browser_detection.d.ts +4 -1
  5. package/dist/_esm5.processed/compat/browser_detection.js +7 -1
  6. package/dist/_esm5.processed/compat/can_reuse_media_keys.d.ts +12 -0
  7. package/dist/_esm5.processed/compat/can_reuse_media_keys.js +15 -0
  8. package/dist/_esm5.processed/compat/enable_audio_track.d.ts +11 -0
  9. package/dist/_esm5.processed/compat/enable_audio_track.js +26 -0
  10. package/dist/_esm5.processed/compat/index.d.ts +4 -2
  11. package/dist/_esm5.processed/compat/index.js +4 -2
  12. package/dist/_esm5.processed/compat/{should_renew_media_keys.d.ts → should_renew_media_key_system_access.d.ts} +3 -3
  13. package/dist/_esm5.processed/compat/{should_renew_media_keys.js → should_renew_media_key_system_access.js} +3 -3
  14. package/dist/_esm5.processed/config.d.ts +1 -0
  15. package/dist/_esm5.processed/core/api/playback_observer.d.ts +14 -5
  16. package/dist/_esm5.processed/core/api/playback_observer.js +54 -22
  17. package/dist/_esm5.processed/core/api/public_api.d.ts +7 -4
  18. package/dist/_esm5.processed/core/api/public_api.js +79 -61
  19. package/dist/_esm5.processed/core/api/tracks_management/media_element_track_choice_manager.js +13 -11
  20. package/dist/_esm5.processed/core/decrypt/__tests__/__global__/utils.js +1 -1
  21. package/dist/_esm5.processed/core/decrypt/find_key_system.js +3 -3
  22. package/dist/_esm5.processed/core/decrypt/get_media_keys.js +4 -1
  23. package/dist/_esm5.processed/core/fetchers/cdn_prioritizer.d.ts +98 -0
  24. package/dist/_esm5.processed/core/fetchers/cdn_prioritizer.js +173 -0
  25. package/dist/_esm5.processed/core/fetchers/manifest/manifest_fetcher.js +4 -4
  26. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.d.ts +2 -1
  27. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.js +15 -16
  28. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher_creator.d.ts +3 -1
  29. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher_creator.js +5 -2
  30. package/dist/_esm5.processed/core/fetchers/utils/schedule_request.d.ts +103 -0
  31. package/dist/_esm5.processed/core/fetchers/utils/schedule_request.js +414 -0
  32. package/dist/_esm5.processed/core/init/content_time_boundaries_observer.d.ts +4 -3
  33. package/dist/_esm5.processed/core/init/content_time_boundaries_observer.js +21 -22
  34. package/dist/_esm5.processed/core/init/initialize_media_source.d.ts +18 -4
  35. package/dist/_esm5.processed/core/init/initialize_media_source.js +10 -2
  36. package/dist/_esm5.processed/core/init/load_on_media_source.js +7 -1
  37. package/dist/_esm5.processed/core/init/stall_avoider.js +3 -1
  38. package/dist/_esm5.processed/default_config.d.ts +11 -0
  39. package/dist/_esm5.processed/default_config.js +11 -0
  40. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.js +1 -1
  41. package/dist/_esm5.processed/manifest/manifest.js +11 -2
  42. package/dist/_esm5.processed/manifest/representation.d.ts +12 -1
  43. package/dist/_esm5.processed/manifest/representation.js +1 -0
  44. package/dist/_esm5.processed/manifest/representation_index/static.d.ts +1 -1
  45. package/dist/_esm5.processed/manifest/representation_index/static.js +2 -2
  46. package/dist/_esm5.processed/manifest/representation_index/types.d.ts +32 -15
  47. package/dist/_esm5.processed/manifest/update_period_in_place.js +1 -0
  48. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/base.d.ts +10 -9
  49. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/base.js +11 -11
  50. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/get_init_segment.d.ts +1 -1
  51. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/get_init_segment.js +3 -3
  52. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/get_segments_from_timeline.d.ts +1 -1
  53. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/get_segments_from_timeline.js +4 -4
  54. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.d.ts +7 -7
  55. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.js +12 -8
  56. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.d.ts +5 -6
  57. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.js +16 -16
  58. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.d.ts +11 -10
  59. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.js +14 -13
  60. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/tokens.d.ts +3 -4
  61. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/tokens.js +4 -12
  62. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_mpd.js +2 -4
  63. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representation_index.js +1 -3
  64. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_representations.js +6 -2
  65. package/dist/_esm5.processed/parsers/manifest/dash/common/resolve_base_urls.d.ts +1 -2
  66. package/dist/_esm5.processed/parsers/manifest/dash/common/resolve_base_urls.js +3 -8
  67. package/dist/_esm5.processed/parsers/manifest/dash/js-parser/node_parsers/BaseURL.d.ts +1 -1
  68. package/dist/_esm5.processed/parsers/manifest/dash/js-parser/node_parsers/BaseURL.js +2 -20
  69. package/dist/_esm5.processed/parsers/manifest/dash/node_parser_types.d.ts +0 -6
  70. package/dist/_esm5.processed/parsers/manifest/dash/wasm-parser/ts/generators/BaseURL.js +0 -11
  71. package/dist/_esm5.processed/parsers/manifest/dash/wasm-parser/ts/types.d.ts +5 -1
  72. package/dist/_esm5.processed/parsers/manifest/local/parse_local_manifest.js +2 -1
  73. package/dist/_esm5.processed/parsers/manifest/local/representation_index.js +2 -2
  74. package/dist/_esm5.processed/parsers/manifest/metaplaylist/metaplaylist_parser.js +7 -1
  75. package/dist/_esm5.processed/parsers/manifest/smooth/create_parser.js +17 -11
  76. package/dist/_esm5.processed/parsers/manifest/smooth/representation_index.js +2 -2
  77. package/dist/_esm5.processed/parsers/manifest/types.d.ts +24 -0
  78. package/dist/_esm5.processed/parsers/texttracks/ttml/html/apply_extent.js +8 -1
  79. package/dist/_esm5.processed/parsers/texttracks/ttml/html/apply_origin.js +9 -1
  80. package/dist/_esm5.processed/parsers/texttracks/ttml/html/create_element.js +2 -1
  81. package/dist/_esm5.processed/transports/dash/construct_segment_url.d.ts +18 -0
  82. package/dist/_esm5.processed/transports/dash/construct_segment_url.js +21 -0
  83. package/dist/_esm5.processed/transports/dash/image_pipelines.d.ts +3 -2
  84. package/dist/_esm5.processed/transports/dash/image_pipelines.js +5 -3
  85. package/dist/_esm5.processed/transports/dash/segment_loader.js +4 -2
  86. package/dist/_esm5.processed/transports/dash/text_loader.js +4 -2
  87. package/dist/_esm5.processed/transports/dash/text_parser.js +3 -1
  88. package/dist/_esm5.processed/transports/local/segment_loader.d.ts +3 -2
  89. package/dist/_esm5.processed/transports/local/segment_loader.js +2 -2
  90. package/dist/_esm5.processed/transports/metaplaylist/pipelines.js +8 -8
  91. package/dist/_esm5.processed/transports/smooth/pipelines.js +11 -7
  92. package/dist/_esm5.processed/transports/smooth/utils.d.ts +4 -2
  93. package/dist/_esm5.processed/transports/smooth/utils.js +7 -1
  94. package/dist/_esm5.processed/transports/types.d.ts +5 -3
  95. package/dist/_esm5.processed/utils/event_emitter.d.ts +1 -2
  96. package/dist/_esm5.processed/utils/resolve_url.d.ts +7 -4
  97. package/dist/_esm5.processed/utils/resolve_url.js +11 -8
  98. package/dist/mpd-parser.wasm +0 -0
  99. package/dist/rx-player.js +5658 -13236
  100. package/dist/rx-player.min.js +1 -1
  101. package/jest.config.js +28 -23
  102. package/package.json +29 -29
  103. package/sonar-project.properties +1 -1
  104. package/src/compat/__tests__/can_reuse_media_keys.test.ts +54 -0
  105. package/src/compat/__tests__/enable_audio_track.test.ts +341 -0
  106. package/src/compat/__tests__/{should_renew_media_keys.test.ts → should_renew_media_key_system_access.test.ts} +7 -5
  107. package/src/compat/browser_detection.ts +10 -0
  108. package/src/compat/can_reuse_media_keys.ts +19 -0
  109. package/src/compat/enable_audio_track.ts +33 -0
  110. package/src/compat/index.ts +6 -2
  111. package/src/compat/{should_renew_media_keys.ts → should_renew_media_key_system_access.ts} +3 -3
  112. package/src/core/api/playback_observer.ts +97 -33
  113. package/src/core/api/public_api.ts +126 -74
  114. package/src/core/api/tracks_management/media_element_track_choice_manager.ts +7 -12
  115. package/src/core/decrypt/__tests__/__global__/media_keys.test.ts +182 -0
  116. package/src/core/decrypt/__tests__/__global__/utils.ts +2 -0
  117. package/src/core/decrypt/find_key_system.ts +3 -3
  118. package/src/core/decrypt/get_media_keys.ts +5 -1
  119. package/src/core/fetchers/cdn_prioritizer.ts +198 -0
  120. package/src/core/fetchers/manifest/manifest_fetcher.ts +7 -11
  121. package/src/core/fetchers/segment/segment_fetcher.ts +12 -10
  122. package/src/core/fetchers/segment/segment_fetcher_creator.ts +10 -1
  123. package/src/core/fetchers/utils/schedule_request.ts +482 -0
  124. package/src/core/init/content_time_boundaries_observer.ts +12 -12
  125. package/src/core/init/initialize_media_source.ts +31 -4
  126. package/src/core/init/load_on_media_source.ts +11 -2
  127. package/src/core/init/stall_avoider.ts +4 -1
  128. package/src/default_config.ts +12 -0
  129. package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.ts +1 -0
  130. package/src/manifest/manifest.ts +11 -2
  131. package/src/manifest/representation.ts +15 -0
  132. package/src/manifest/representation_index/__tests__/static.test.ts +1 -1
  133. package/src/manifest/representation_index/static.ts +3 -3
  134. package/src/manifest/representation_index/types.ts +33 -15
  135. package/src/manifest/update_period_in_place.ts +1 -0
  136. package/src/parsers/manifest/dash/common/indexes/base.ts +22 -23
  137. package/src/parsers/manifest/dash/common/indexes/get_init_segment.ts +6 -4
  138. package/src/parsers/manifest/dash/common/indexes/get_segments_from_timeline.ts +5 -5
  139. package/src/parsers/manifest/dash/common/indexes/list.ts +19 -20
  140. package/src/parsers/manifest/dash/common/indexes/template.ts +23 -27
  141. package/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts +25 -23
  142. package/src/parsers/manifest/dash/common/indexes/tokens.ts +7 -18
  143. package/src/parsers/manifest/dash/common/parse_mpd.ts +2 -4
  144. package/src/parsers/manifest/dash/common/parse_representation_index.ts +1 -6
  145. package/src/parsers/manifest/dash/common/parse_representations.ts +9 -0
  146. package/src/parsers/manifest/dash/common/resolve_base_urls.ts +5 -9
  147. package/src/parsers/manifest/dash/js-parser/node_parsers/BaseURL.ts +2 -29
  148. package/src/parsers/manifest/dash/js-parser/node_parsers/__tests__/AdaptationSet.test.ts +7 -11
  149. package/src/parsers/manifest/dash/node_parser_types.ts +0 -7
  150. package/src/parsers/manifest/dash/wasm-parser/rs/events.rs +3 -1
  151. package/src/parsers/manifest/dash/wasm-parser/rs/processor/attributes.rs +1 -8
  152. package/src/parsers/manifest/dash/wasm-parser/ts/generators/BaseURL.ts +0 -13
  153. package/src/parsers/manifest/dash/wasm-parser/ts/types.ts +8 -0
  154. package/src/parsers/manifest/local/parse_local_manifest.ts +1 -0
  155. package/src/parsers/manifest/local/representation_index.ts +2 -2
  156. package/src/parsers/manifest/metaplaylist/metaplaylist_parser.ts +7 -1
  157. package/src/parsers/manifest/smooth/create_parser.ts +17 -13
  158. package/src/parsers/manifest/smooth/representation_index.ts +2 -2
  159. package/src/parsers/manifest/types.ts +26 -1
  160. package/src/parsers/manifest/utils/__tests__/get_first_time_from_adaptations.test.ts +15 -0
  161. package/src/parsers/manifest/utils/__tests__/get_last_time_from_adaptation.test.ts +15 -0
  162. package/src/parsers/texttracks/ttml/html/apply_extent.ts +8 -1
  163. package/src/parsers/texttracks/ttml/html/apply_origin.ts +9 -1
  164. package/src/parsers/texttracks/ttml/html/create_element.ts +2 -2
  165. package/src/transports/dash/construct_segment_url.ts +28 -0
  166. package/src/transports/dash/image_pipelines.ts +5 -2
  167. package/src/transports/dash/segment_loader.ts +5 -2
  168. package/src/transports/dash/text_loader.ts +5 -2
  169. package/src/transports/dash/text_parser.ts +3 -1
  170. package/src/transports/local/segment_loader.ts +3 -2
  171. package/src/transports/metaplaylist/pipelines.ts +28 -9
  172. package/src/transports/smooth/pipelines.ts +12 -6
  173. package/src/transports/smooth/utils.ts +13 -1
  174. package/src/transports/types.ts +6 -3
  175. package/src/utils/__tests__/event_emitter.test.ts +72 -67
  176. package/src/utils/__tests__/initialization_segment_cache.test.ts +7 -7
  177. package/src/utils/__tests__/resolve_url.test.ts +27 -23
  178. package/src/utils/event_emitter.ts +1 -3
  179. package/src/utils/resolve_url.ts +11 -8
  180. package/dist/_esm5.processed/core/fetchers/utils/try_urls_with_backoff.d.ts +0 -85
  181. package/dist/_esm5.processed/core/fetchers/utils/try_urls_with_backoff.js +0 -264
  182. package/dummy +0 -1
  183. package/src/core/fetchers/utils/try_urls_with_backoff.ts +0 -287
package/CHANGELOG.md CHANGED
@@ -1,27 +1,40 @@
1
1
  # Changelog
2
2
 
3
- ## v3.29.0-dev.2022091300 (2022-09-15)
3
+ ## v3.29.0 (XXXX-XX-XX)
4
4
 
5
5
  ### Features
6
6
 
7
7
  - add `networkConfig.segmentRequestTimeout` and `networkConfig.manifestRequestTimeout` options to loadVideo to configure the timeout of respectively segment and manifest requests [#1156]
8
8
  - add `timeout` property to the first argument communicated to a `segmentLoader` (from `loadVideo`'s `transportOptions`) [#1156]
9
9
  - add `timeout` property to a new third argument communicated to a `manifestLoader` (from `loadVideo`'s `transportOptions`) [#1156]
10
- - add `keySystems[].onKeyExpiration` to `loadVideo` options to configure the behavior the RxPlayer should have on key expiration [#1157]
11
- - add `keyStatuses` property to an `EncryptedMediaError` with the `KEY_STATUS_CHANGE_ERROR` code to communicate which key id and key statuses caused issues. [#1157]
10
+ - DRM: add `keySystems[].onKeyExpiration` to `loadVideo` options to configure the behavior the RxPlayer should have on key expiration [#1157]
11
+ - DRM: add `keyStatuses` property to an `EncryptedMediaError` with the `KEY_STATUS_CHANGE_ERROR` code to communicate which key id and key statuses caused issues. [#1157]
12
+
13
+ ### Deprecated
14
+
15
+ - DRM: Deprecate `keySystems[].throwOnLicenseExpiration` `loadVideo` option as this boolean can be replaced with more customability by the new `keySystems[].onKeyExpiration` `loadVideo` option [#1157]
12
16
 
13
17
  ### Bug fixes
14
18
 
15
- - Compat/Directfile: Fix an issue with LG TV when playing multiple directfile contents with the `stopAtEnd` player option set to `true` [#1154]
16
- - Compat: To work around an issue on LG TVs, also specify a request timeout manually through a `setTimeout` call when XMLHttpRequests are created for Manifest and segment requests [#1152]
17
- - Compat: Fix issue with Samsung TVs where starting playback on a discontinuity could lead to infinite rebuffering [#1140]
18
- - Better handle valid reverse playback use cases by not skipping gaps when the playback rate has been set to `0` or a negative value [#1138]
19
- - DRM: When using persistent licenses, create new MediaKeySession when `load` resolves with `false`, instead of relying the same, to fix issues with such persistent sessions [#1139]
19
+ - Directfile: Fix long-running issues with rare "directfile" contents and some browsers/platforms (seen on Chrome PC and PlayStation 5) where playback would stay in `LOADING` state indefinitely despite playing [#1174]
20
+ - DRM: Fix undocumented `keySystems[].videoRobustnesses` `loadVideo` option. `audioRobustnesses` was previously used even for video capabilities [#1171]
21
+ - Compat/Directfile: Fix an issue with WebOS (LG TVs) when playing multiple directfile contents with the `stopAtEnd` player option set to `true` [#1154]
22
+ - Compat/DRM: Fix infinite loading on WebOS (LG TVs) 2021 and 2022 when loading more than once an encrypted content by resetting decryption capabilities each time [#1175]
23
+ - Compat: To work around an issue on WebOS (LG TVs), also specify a request timeout manually through a `setTimeout` call when XMLHttpRequests are created for Manifest and segment requests [#1152]
24
+ - Compat/Directfile: Fix an issue on Tizen (Samsung TVs) where playing directfile contents could randomly lead to not having audio [#1170]
25
+ - Compat: Fix issue with Tizen (Samsung TVs) where starting playback on a discontinuity could lead to infinite rebuffering [#1140]
26
+ - Compat/Directfile: For `"directfile"` contents, also consider `AudioTrack` with a `description` (without an "s") as audio-description audio tracks to work-around what seems to be a Safari typo [#1160]
27
+ - DRM: When using persistent licenses, create new MediaKeySession when `load` resolves with `false`, instead of relying the same, to fix issues with such persistent sessions if the browser cleaned it up [#1139]
28
+ - Only call "MediaSource.endOfStream" once, the most visible side-effect should have been repeated logs [#1163]
29
+ - TTML: put saner values for extent and origins when weird ones are found
20
30
 
21
31
  ### Other improvements
22
32
 
33
+ - DASH: Improve multi-CDN configurations, by smartly selecting the right CDN depending on past status [#1165]
34
+ - Allow reverse playback use cases by not skipping gaps and most discontinuities when the playback rate has been set to `0` or a negative value [#1138]
23
35
  - In the experimental "local" transport, add `incomingRanges` property to signal the time ranges of remaining data, allowing better discontinuity handling and duration estimates for sill-loading dowloaded contents [#1151]
24
- - Only send through `"warning"` events, just one `EncryptedMediaError` with a `KEY_STATUS_CHANGE_ERROR` code when multiple ones arises at the same time [#1157]
36
+ - Only send, through `"warning"` events, one `EncryptedMediaError` with a `KEY_STATUS_CHANGE_ERROR` code when multiple ones arises at the same time [#1157]
37
+
25
38
 
26
39
  ## v3.28.0 (2022-07-12)
27
40
 
package/MAINTAINERS.md CHANGED
@@ -16,7 +16,6 @@ RxPlayer-related question or to propose new features.
16
16
  Here is the list of current maintainers:
17
17
 
18
18
  - Paul Berberian <paul.berberian@canal-plus.com>
19
- - Paul Rosset <paul.rosset@canal-plus.com>
20
19
 
21
20
 
22
21
  ## Previous maintainers ########################################################
@@ -24,8 +23,10 @@ Here is the list of current maintainers:
24
23
  Here is the list of previous maintainers, which are not working on the project
25
24
  anymore:
26
25
 
26
+ - Achraf Laamoum <achraf.laamoum@canal-plus.com>
27
27
  - Alexandre Duros <alexandre.duros@canal-plus.com>
28
28
  - Antoine Maillard <antoine.maillard@canal-plus.com>
29
29
  - Guillaume Bentaieb <guillaume.bentaieb@canal-plus.com>
30
30
  - Guillaume Renault <guillaume.renault@canal-plus.com>
31
+ - Paul Rosset <paul.rosset@canal-plus.com>
31
32
  - Pierre Guilleminot <pierre.guilleminot@canal-plus.com>
package/VERSION CHANGED
@@ -1 +1 @@
1
- 3.29.0-dev.2022091500
1
+ 3.29.0-dev.2022103100
@@ -19,8 +19,11 @@ declare const isEdgeChromium: boolean;
19
19
  declare const isFirefox: boolean;
20
20
  declare const isSamsungBrowser: boolean;
21
21
  declare const isTizen: boolean;
22
+ declare const isWebOs: boolean;
23
+ declare const isWebOs2021: boolean;
24
+ declare const isWebOs2022: boolean;
22
25
  /** `true` on Safari on a PC platform (i.e. not iPhone / iPad etc.) */
23
26
  declare const isSafariDesktop: boolean;
24
27
  /** `true` on Safari on an iPhone, iPad & iPod platform */
25
28
  declare const isSafariMobile: boolean;
26
- export { isEdgeChromium, isIE11, isIEOrEdge, isFirefox, isSafariDesktop, isSafariMobile, isSamsungBrowser, isTizen, };
29
+ export { isEdgeChromium, isIE11, isIEOrEdge, isFirefox, isSafariDesktop, isSafariMobile, isSamsungBrowser, isTizen, isWebOs, isWebOs2021, isWebOs2022, };
@@ -34,6 +34,12 @@ var isSamsungBrowser = !isNode &&
34
34
  /SamsungBrowser/.test(navigator.userAgent);
35
35
  var isTizen = !isNode &&
36
36
  /Tizen/.test(navigator.userAgent);
37
+ var isWebOs = !isNode &&
38
+ /Web0S/.test(navigator.userAgent);
39
+ var isWebOs2021 = !isNode &&
40
+ /WebOS.TV-2021/.test(navigator.userAgent);
41
+ var isWebOs2022 = !isNode &&
42
+ /WebOS.TV-2022/.test(navigator.userAgent);
37
43
  /** `true` on Safari on a PC platform (i.e. not iPhone / iPad etc.) */
38
44
  var isSafariDesktop = !isNode && (Object.prototype.toString.call(window.HTMLElement).indexOf("Constructor") >= 0 ||
39
45
  ((_b = (_a = window.safari) === null || _a === void 0 ? void 0 : _a.pushNotification) === null || _b === void 0 ? void 0 : _b.toString()) ===
@@ -42,4 +48,4 @@ var isSafariDesktop = !isNode && (Object.prototype.toString.call(window.HTMLElem
42
48
  var isSafariMobile = !isNode &&
43
49
  typeof navigator.platform === "string" &&
44
50
  /iPad|iPhone|iPod/.test(navigator.platform);
45
- export { isEdgeChromium, isIE11, isIEOrEdge, isFirefox, isSafariDesktop, isSafariMobile, isSamsungBrowser, isTizen, };
51
+ export { isEdgeChromium, isIE11, isIEOrEdge, isFirefox, isSafariDesktop, isSafariMobile, isSamsungBrowser, isTizen, isWebOs, isWebOs2021, isWebOs2022, };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Returns `true` if a `MediaKeys` instance (the `Encrypted Media Extension`
3
+ * concept) can be reused between contents.
4
+ *
5
+ * This should usually be the case but we found rare devices where this would
6
+ * cause problem:
7
+ * - (2022-10-26): WebOS (LG TVs) 2021 and 2022 just rebuffered indefinitely
8
+ * when loading a content already-loaded on the HTMLMediaElement.
9
+ *
10
+ * @returns {boolean}
11
+ */
12
+ export default function canReuseMediaKeys(): boolean;
@@ -0,0 +1,15 @@
1
+ import { isWebOs2021, isWebOs2022, } from "./browser_detection";
2
+ /**
3
+ * Returns `true` if a `MediaKeys` instance (the `Encrypted Media Extension`
4
+ * concept) can be reused between contents.
5
+ *
6
+ * This should usually be the case but we found rare devices where this would
7
+ * cause problem:
8
+ * - (2022-10-26): WebOS (LG TVs) 2021 and 2022 just rebuffered indefinitely
9
+ * when loading a content already-loaded on the HTMLMediaElement.
10
+ *
11
+ * @returns {boolean}
12
+ */
13
+ export default function canReuseMediaKeys() {
14
+ return !(isWebOs2021 || isWebOs2022);
15
+ }
@@ -0,0 +1,11 @@
1
+ import { ICompatAudioTrack } from "./browser_compatibility_types";
2
+ /**
3
+ * Enable the audio track at the given index while disabling all others in the
4
+ * `audioTracks` array.
5
+ *
6
+ * Returns false if the given index is not found in the `audioTracks` array.
7
+ * @param {array.<audioTrack>} audioTracks
8
+ * @param {number} indexToEnable
9
+ * @returns {boolean}
10
+ */
11
+ export default function enableAudioTrack(audioTracks: ICompatAudioTrack[], indexToEnable: number): boolean;
@@ -0,0 +1,26 @@
1
+ import { isTizen } from "./browser_detection";
2
+ /**
3
+ * Enable the audio track at the given index while disabling all others in the
4
+ * `audioTracks` array.
5
+ *
6
+ * Returns false if the given index is not found in the `audioTracks` array.
7
+ * @param {array.<audioTrack>} audioTracks
8
+ * @param {number} indexToEnable
9
+ * @returns {boolean}
10
+ */
11
+ export default function enableAudioTrack(audioTracks, indexToEnable) {
12
+ // Seen on Safari MacOS only (2022-02-14), not disabling ALL audio tracks
13
+ // first (even the wanted one), can lead to the media not playing.
14
+ for (var i = 0; i < audioTracks.length; i++) {
15
+ // However, Tizen just plays no audio if it is disabled then enabled
16
+ // synchronously (2022-10-12)
17
+ if (!isTizen || i !== indexToEnable) {
18
+ audioTracks[i].enabled = false;
19
+ }
20
+ }
21
+ if (indexToEnable < 0 || indexToEnable >= audioTracks.length) {
22
+ return false;
23
+ }
24
+ audioTracks[indexToEnable].enabled = true;
25
+ return true;
26
+ }
@@ -17,9 +17,11 @@ import addClassName from "./add_class_name";
17
17
  import addTextTrack from "./add_text_track";
18
18
  import { ICompatTextTrack, ICompatVTTCue, MediaSource_ } from "./browser_compatibility_types";
19
19
  import canPatchISOBMFFSegment from "./can_patch_isobmff";
20
+ import canReuseMediaKeys from "./can_reuse_media_keys";
20
21
  import tryToChangeSourceBufferType, { ICompatSourceBuffer } from "./change_source_buffer_type";
21
22
  import clearElementSrc from "./clear_element_src";
22
23
  import { closeSession, CustomMediaKeySystemAccess, generateKeyRequest, getInitData, ICustomMediaKeys, ICustomMediaKeySession, ICustomMediaKeySystemAccess, loadSession, requestMediaKeySystemAccess, setMediaKeys } from "./eme";
24
+ import enableAudioTrack from "./enable_audio_track";
23
25
  import * as events from "./event_listeners";
24
26
  import { exitFullscreen, isFullscreen, requestFullscreen } from "./fullscreen";
25
27
  import getStartDate from "./get_start_date";
@@ -33,9 +35,9 @@ import onHeightWidthChange from "./on_height_width_change";
33
35
  import play from "./play";
34
36
  import setElementSrc$ from "./set_element_src";
35
37
  import shouldReloadMediaSourceOnDecipherabilityUpdate from "./should_reload_media_source_on_decipherability_update";
36
- import shouldRenewMediaKeys from "./should_renew_media_keys";
38
+ import shouldRenewMediaKeySystemAccess from "./should_renew_media_key_system_access";
37
39
  import shouldUnsetMediaKeys from "./should_unset_media_keys";
38
40
  import shouldValidateMetadata from "./should_validate_metadata";
39
41
  import shouldWaitForDataBeforeLoaded from "./should_wait_for_data_before_loaded";
40
42
  import whenLoadedMetadata$ from "./when_loaded_metadata";
41
- export { addClassName, addTextTrack, canPatchISOBMFFSegment, clearElementSrc, closeSession, CustomMediaKeySystemAccess, events, exitFullscreen, generateKeyRequest, getInitData, getStartDate, hasEMEAPIs, ICompatTextTrack, ICompatVTTCue, ICustomMediaKeySession, ICustomMediaKeySystemAccess, ICustomMediaKeys, ICompatSourceBuffer, isCodecSupported, isFullscreen, isNode, isOffline, isVTTCue, loadSession, makeVTTCue, MediaSource_, onHeightWidthChange, play, requestFullscreen, requestMediaKeySystemAccess, setElementSrc$, setMediaKeys, shouldReloadMediaSourceOnDecipherabilityUpdate, shouldRenewMediaKeys, shouldUnsetMediaKeys, shouldValidateMetadata, shouldWaitForDataBeforeLoaded, tryToChangeSourceBufferType, whenLoadedMetadata$, };
43
+ export { addClassName, addTextTrack, canPatchISOBMFFSegment, canReuseMediaKeys, clearElementSrc, closeSession, CustomMediaKeySystemAccess, enableAudioTrack, events, exitFullscreen, generateKeyRequest, getInitData, getStartDate, hasEMEAPIs, ICompatTextTrack, ICompatVTTCue, ICustomMediaKeySession, ICustomMediaKeySystemAccess, ICustomMediaKeys, ICompatSourceBuffer, isCodecSupported, isFullscreen, isNode, isOffline, isVTTCue, loadSession, makeVTTCue, MediaSource_, onHeightWidthChange, play, requestFullscreen, requestMediaKeySystemAccess, setElementSrc$, setMediaKeys, shouldReloadMediaSourceOnDecipherabilityUpdate, shouldRenewMediaKeySystemAccess, shouldUnsetMediaKeys, shouldValidateMetadata, shouldWaitForDataBeforeLoaded, tryToChangeSourceBufferType, whenLoadedMetadata$, };
@@ -17,9 +17,11 @@ import addClassName from "./add_class_name";
17
17
  import addTextTrack from "./add_text_track";
18
18
  import { MediaSource_, } from "./browser_compatibility_types";
19
19
  import canPatchISOBMFFSegment from "./can_patch_isobmff";
20
+ import canReuseMediaKeys from "./can_reuse_media_keys";
20
21
  import tryToChangeSourceBufferType from "./change_source_buffer_type";
21
22
  import clearElementSrc from "./clear_element_src";
22
23
  import { closeSession, CustomMediaKeySystemAccess, generateKeyRequest, getInitData, loadSession, requestMediaKeySystemAccess, setMediaKeys, } from "./eme";
24
+ import enableAudioTrack from "./enable_audio_track";
23
25
  import * as events from "./event_listeners";
24
26
  import { exitFullscreen, isFullscreen, requestFullscreen, } from "./fullscreen";
25
27
  import getStartDate from "./get_start_date";
@@ -35,7 +37,7 @@ import play from "./play";
35
37
  import setElementSrc$ from "./set_element_src";
36
38
  // eslint-disable-next-line max-len
37
39
  import shouldReloadMediaSourceOnDecipherabilityUpdate from "./should_reload_media_source_on_decipherability_update";
38
- import shouldRenewMediaKeys from "./should_renew_media_keys";
40
+ import shouldRenewMediaKeySystemAccess from "./should_renew_media_key_system_access";
39
41
  import shouldUnsetMediaKeys from "./should_unset_media_keys";
40
42
  import shouldValidateMetadata from "./should_validate_metadata";
41
43
  import shouldWaitForDataBeforeLoaded from "./should_wait_for_data_before_loaded";
@@ -44,4 +46,4 @@ import whenLoadedMetadata$ from "./when_loaded_metadata";
44
46
  // we would prefer to disallow (both for the understandability of the code and
45
47
  // to better exploit tree shaking.
46
48
  patchWebkitSourceBuffer();
47
- export { addClassName, addTextTrack, canPatchISOBMFFSegment, clearElementSrc, closeSession, CustomMediaKeySystemAccess, events, exitFullscreen, generateKeyRequest, getInitData, getStartDate, hasEMEAPIs, isCodecSupported, isFullscreen, isNode, isOffline, isVTTCue, loadSession, makeVTTCue, MediaSource_, onHeightWidthChange, play, requestFullscreen, requestMediaKeySystemAccess, setElementSrc$, setMediaKeys, shouldReloadMediaSourceOnDecipherabilityUpdate, shouldRenewMediaKeys, shouldUnsetMediaKeys, shouldValidateMetadata, shouldWaitForDataBeforeLoaded, tryToChangeSourceBufferType, whenLoadedMetadata$, };
49
+ export { addClassName, addTextTrack, canPatchISOBMFFSegment, canReuseMediaKeys, clearElementSrc, closeSession, CustomMediaKeySystemAccess, enableAudioTrack, events, exitFullscreen, generateKeyRequest, getInitData, getStartDate, hasEMEAPIs, isCodecSupported, isFullscreen, isNode, isOffline, isVTTCue, loadSession, makeVTTCue, MediaSource_, onHeightWidthChange, play, requestFullscreen, requestMediaKeySystemAccess, setElementSrc$, setMediaKeys, shouldReloadMediaSourceOnDecipherabilityUpdate, shouldRenewMediaKeySystemAccess, shouldUnsetMediaKeys, shouldValidateMetadata, shouldWaitForDataBeforeLoaded, tryToChangeSourceBufferType, whenLoadedMetadata$, };
@@ -14,8 +14,8 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  /**
17
- * Returns true if the current target require the media keys to be renewed on
18
- * each content.
17
+ * Returns true if the current target require the MediaKeySystemAccess to be
18
+ * renewed on each content.
19
19
  * @returns {Boolean}
20
20
  */
21
- export default function shouldRenewMediaKeys(): boolean;
21
+ export default function shouldRenewMediaKeySystemAccess(): boolean;
@@ -15,10 +15,10 @@
15
15
  */
16
16
  import { isIE11 } from "./browser_detection";
17
17
  /**
18
- * Returns true if the current target require the media keys to be renewed on
19
- * each content.
18
+ * Returns true if the current target require the MediaKeySystemAccess to be
19
+ * renewed on each content.
20
20
  * @returns {Boolean}
21
21
  */
22
- export default function shouldRenewMediaKeys() {
22
+ export default function shouldRenewMediaKeySystemAccess() {
23
23
  return isIE11;
24
24
  }
@@ -63,6 +63,7 @@ declare class ConfigHandler {
63
63
  BEEFY: number;
64
64
  };
65
65
  DEFAULT_MAX_MANIFEST_REQUEST_RETRY: number;
66
+ DEFAULT_CDN_DOWNGRADE_TIME: number;
66
67
  DEFAULT_MAX_REQUESTS_RETRY_ON_ERROR: number;
67
68
  DEFAULT_MAX_REQUESTS_RETRY_ON_OFFLINE: number;
68
69
  INITIAL_BACKOFF_DELAY_BASE: {
@@ -198,15 +198,23 @@ export declare type IPlaybackObserverEventType =
198
198
  "internal-seeking";
199
199
  /** Information recuperated on the media element on each playback observation. */
200
200
  interface IMediaInfos {
201
- /** Gap between `currentTime` and the next position with un-buffered data. */
202
- bufferGap: number;
201
+ /**
202
+ * Gap between `currentTime` and the next position with un-buffered data.
203
+ * `Infinity` if we don't have buffered data right now.
204
+ * `undefined` if we cannot determine the buffer gap.
205
+ */
206
+ bufferGap: number | undefined;
203
207
  /** Value of `buffered` (buffered ranges) for the media element. */
204
208
  buffered: TimeRanges;
205
- /** The buffered range we are currently playing. */
209
+ /**
210
+ * The buffered range we are currently playing.
211
+ * `null` if no range is currently available.
212
+ * `undefined` if we cannot tell which range is currently available.
213
+ */
206
214
  currentRange: {
207
215
  start: number;
208
216
  end: number;
209
- } | null;
217
+ } | null | undefined;
210
218
  /**
211
219
  * `currentTime` (position) set on the media element at the time of the
212
220
  * PlaybackObserver's measure.
@@ -245,8 +253,9 @@ export interface IRebufferingStatus {
245
253
  /**
246
254
  * Position, in seconds, at which data is awaited.
247
255
  * If `null` the player is rebuffering but not because it is awaiting future data.
256
+ * If `undefined`, that position is unknown.
248
257
  */
249
- position: number | null;
258
+ position: number | null | undefined;
250
259
  }
251
260
  /**
252
261
  * Describes when the player is "frozen".
@@ -193,7 +193,7 @@ var PlaybackObserver = /** @class */ (function () {
193
193
  startedInternalSeekTime = _this._internalSeeksIncoming.shift();
194
194
  }
195
195
  var _lastObservation = lastObservation !== null && lastObservation !== void 0 ? lastObservation : _this._generateInitialObservation();
196
- var mediaTimings = getMediaInfos(_this._mediaElement, tmpEvt);
196
+ var mediaTimings = getMediaInfos(_this._mediaElement, tmpEvt, _this._withMediaSource);
197
197
  var pendingInternalSeek = null;
198
198
  if (mediaTimings.seeking) {
199
199
  if (typeof startedInternalSeekTime === "number") {
@@ -252,7 +252,7 @@ var PlaybackObserver = /** @class */ (function () {
252
252
  }
253
253
  };
254
254
  PlaybackObserver.prototype._generateInitialObservation = function () {
255
- return objectAssign(getMediaInfos(this._mediaElement, "init"), { rebuffering: null,
255
+ return objectAssign(getMediaInfos(this._mediaElement, "init", this._withMediaSource), { rebuffering: null,
256
256
  freezing: null,
257
257
  pendingInternalSeek: null });
258
258
  };
@@ -292,10 +292,13 @@ function getRebufferingEndGap(rebufferingStatus, lowLatencyMode) {
292
292
  * @param {Boolean} lowLatencyMode
293
293
  * @returns {Boolean}
294
294
  */
295
- function hasLoadedUntilTheEnd(currentRange, duration, lowLatencyMode) {
295
+ function hasLoadedUntilTheEnd(currentTime, currentRange, ended, duration, lowLatencyMode) {
296
296
  var REBUFFERING_GAP = config.getCurrent().REBUFFERING_GAP;
297
297
  var suffix = lowLatencyMode ? "LOW_LATENCY" :
298
298
  "DEFAULT";
299
+ if (currentRange === undefined) {
300
+ return ended && Math.abs(duration - currentTime) <= REBUFFERING_GAP[suffix];
301
+ }
299
302
  return currentRange !== null &&
300
303
  (duration - currentRange.end) <= REBUFFERING_GAP[suffix];
301
304
  }
@@ -305,13 +308,26 @@ function hasLoadedUntilTheEnd(currentRange, duration, lowLatencyMode) {
305
308
  * @param {string} event
306
309
  * @returns {Object}
307
310
  */
308
- function getMediaInfos(mediaElement, event) {
311
+ function getMediaInfos(mediaElement, event, withMediaSource) {
309
312
  var buffered = mediaElement.buffered, currentTime = mediaElement.currentTime, duration = mediaElement.duration, ended = mediaElement.ended, paused = mediaElement.paused, playbackRate = mediaElement.playbackRate, readyState = mediaElement.readyState, seeking = mediaElement.seeking;
310
- var currentRange = getRange(buffered, currentTime);
311
- return { bufferGap: currentRange !== null ? currentRange.end - currentTime :
313
+ var currentRange;
314
+ var bufferGap;
315
+ if (!withMediaSource && buffered.length === 0 && readyState >= 3) {
316
+ // Sometimes `buffered` stay empty for directfile contents yet we are able
317
+ // to play. This seems to be linked to browser-side issues but has been
318
+ // encountered on enough platforms (Chrome desktop and PlayStation 4's
319
+ // WebKit for us to do something about it in the player.
320
+ currentRange = undefined;
321
+ bufferGap = undefined;
322
+ }
323
+ else {
324
+ currentRange = getRange(buffered, currentTime);
325
+ bufferGap = currentRange !== null ? currentRange.end - currentTime :
312
326
  // TODO null/0 would probably be
313
327
  // more appropriate
314
- Infinity, buffered: buffered, currentRange: currentRange, position: currentTime, duration: duration, ended: ended, paused: paused, playbackRate: playbackRate, readyState: readyState, seeking: seeking, event: event };
328
+ Infinity;
329
+ }
330
+ return { bufferGap: bufferGap, buffered: buffered, currentRange: currentRange, position: currentTime, duration: duration, ended: ended, paused: paused, playbackRate: playbackRate, readyState: readyState, seeking: seeking, event: event };
315
331
  }
316
332
  /**
317
333
  * Infer rebuffering status of the media based on:
@@ -330,7 +346,7 @@ function getRebufferingStatus(prevObservation, currentInfo, _a) {
330
346
  var REBUFFERING_GAP = config.getCurrent().REBUFFERING_GAP;
331
347
  var currentEvt = currentInfo.event, currentTime = currentInfo.position, bufferGap = currentInfo.bufferGap, currentRange = currentInfo.currentRange, duration = currentInfo.duration, paused = currentInfo.paused, readyState = currentInfo.readyState, ended = currentInfo.ended;
332
348
  var prevRebuffering = prevObservation.rebuffering, prevEvt = prevObservation.event, prevTime = prevObservation.position;
333
- var fullyLoaded = hasLoadedUntilTheEnd(currentRange, duration, lowLatencyMode);
349
+ var fullyLoaded = hasLoadedUntilTheEnd(currentTime, currentRange, ended, duration, lowLatencyMode);
334
350
  var canSwitchToRebuffering = (readyState >= 1 &&
335
351
  currentEvt !== "loadedmetadata" &&
336
352
  prevRebuffering === null &&
@@ -342,24 +358,37 @@ function getRebufferingStatus(prevObservation, currentInfo, _a) {
342
358
  REBUFFERING_GAP.DEFAULT;
343
359
  if (withMediaSource) {
344
360
  if (canSwitchToRebuffering) {
345
- if (bufferGap <= rebufferGap) {
361
+ if (bufferGap === Infinity) {
346
362
  shouldRebuffer = true;
347
- rebufferEndPosition = currentTime + bufferGap;
363
+ rebufferEndPosition = currentTime;
348
364
  }
349
- else if (bufferGap === Infinity) {
365
+ else if (bufferGap === undefined) {
366
+ if (readyState < 3) {
367
+ shouldRebuffer = true;
368
+ rebufferEndPosition = undefined;
369
+ }
370
+ }
371
+ else if (bufferGap <= rebufferGap) {
350
372
  shouldRebuffer = true;
351
- rebufferEndPosition = currentTime;
373
+ rebufferEndPosition = currentTime + bufferGap;
352
374
  }
353
375
  }
354
376
  else if (prevRebuffering !== null) {
355
377
  var resumeGap = getRebufferingEndGap(prevRebuffering, lowLatencyMode);
356
378
  if (shouldRebuffer !== true && prevRebuffering !== null && readyState > 1 &&
357
- (fullyLoaded || ended || (bufferGap < Infinity && bufferGap > resumeGap))) {
379
+ (fullyLoaded || ended ||
380
+ (bufferGap !== undefined && isFinite(bufferGap) && bufferGap > resumeGap)) ||
381
+ (bufferGap === undefined && readyState >= 3)) {
358
382
  shouldStopRebuffer = true;
359
383
  }
360
- else if (bufferGap === Infinity || bufferGap <= resumeGap) {
361
- rebufferEndPosition = bufferGap === Infinity ? currentTime :
362
- currentTime + bufferGap;
384
+ else if (bufferGap === undefined) {
385
+ rebufferEndPosition = undefined;
386
+ }
387
+ else if (bufferGap === Infinity) {
388
+ rebufferEndPosition = currentTime;
389
+ }
390
+ else if (bufferGap <= resumeGap) {
391
+ rebufferEndPosition = currentTime + bufferGap;
363
392
  }
364
393
  }
365
394
  }
@@ -368,17 +397,19 @@ function getRebufferingStatus(prevObservation, currentInfo, _a) {
368
397
  // between two consecutive timeupdates
369
398
  else {
370
399
  if (canSwitchToRebuffering &&
371
- (!paused && currentEvt === "timeupdate" &&
372
- prevEvt === "timeupdate" && currentTime === prevTime ||
373
- currentEvt === "seeking" && bufferGap === Infinity)) {
400
+ ((!paused &&
401
+ currentEvt === "timeupdate" && prevEvt === "timeupdate" &&
402
+ currentTime === prevTime) ||
403
+ (currentEvt === "seeking" && (bufferGap === Infinity || (bufferGap === undefined && readyState < 3))))) {
374
404
  shouldRebuffer = true;
375
405
  }
376
406
  else if (prevRebuffering !== null &&
377
- (currentEvt !== "seeking" && currentTime !== prevTime ||
407
+ ((currentEvt !== "seeking" && currentTime !== prevTime) ||
378
408
  currentEvt === "canplay" ||
379
- bufferGap < Infinity &&
409
+ (bufferGap === undefined && readyState >= 3) ||
410
+ (bufferGap !== undefined && bufferGap < Infinity &&
380
411
  (bufferGap > getRebufferingEndGap(prevRebuffering, lowLatencyMode) ||
381
- fullyLoaded || ended))) {
412
+ fullyLoaded || ended)))) {
382
413
  shouldStopRebuffer = true;
383
414
  }
384
415
  }
@@ -433,6 +464,7 @@ function getFreezingStatus(prevObservation, currentInfo) {
433
464
  return prevObservation.freezing; // Stay in it
434
465
  }
435
466
  return currentInfo.event === "timeupdate" &&
467
+ currentInfo.bufferGap !== undefined &&
436
468
  currentInfo.bufferGap > MINIMUM_BUFFER_AMOUNT_BEFORE_FREEZING &&
437
469
  !currentInfo.ended &&
438
470
  !currentInfo.paused &&
@@ -112,8 +112,11 @@ declare class Player extends EventEmitter<IPublicAPIEvent> {
112
112
  private _priv_contentEventsMemory;
113
113
  /** Determines whether or not the player should stop at the end of video playback. */
114
114
  private readonly _priv_stopAtEnd;
115
- /** Information about last content being played. */
116
- private _priv_lastContentPlaybackInfos;
115
+ /**
116
+ * Information that can be relied on once `reload` is called.
117
+ * It should refer to the last content being played.
118
+ */
119
+ private _priv_reloadingMetadata;
117
120
  /** All possible Error types emitted by the RxPlayer. */
118
121
  static get ErrorTypes(): Record<IErrorType, IErrorType>;
119
122
  /** All possible Error codes emitted by the RxPlayer. */
@@ -160,8 +163,7 @@ declare class Player extends EventEmitter<IPublicAPIEvent> {
160
163
  */
161
164
  loadVideo(opts: ILoadVideoOptions): void;
162
165
  /**
163
- * Reload last content. Init media playback without fetching again
164
- * the manifest.
166
+ * Reload the last loaded content.
165
167
  * @param {Object} reloadOpts
166
168
  */
167
169
  reload(reloadOpts?: {
@@ -169,6 +171,7 @@ declare class Player extends EventEmitter<IPublicAPIEvent> {
169
171
  position?: number;
170
172
  relative?: number;
171
173
  };
174
+ autoPlay?: boolean;
172
175
  }): void;
173
176
  /**
174
177
  * From given options, initialize content playback.