rx-player 3.28.0-dev.2022071100 → 3.29.0-dev.2022090500

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 (222) hide show
  1. package/.github/workflows/checks.yml +20 -18
  2. package/CHANGELOG.md +24 -2
  3. package/VERSION +1 -1
  4. package/dist/_esm5.processed/compat/eme/load_session.d.ts +5 -6
  5. package/dist/_esm5.processed/compat/eme/load_session.js +5 -6
  6. package/dist/_esm5.processed/compat/event_listeners.d.ts +18 -2
  7. package/dist/_esm5.processed/compat/event_listeners.js +64 -2
  8. package/dist/_esm5.processed/compat/on_height_width_change.d.ts +5 -4
  9. package/dist/_esm5.processed/compat/on_height_width_change.js +43 -34
  10. package/dist/_esm5.processed/core/api/media_element_track_choice_manager.js +1 -1
  11. package/dist/_esm5.processed/core/api/playback_observer.d.ts +12 -2
  12. package/dist/_esm5.processed/core/api/playback_observer.js +27 -12
  13. package/dist/_esm5.processed/core/api/public_api.js +14 -14
  14. package/dist/_esm5.processed/core/decrypt/create_session.js +33 -4
  15. package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.d.ts +14 -0
  16. package/dist/_esm5.processed/core/decrypt/utils/loaded_sessions_store.js +25 -0
  17. package/dist/_esm5.processed/core/fetchers/manifest/manifest_fetcher.d.ts +7 -0
  18. package/dist/_esm5.processed/core/fetchers/manifest/manifest_fetcher.js +10 -2
  19. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.d.ts +9 -2
  20. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher.js +11 -5
  21. package/dist/_esm5.processed/core/fetchers/segment/segment_fetcher_creator.d.ts +7 -0
  22. package/dist/_esm5.processed/core/init/content_time_boundaries_observer.js +110 -38
  23. package/dist/_esm5.processed/core/init/initialize_directfile.js +1 -1
  24. package/dist/_esm5.processed/core/init/load_on_media_source.js +1 -1
  25. package/dist/_esm5.processed/core/init/stall_avoider.d.ts +4 -2
  26. package/dist/_esm5.processed/core/init/stall_avoider.js +32 -26
  27. package/dist/_esm5.processed/core/segment_buffers/garbage_collector.d.ts +12 -6
  28. package/dist/_esm5.processed/core/segment_buffers/garbage_collector.js +142 -78
  29. package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.d.ts +18 -16
  30. package/dist/_esm5.processed/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.js +53 -41
  31. package/dist/_esm5.processed/core/segment_buffers/implementations/image/image_segment_buffer.d.ts +6 -5
  32. package/dist/_esm5.processed/core/segment_buffers/implementations/image/image_segment_buffer.js +37 -39
  33. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.d.ts +23 -22
  34. package/dist/_esm5.processed/core/segment_buffers/implementations/text/html/html_text_segment_buffer.js +84 -72
  35. package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.d.ts +6 -12
  36. package/dist/_esm5.processed/core/segment_buffers/implementations/text/native/native_text_segment_buffer.js +33 -43
  37. package/dist/_esm5.processed/core/segment_buffers/implementations/types.d.ts +12 -9
  38. package/dist/_esm5.processed/core/segment_buffers/segment_buffers_store.d.ts +7 -6
  39. package/dist/_esm5.processed/core/segment_buffers/segment_buffers_store.js +17 -10
  40. package/dist/_esm5.processed/core/stream/orchestrator/stream_orchestrator.js +20 -9
  41. package/dist/_esm5.processed/core/stream/period/period_stream.js +25 -14
  42. package/dist/_esm5.processed/core/stream/representation/append_segment_to_buffer.d.ts +4 -7
  43. package/dist/_esm5.processed/core/stream/representation/append_segment_to_buffer.js +80 -23
  44. package/dist/_esm5.processed/core/stream/representation/check_for_discontinuity.js +21 -9
  45. package/dist/_esm5.processed/core/stream/representation/force_garbage_collection.d.ts +5 -4
  46. package/dist/_esm5.processed/core/stream/representation/force_garbage_collection.js +78 -26
  47. package/dist/_esm5.processed/core/stream/representation/get_buffer_status.js +28 -32
  48. package/dist/_esm5.processed/core/stream/representation/push_init_segment.js +7 -1
  49. package/dist/_esm5.processed/core/stream/representation/push_media_segment.js +7 -1
  50. package/dist/_esm5.processed/core/stream/representation/representation_stream.js +15 -8
  51. package/dist/_esm5.processed/default_config.js +1 -1
  52. package/dist/_esm5.processed/errors/custom_loader_error.d.ts +3 -2
  53. package/dist/_esm5.processed/errors/custom_loader_error.js +3 -2
  54. package/dist/_esm5.processed/errors/encrypted_media_error.d.ts +1 -2
  55. package/dist/_esm5.processed/errors/encrypted_media_error.js +0 -1
  56. package/dist/_esm5.processed/errors/error_codes.d.ts +6 -1
  57. package/dist/_esm5.processed/errors/media_error.d.ts +1 -2
  58. package/dist/_esm5.processed/errors/media_error.js +0 -1
  59. package/dist/_esm5.processed/errors/network_error.d.ts +1 -2
  60. package/dist/_esm5.processed/errors/network_error.js +0 -1
  61. package/dist/_esm5.processed/errors/other_error.d.ts +1 -2
  62. package/dist/_esm5.processed/errors/other_error.js +0 -1
  63. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/get_initialized_source_buffer.js +5 -2
  64. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/push_data.js +5 -2
  65. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/remove_buffer_around_time.js +9 -2
  66. package/dist/_esm5.processed/experimental/tools/VideoThumbnailLoader/thumbnail_loader.js +3 -1
  67. package/dist/_esm5.processed/experimental/tools/createMetaplaylist/get_duration_from_manifest.js +4 -3
  68. package/dist/_esm5.processed/manifest/manifest.d.ts +1 -1
  69. package/dist/_esm5.processed/manifest/manifest.js +1 -1
  70. package/dist/_esm5.processed/manifest/representation_index/static.d.ts +21 -6
  71. package/dist/_esm5.processed/manifest/representation_index/static.js +26 -8
  72. package/dist/_esm5.processed/manifest/representation_index/types.d.ts +55 -44
  73. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/base.d.ts +21 -8
  74. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/base.js +25 -10
  75. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.d.ts +26 -12
  76. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/list.js +26 -13
  77. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.d.ts +23 -7
  78. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/template.js +65 -22
  79. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.d.ts +20 -3
  80. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.js +57 -7
  81. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/{is_period_fulfilled.d.ts → utils.d.ts} +3 -6
  82. package/dist/_esm5.processed/parsers/manifest/dash/common/indexes/{is_period_fulfilled.js → utils.js} +4 -8
  83. package/dist/_esm5.processed/parsers/manifest/dash/common/parse_periods.js +1 -1
  84. package/dist/_esm5.processed/parsers/manifest/local/parse_local_manifest.js +5 -8
  85. package/dist/_esm5.processed/parsers/manifest/local/representation_index.d.ts +21 -8
  86. package/dist/_esm5.processed/parsers/manifest/local/representation_index.js +49 -14
  87. package/dist/_esm5.processed/parsers/manifest/local/types.d.ts +16 -0
  88. package/dist/_esm5.processed/parsers/manifest/metaplaylist/representation_index.d.ts +20 -6
  89. package/dist/_esm5.processed/parsers/manifest/metaplaylist/representation_index.js +28 -10
  90. package/dist/_esm5.processed/parsers/manifest/smooth/create_parser.js +4 -4
  91. package/dist/_esm5.processed/parsers/manifest/smooth/representation_index.d.ts +21 -12
  92. package/dist/_esm5.processed/parsers/manifest/smooth/representation_index.js +39 -14
  93. package/dist/_esm5.processed/parsers/manifest/utils/get_first_time_from_adaptation.js +1 -1
  94. package/dist/_esm5.processed/parsers/manifest/utils/get_last_time_from_adaptation.js +1 -1
  95. package/dist/_esm5.processed/public_types.d.ts +22 -3
  96. package/dist/_esm5.processed/transports/dash/add_segment_integrity_checks_to_loader.js +2 -2
  97. package/dist/_esm5.processed/transports/dash/image_pipelines.d.ts +3 -2
  98. package/dist/_esm5.processed/transports/dash/image_pipelines.js +3 -1
  99. package/dist/_esm5.processed/transports/dash/init_segment_loader.d.ts +3 -2
  100. package/dist/_esm5.processed/transports/dash/init_segment_loader.js +12 -6
  101. package/dist/_esm5.processed/transports/dash/low_latency_segment_loader.d.ts +3 -2
  102. package/dist/_esm5.processed/transports/dash/low_latency_segment_loader.js +3 -2
  103. package/dist/_esm5.processed/transports/dash/manifest_parser.js +6 -2
  104. package/dist/_esm5.processed/transports/dash/segment_loader.d.ts +3 -2
  105. package/dist/_esm5.processed/transports/dash/segment_loader.js +12 -9
  106. package/dist/_esm5.processed/transports/dash/text_loader.js +6 -3
  107. package/dist/_esm5.processed/transports/local/pipelines.d.ts +2 -2
  108. package/dist/_esm5.processed/transports/local/pipelines.js +6 -6
  109. package/dist/_esm5.processed/transports/local/segment_loader.d.ts +3 -2
  110. package/dist/_esm5.processed/transports/local/segment_loader.js +4 -3
  111. package/dist/_esm5.processed/transports/metaplaylist/manifest_loader.d.ts +2 -2
  112. package/dist/_esm5.processed/transports/metaplaylist/manifest_loader.js +5 -2
  113. package/dist/_esm5.processed/transports/metaplaylist/pipelines.js +15 -12
  114. package/dist/_esm5.processed/transports/smooth/pipelines.d.ts +1 -1
  115. package/dist/_esm5.processed/transports/smooth/pipelines.js +18 -14
  116. package/dist/_esm5.processed/transports/smooth/segment_loader.d.ts +2 -2
  117. package/dist/_esm5.processed/transports/smooth/segment_loader.js +9 -7
  118. package/dist/_esm5.processed/transports/types.d.ts +26 -3
  119. package/dist/_esm5.processed/transports/utils/call_custom_manifest_loader.d.ts +2 -2
  120. package/dist/_esm5.processed/transports/utils/call_custom_manifest_loader.js +3 -3
  121. package/dist/_esm5.processed/transports/utils/generate_manifest_loader.d.ts +2 -2
  122. package/dist/_esm5.processed/transports/utils/generate_manifest_loader.js +9 -6
  123. package/dist/_esm5.processed/utils/deep_merge.d.ts +1 -1
  124. package/dist/_esm5.processed/utils/deep_merge.js +6 -5
  125. package/dist/_esm5.processed/utils/request/fetch.js +7 -8
  126. package/dist/_esm5.processed/utils/request/xhr.d.ts +1 -1
  127. package/dist/_esm5.processed/utils/request/xhr.js +28 -14
  128. package/dist/_esm5.processed/utils/task_canceller.d.ts +1 -5
  129. package/dist/_esm5.processed/utils/task_canceller.js +1 -5
  130. package/dist/mpd-parser.wasm +0 -0
  131. package/dist/rx-player.js +2497 -1752
  132. package/dist/rx-player.min.js +1 -1
  133. package/jest.config.js +5 -0
  134. package/package.json +31 -30
  135. package/sonar-project.properties +1 -1
  136. package/src/compat/eme/load_session.ts +5 -6
  137. package/src/compat/event_listeners.ts +86 -1
  138. package/src/compat/on_height_width_change.ts +48 -49
  139. package/src/core/api/media_element_track_choice_manager.ts +1 -1
  140. package/src/core/api/playback_observer.ts +34 -14
  141. package/src/core/api/public_api.ts +23 -18
  142. package/src/core/decrypt/create_session.ts +28 -2
  143. package/src/core/decrypt/utils/loaded_sessions_store.ts +29 -0
  144. package/src/core/fetchers/manifest/manifest_fetcher.ts +20 -2
  145. package/src/core/fetchers/segment/segment_fetcher.ts +24 -4
  146. package/src/core/fetchers/segment/segment_fetcher_creator.ts +7 -0
  147. package/src/core/init/content_time_boundaries_observer.ts +116 -42
  148. package/src/core/init/initialize_directfile.ts +1 -1
  149. package/src/core/init/load_on_media_source.ts +1 -0
  150. package/src/core/init/stall_avoider.ts +40 -26
  151. package/src/core/segment_buffers/garbage_collector.ts +55 -47
  152. package/src/core/segment_buffers/implementations/audio_video/audio_video_segment_buffer.ts +92 -70
  153. package/src/core/segment_buffers/implementations/image/image_segment_buffer.ts +37 -42
  154. package/src/core/segment_buffers/implementations/text/html/html_text_segment_buffer.ts +103 -105
  155. package/src/core/segment_buffers/implementations/text/native/native_text_segment_buffer.ts +35 -46
  156. package/src/core/segment_buffers/implementations/types.ts +22 -9
  157. package/src/core/segment_buffers/segment_buffers_store.ts +23 -14
  158. package/src/core/stream/orchestrator/stream_orchestrator.ts +31 -12
  159. package/src/core/stream/period/period_stream.ts +31 -18
  160. package/src/core/stream/representation/append_segment_to_buffer.ts +27 -42
  161. package/src/core/stream/representation/check_for_discontinuity.ts +28 -10
  162. package/src/core/stream/representation/force_garbage_collection.ts +28 -32
  163. package/src/core/stream/representation/get_buffer_status.ts +34 -37
  164. package/src/core/stream/representation/push_init_segment.ts +12 -6
  165. package/src/core/stream/representation/push_media_segment.ts +12 -6
  166. package/src/core/stream/representation/representation_stream.ts +11 -5
  167. package/src/default_config.ts +17 -17
  168. package/src/errors/custom_loader_error.ts +3 -2
  169. package/src/errors/encrypted_media_error.ts +1 -2
  170. package/src/errors/error_codes.ts +2 -2
  171. package/src/errors/media_error.ts +1 -2
  172. package/src/errors/network_error.ts +1 -2
  173. package/src/errors/other_error.ts +1 -2
  174. package/src/experimental/tools/VideoThumbnailLoader/get_initialized_source_buffer.ts +7 -2
  175. package/src/experimental/tools/VideoThumbnailLoader/push_data.ts +6 -2
  176. package/src/experimental/tools/VideoThumbnailLoader/remove_buffer_around_time.ts +10 -2
  177. package/src/experimental/tools/VideoThumbnailLoader/thumbnail_loader.ts +3 -1
  178. package/src/experimental/tools/createMetaplaylist/get_duration_from_manifest.ts +4 -3
  179. package/src/manifest/__tests__/adaptation.test.ts +4 -3
  180. package/src/manifest/__tests__/representation.test.ts +4 -3
  181. package/src/manifest/manifest.ts +1 -1
  182. package/src/manifest/representation_index/__tests__/static.test.ts +5 -4
  183. package/src/manifest/representation_index/static.ts +28 -9
  184. package/src/manifest/representation_index/types.ts +62 -46
  185. package/src/parsers/manifest/dash/common/indexes/base.ts +27 -11
  186. package/src/parsers/manifest/dash/common/indexes/list.ts +32 -15
  187. package/src/parsers/manifest/dash/common/indexes/template.ts +73 -27
  188. package/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts +60 -8
  189. package/src/parsers/manifest/dash/common/indexes/{is_period_fulfilled.ts → utils.ts} +4 -13
  190. package/src/parsers/manifest/dash/common/parse_periods.ts +1 -1
  191. package/src/parsers/manifest/local/parse_local_manifest.ts +8 -20
  192. package/src/parsers/manifest/local/representation_index.ts +51 -16
  193. package/src/parsers/manifest/local/types.ts +13 -0
  194. package/src/parsers/manifest/metaplaylist/representation_index.ts +31 -11
  195. package/src/parsers/manifest/smooth/create_parser.ts +4 -4
  196. package/src/parsers/manifest/smooth/representation_index.ts +40 -15
  197. package/src/parsers/manifest/utils/__tests__/get_first_time_from_adaptations.test.ts +4 -3
  198. package/src/parsers/manifest/utils/__tests__/get_last_time_from_adaptation.test.ts +4 -3
  199. package/src/parsers/manifest/utils/get_first_time_from_adaptation.ts +1 -1
  200. package/src/parsers/manifest/utils/get_last_time_from_adaptation.ts +1 -1
  201. package/src/public_types.ts +28 -4
  202. package/src/transports/dash/add_segment_integrity_checks_to_loader.ts +2 -2
  203. package/src/transports/dash/image_pipelines.ts +4 -0
  204. package/src/transports/dash/init_segment_loader.ts +8 -0
  205. package/src/transports/dash/low_latency_segment_loader.ts +4 -0
  206. package/src/transports/dash/manifest_parser.ts +4 -0
  207. package/src/transports/dash/segment_loader.ts +21 -5
  208. package/src/transports/dash/text_loader.ts +7 -2
  209. package/src/transports/local/pipelines.ts +7 -5
  210. package/src/transports/local/segment_loader.ts +4 -2
  211. package/src/transports/metaplaylist/manifest_loader.ts +9 -2
  212. package/src/transports/metaplaylist/pipelines.ts +16 -8
  213. package/src/transports/smooth/pipelines.ts +17 -9
  214. package/src/transports/smooth/segment_loader.ts +9 -1
  215. package/src/transports/types.ts +28 -1
  216. package/src/transports/utils/call_custom_manifest_loader.ts +8 -2
  217. package/src/transports/utils/generate_manifest_loader.ts +18 -5
  218. package/src/utils/__tests__/initialization_segment_cache.test.ts +7 -0
  219. package/src/utils/deep_merge.ts +7 -4
  220. package/src/utils/request/fetch.ts +7 -8
  221. package/src/utils/request/xhr.ts +31 -15
  222. package/src/utils/task_canceller.ts +1 -5
@@ -110,7 +110,7 @@ function createAndTryToRetrievePersistentSession(loadedSessionsStore, persistent
110
110
  */
111
111
  function recreatePersistentSession() {
112
112
  return __awaiter(this, void 0, void 0, function () {
113
- var persistentEntry, newEntry;
113
+ var persistentEntry, err_2, newEntry;
114
114
  return __generator(this, function (_a) {
115
115
  switch (_a.label) {
116
116
  case 0:
@@ -122,9 +122,30 @@ function createAndTryToRetrievePersistentSession(loadedSessionsStore, persistent
122
122
  if (persistentEntry !== null) {
123
123
  persistentSessionsStore.delete(persistentEntry.sessionId);
124
124
  }
125
- return [4 /*yield*/, loadedSessionsStore.closeSession(entry.mediaKeySession)];
125
+ _a.label = 1;
126
126
  case 1:
127
+ _a.trys.push([1, 3, , 4]);
128
+ return [4 /*yield*/, loadedSessionsStore.closeSession(entry.mediaKeySession)];
129
+ case 2:
127
130
  _a.sent();
131
+ return [3 /*break*/, 4];
132
+ case 3:
133
+ err_2 = _a.sent();
134
+ // From reading the EME specification in details, it seems that a
135
+ // `MediaKeySession`'s ability to be closed is tightly linked to its
136
+ // possession of a "sanitized session ID" set as `sessionId`.
137
+ // This is never clearly stated however and I'm (Paul B.) always afraid of
138
+ // breaking compatibility when it comes to EME code.
139
+ // So we still try to close the `MediaKeySession` in any case, only, if it
140
+ // fails and it didn't had any `sessionId` set, we just ignore the error.
141
+ // Note that trying to close the `MediaKeySession` might incur some delays
142
+ // in those rare cases.
143
+ if (entry.mediaKeySession.sessionId !== "") {
144
+ throw err_2;
145
+ }
146
+ loadedSessionsStore.removeSessionWithoutClosingIt(entry.mediaKeySession);
147
+ return [3 /*break*/, 4];
148
+ case 4:
128
149
  if (cancelSignal.cancellationError !== null) {
129
150
  throw cancelSignal.cancellationError;
130
151
  }
@@ -135,7 +156,7 @@ function createAndTryToRetrievePersistentSession(loadedSessionsStore, persistent
135
156
  });
136
157
  });
137
158
  }
138
- var entry, storedEntry, hasLoadedSession, err_1;
159
+ var entry, storedEntry, hasLoadedSession, newEntry, err_1;
139
160
  return __generator(this, function (_a) {
140
161
  switch (_a.label) {
141
162
  case 0:
@@ -158,8 +179,16 @@ function createAndTryToRetrievePersistentSession(loadedSessionsStore, persistent
158
179
  if (!hasLoadedSession) {
159
180
  log.warn("DRM: No data stored for the loaded session");
160
181
  persistentSessionsStore.delete(storedEntry.sessionId);
182
+ // The EME specification is kind of implicit about it but it seems from my
183
+ // understanding (Paul B.) that a MediaKeySession on wich a `load` attempt
184
+ // did not succeed due to the loaded session not being found by the
185
+ // browser/CDM, should neither be used anymore nor closed.
186
+ // Thus, we're creating another `"persistent-license"` `MediaKeySession`
187
+ // in that specific case.
188
+ loadedSessionsStore.removeSessionWithoutClosingIt(entry.mediaKeySession);
189
+ newEntry = loadedSessionsStore.createSession(initData, "persistent-license");
161
190
  return [2 /*return*/, { type: "created-session" /* MediaKeySessionLoadingType.Created */,
162
- value: entry }];
191
+ value: newEntry }];
163
192
  }
164
193
  if (hasLoadedSession && isSessionUsable(entry.mediaKeySession)) {
165
194
  persistentSessionsStore.add(initData, initData.keyIds, entry.mediaKeySession);
@@ -106,6 +106,20 @@ export default class LoadedSessionsStore {
106
106
  * @returns {Promise}
107
107
  */
108
108
  closeAllSessions(): Promise<void>;
109
+ /**
110
+ * Find the given `MediaKeySession` in the `LoadedSessionsStore` and removes
111
+ * any reference to it without actually closing it.
112
+ *
113
+ * Returns `true` if the given `mediaKeySession` has been found and removed,
114
+ * `false` otherwise.
115
+ *
116
+ * Note that this may create a `MediaKeySession` leakage in the wrong
117
+ * conditions, cases where this method should be called should be very
118
+ * carefully evaluated.
119
+ * @param {MediaKeySession} mediaKeySession
120
+ * @returns {boolean}
121
+ */
122
+ removeSessionWithoutClosingIt(mediaKeySession: MediaKeySession | ICustomMediaKeySession): boolean;
109
123
  /**
110
124
  * Get the index of a stored MediaKeySession entry based on its
111
125
  * `KeySessionRecord`.
@@ -62,6 +62,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
62
62
  };
63
63
  import { closeSession, generateKeyRequest, loadSession, } from "../../../compat";
64
64
  import log from "../../../log";
65
+ import assert from "../../../utils/assert";
65
66
  import isNullOrUndefined from "../../../utils/is_null_or_undefined";
66
67
  import KeySessionRecord from "./key_session_record";
67
68
  /**
@@ -346,6 +347,30 @@ var LoadedSessionsStore = /** @class */ (function () {
346
347
  });
347
348
  });
348
349
  };
350
+ /**
351
+ * Find the given `MediaKeySession` in the `LoadedSessionsStore` and removes
352
+ * any reference to it without actually closing it.
353
+ *
354
+ * Returns `true` if the given `mediaKeySession` has been found and removed,
355
+ * `false` otherwise.
356
+ *
357
+ * Note that this may create a `MediaKeySession` leakage in the wrong
358
+ * conditions, cases where this method should be called should be very
359
+ * carefully evaluated.
360
+ * @param {MediaKeySession} mediaKeySession
361
+ * @returns {boolean}
362
+ */
363
+ LoadedSessionsStore.prototype.removeSessionWithoutClosingIt = function (mediaKeySession) {
364
+ assert(mediaKeySession.sessionId === "", "Initialized `MediaKeySession`s should always be properly closed");
365
+ for (var i = this._storage.length - 1; i >= 0; i--) {
366
+ var stored = this._storage[i];
367
+ if (stored.mediaKeySession === mediaKeySession) {
368
+ this._storage.splice(i, 1);
369
+ return true;
370
+ }
371
+ }
372
+ return false;
373
+ };
349
374
  /**
350
375
  * Get the index of a stored MediaKeySession entry based on its
351
376
  * `KeySessionRecord`.
@@ -74,6 +74,13 @@ export interface IManifestFetcherSettings {
74
74
  maxRetryRegular: number | undefined;
75
75
  /** Maximum number of time a request be retried when the user is offline. */
76
76
  maxRetryOffline: number | undefined;
77
+ /**
78
+ * Timeout after which request are aborted and, depending on other options,
79
+ * retried.
80
+ * To set to `-1` for no timeout.
81
+ * `undefined` will lead to a default, large, timeout being used.
82
+ */
83
+ requestTimeout: number | undefined;
77
84
  }
78
85
  /**
79
86
  * Class allowing to facilitate the task of loading and parsing a Manifest.
@@ -54,6 +54,7 @@ import config from "../../../config";
54
54
  import { formatError } from "../../../errors";
55
55
  import log from "../../../log";
56
56
  import assert from "../../../utils/assert";
57
+ import isNullOrUndefined from "../../../utils/is_null_or_undefined";
57
58
  import TaskCanceller from "../../../utils/task_canceller";
58
59
  import errorSelector from "../utils/error_selector";
59
60
  import { tryRequestPromiseWithBackoff, } from "../utils/try_urls_with_backoff";
@@ -106,6 +107,7 @@ var ManifestFetcher = /** @class */ (function () {
106
107
  ManifestFetcher.prototype.fetch = function (url) {
107
108
  var _this = this;
108
109
  return new Observable(function (obs) {
110
+ var settings = _this._settings;
109
111
  var pipelines = _this._pipelines;
110
112
  var requestUrl = url !== null && url !== void 0 ? url : _this._manifestUrl;
111
113
  /** `true` if the loading pipeline is already completely executed. */
@@ -160,12 +162,18 @@ var ManifestFetcher = /** @class */ (function () {
160
162
  * Call the loader part of the pipeline, retrying if it fails according
161
163
  * to the current settings.
162
164
  * Returns the Promise of the last attempt.
163
- * @param {string | undefined} resolverUrl
165
+ * @param {string | undefined} manifestUrl
164
166
  * @returns {Promise}
165
167
  */
166
168
  function callLoaderWithRetries(manifestUrl) {
167
169
  var loadManifest = pipelines.loadManifest;
168
- var callLoader = function () { return loadManifest(manifestUrl, canceller.signal); };
170
+ var requestTimeout = isNullOrUndefined(settings.requestTimeout) ?
171
+ config.getCurrent().DEFAULT_REQUEST_TIMEOUT :
172
+ settings.requestTimeout;
173
+ if (requestTimeout < 0) {
174
+ requestTimeout = undefined;
175
+ }
176
+ var callLoader = function () { return loadManifest(manifestUrl, { timeout: requestTimeout }, canceller.signal); };
169
177
  return tryRequestPromiseWithBackoff(callLoader, backoffSettings, canceller.signal);
170
178
  }
171
179
  });
@@ -26,7 +26,7 @@ import { IBufferType } from "../../segment_buffers";
26
26
  * `options` argument, which may retry a segment request when it fails.
27
27
  *
28
28
  * @param {string} bufferType
29
- * @param {Object} transport
29
+ * @param {Object} pipeline
30
30
  * @param {Object} callbacks
31
31
  * @param {Object} options
32
32
  * @returns {Function}
@@ -123,14 +123,21 @@ export interface ISegmentFetcherOptions {
123
123
  * currently offline.
124
124
  */
125
125
  maxRetryOffline: number;
126
+ /**
127
+ * Timeout after which request are aborted and, depending on other options,
128
+ * retried.
129
+ * To set to `-1` for no timeout.
130
+ */
131
+ requestTimeout: number;
126
132
  }
127
133
  /**
128
134
  * @param {string} bufferType
129
135
  * @param {Object}
130
136
  * @returns {Object}
131
137
  */
132
- export declare function getSegmentFetcherOptions(bufferType: string, { maxRetryRegular, maxRetryOffline, lowLatencyMode }: {
138
+ export declare function getSegmentFetcherOptions(bufferType: string, { maxRetryRegular, maxRetryOffline, lowLatencyMode, requestTimeout }: {
133
139
  maxRetryRegular?: number | undefined;
134
140
  maxRetryOffline?: number | undefined;
141
+ requestTimeout?: number | undefined;
135
142
  lowLatencyMode: boolean;
136
143
  }): ISegmentFetcherOptions;
@@ -34,12 +34,16 @@ var generateRequestID = idGenerator();
34
34
  * `options` argument, which may retry a segment request when it fails.
35
35
  *
36
36
  * @param {string} bufferType
37
- * @param {Object} transport
37
+ * @param {Object} pipeline
38
38
  * @param {Object} callbacks
39
39
  * @param {Object} options
40
40
  * @returns {Function}
41
41
  */
42
42
  export default function createSegmentFetcher(bufferType, pipeline, callbacks, options) {
43
+ var requestOptions = {
44
+ timeout: options.requestTimeout < 0 ? undefined :
45
+ options.requestTimeout,
46
+ };
43
47
  /**
44
48
  * Cache audio and video initialization segments.
45
49
  * This allows to avoid doing too many requests for what are usually very
@@ -203,7 +207,7 @@ export default function createSegmentFetcher(bufferType, pipeline, callbacks, op
203
207
  * @returns {Promise}
204
208
  */
205
209
  function callLoaderWithUrl(url, cancellationSignal) {
206
- return loadSegment(url, content, cancellationSignal, loaderCallbacks);
210
+ return loadSegment(url, content, requestOptions, cancellationSignal, loaderCallbacks);
207
211
  }
208
212
  /**
209
213
  * Generate function allowing to parse a loaded segment.
@@ -272,13 +276,15 @@ export default function createSegmentFetcher(bufferType, pipeline, callbacks, op
272
276
  * @returns {Object}
273
277
  */
274
278
  export function getSegmentFetcherOptions(bufferType, _a) {
275
- var maxRetryRegular = _a.maxRetryRegular, maxRetryOffline = _a.maxRetryOffline, lowLatencyMode = _a.lowLatencyMode;
276
- var _b = config.getCurrent(), DEFAULT_MAX_REQUESTS_RETRY_ON_ERROR = _b.DEFAULT_MAX_REQUESTS_RETRY_ON_ERROR, DEFAULT_MAX_REQUESTS_RETRY_ON_OFFLINE = _b.DEFAULT_MAX_REQUESTS_RETRY_ON_OFFLINE, INITIAL_BACKOFF_DELAY_BASE = _b.INITIAL_BACKOFF_DELAY_BASE, MAX_BACKOFF_DELAY_BASE = _b.MAX_BACKOFF_DELAY_BASE;
279
+ var maxRetryRegular = _a.maxRetryRegular, maxRetryOffline = _a.maxRetryOffline, lowLatencyMode = _a.lowLatencyMode, requestTimeout = _a.requestTimeout;
280
+ var _b = config.getCurrent(), DEFAULT_MAX_REQUESTS_RETRY_ON_ERROR = _b.DEFAULT_MAX_REQUESTS_RETRY_ON_ERROR, DEFAULT_REQUEST_TIMEOUT = _b.DEFAULT_REQUEST_TIMEOUT, DEFAULT_MAX_REQUESTS_RETRY_ON_OFFLINE = _b.DEFAULT_MAX_REQUESTS_RETRY_ON_OFFLINE, INITIAL_BACKOFF_DELAY_BASE = _b.INITIAL_BACKOFF_DELAY_BASE, MAX_BACKOFF_DELAY_BASE = _b.MAX_BACKOFF_DELAY_BASE;
277
281
  return { maxRetryRegular: bufferType === "image" ? 0 :
278
282
  maxRetryRegular !== null && maxRetryRegular !== void 0 ? maxRetryRegular : DEFAULT_MAX_REQUESTS_RETRY_ON_ERROR,
279
283
  maxRetryOffline: maxRetryOffline !== null && maxRetryOffline !== void 0 ? maxRetryOffline : DEFAULT_MAX_REQUESTS_RETRY_ON_OFFLINE,
280
284
  baseDelay: lowLatencyMode ? INITIAL_BACKOFF_DELAY_BASE.LOW_LATENCY :
281
285
  INITIAL_BACKOFF_DELAY_BASE.REGULAR,
282
286
  maxDelay: lowLatencyMode ? MAX_BACKOFF_DELAY_BASE.LOW_LATENCY :
283
- MAX_BACKOFF_DELAY_BASE.REGULAR };
287
+ MAX_BACKOFF_DELAY_BASE.REGULAR,
288
+ requestTimeout: isNullOrUndefined(requestTimeout) ? DEFAULT_REQUEST_TIMEOUT :
289
+ requestTimeout };
284
290
  }
@@ -91,4 +91,11 @@ export interface ISegmentFetcherCreatorBackoffOptions {
91
91
  maxRetryRegular: number | undefined;
92
92
  /** Maximum number of time a request be retried when the user is offline. */
93
93
  maxRetryOffline: number | undefined;
94
+ /**
95
+ * Timeout after which request are aborted and, depending on other options,
96
+ * retried.
97
+ * To set to `-1` for no timeout.
98
+ * `undefined` will lead to a default, large, timeout being used.
99
+ */
100
+ requestTimeout: number | undefined;
94
101
  }
@@ -17,6 +17,7 @@ import { distinctUntilChanged, ignoreElements, map, merge as observableMerge, sk
17
17
  import { MediaError } from "../../errors";
18
18
  import { fromEvent } from "../../utils/event_emitter";
19
19
  import filterMap from "../../utils/filter_map";
20
+ import isNullOrUndefined from "../../utils/is_null_or_undefined";
20
21
  import createSharedReference from "../../utils/reference";
21
22
  import EVENTS from "./events_generators";
22
23
  // NOTE As of now (RxJS 7.4.0), RxJS defines `ignoreElements` default
@@ -54,7 +55,7 @@ export default function ContentTimeBoundariesObserver(manifest, streams, playbac
54
55
  "earliest time announced in the Manifest.");
55
56
  return EVENTS.warning(warning);
56
57
  }
57
- else if (wantedPosition > maximumPositionCalculator.getCurrentMaximumPosition()) {
58
+ else if (wantedPosition > maximumPositionCalculator.getMaximumAvailablePosition()) {
58
59
  var warning = new MediaError("MEDIA_TIME_AFTER_MANIFEST", "The current position is after the latest " +
59
60
  "time announced in the Manifest.");
60
61
  return EVENTS.warning(warning);
@@ -68,32 +69,31 @@ export default function ContentTimeBoundariesObserver(manifest, streams, playbac
68
69
  */
69
70
  var contentDuration = createSharedReference(undefined);
70
71
  var updateDurationOnManifestUpdate$ = fromEvent(manifest, "manifestUpdate").pipe(startWith(null), tap(function () {
71
- if (!manifest.isDynamic) {
72
- var maxPos = maximumPositionCalculator.getCurrentMaximumPosition();
73
- contentDuration.setValue(maxPos);
74
- }
75
- else {
76
- // TODO handle finished dynamic contents?
77
- contentDuration.setValue(undefined);
78
- }
72
+ var duration = manifest.isDynamic ?
73
+ maximumPositionCalculator.getEndingPosition() :
74
+ maximumPositionCalculator.getMaximumAvailablePosition();
75
+ contentDuration.setValue(duration);
79
76
  }), ignoreElements());
80
77
  var updateDurationAndTimeBoundsOnTrackChange$ = streams.pipe(tap(function (message) {
81
78
  if (message.type === "adaptationChange") {
79
+ if (!manifest.isLastPeriodKnown) {
80
+ return;
81
+ }
82
82
  var lastPeriod = manifest.periods[manifest.periods.length - 1];
83
83
  if (message.value.period.id === (lastPeriod === null || lastPeriod === void 0 ? void 0 : lastPeriod.id)) {
84
- if (message.value.type === "audio") {
85
- maximumPositionCalculator
86
- .updateLastAudioAdaptation(message.value.adaptation);
87
- if (!manifest.isDynamic) {
88
- contentDuration.setValue(maximumPositionCalculator.getCurrentMaximumPosition());
84
+ if (message.value.type === "audio" || message.value.type === "video") {
85
+ if (message.value.type === "audio") {
86
+ maximumPositionCalculator
87
+ .updateLastAudioAdaptation(message.value.adaptation);
89
88
  }
90
- }
91
- else if (message.value.type === "video") {
92
- maximumPositionCalculator
93
- .updateLastVideoAdaptation(message.value.adaptation);
94
- if (!manifest.isDynamic) {
95
- contentDuration.setValue(maximumPositionCalculator.getCurrentMaximumPosition());
89
+ else {
90
+ maximumPositionCalculator
91
+ .updateLastVideoAdaptation(message.value.adaptation);
96
92
  }
93
+ var newDuration = manifest.isDynamic ?
94
+ maximumPositionCalculator.getMaximumAvailablePosition() :
95
+ maximumPositionCalculator.getEndingPosition();
96
+ contentDuration.setValue(newDuration);
97
97
  }
98
98
  }
99
99
  }
@@ -119,7 +119,7 @@ var MaximumPositionCalculator = /** @class */ (function () {
119
119
  * If no Adaptation has been set, it should be set to `null`.
120
120
  *
121
121
  * Allows to calculate the maximum position more precizely in
122
- * `getCurrentMaximumPosition`.
122
+ * `getMaximumAvailablePosition` and `getEndingPosition`.
123
123
  * @param {Object|null} adaptation
124
124
  */
125
125
  MaximumPositionCalculator.prototype.updateLastAudioAdaptation = function (adaptation) {
@@ -130,18 +130,18 @@ var MaximumPositionCalculator = /** @class */ (function () {
130
130
  * If no Adaptation has been set, it should be set to `null`.
131
131
  *
132
132
  * Allows to calculate the maximum position more precizely in
133
- * `getCurrentMaximumPosition`.
133
+ * `getMaximumAvailablePosition` and `getEndingPosition`.
134
134
  * @param {Object|null} adaptation
135
135
  */
136
136
  MaximumPositionCalculator.prototype.updateLastVideoAdaptation = function (adaptation) {
137
137
  this._lastVideoAdaptation = adaptation;
138
138
  };
139
139
  /**
140
- * Returns an estimate of the maximum position reachable under the current
141
- * circumstances.
140
+ * Returns an estimate of the maximum position currently reachable (i.e.
141
+ * segments are available) under the current circumstances.
142
142
  * @returns {number}
143
143
  */
144
- MaximumPositionCalculator.prototype.getCurrentMaximumPosition = function () {
144
+ MaximumPositionCalculator.prototype.getMaximumAvailablePosition = function () {
145
145
  var _a;
146
146
  if (this._manifest.isDynamic) {
147
147
  return (_a = this._manifest.getLivePosition()) !== null && _a !== void 0 ? _a : this._manifest.getMaximumSafePosition();
@@ -155,7 +155,7 @@ var MaximumPositionCalculator = /** @class */ (function () {
155
155
  return this._manifest.getMaximumSafePosition();
156
156
  }
157
157
  else {
158
- var lastVideoPosition = getLastPositionFromAdaptation(this._lastVideoAdaptation);
158
+ var lastVideoPosition = getLastAvailablePositionFromAdaptation(this._lastVideoAdaptation);
159
159
  if (typeof lastVideoPosition !== "number") {
160
160
  return this._manifest.getMaximumSafePosition();
161
161
  }
@@ -163,15 +163,15 @@ var MaximumPositionCalculator = /** @class */ (function () {
163
163
  }
164
164
  }
165
165
  else if (this._lastVideoAdaptation === null) {
166
- var lastAudioPosition = getLastPositionFromAdaptation(this._lastAudioAdaptation);
166
+ var lastAudioPosition = getLastAvailablePositionFromAdaptation(this._lastAudioAdaptation);
167
167
  if (typeof lastAudioPosition !== "number") {
168
168
  return this._manifest.getMaximumSafePosition();
169
169
  }
170
170
  return lastAudioPosition;
171
171
  }
172
172
  else {
173
- var lastAudioPosition = getLastPositionFromAdaptation(this._lastAudioAdaptation);
174
- var lastVideoPosition = getLastPositionFromAdaptation(this._lastVideoAdaptation);
173
+ var lastAudioPosition = getLastAvailablePositionFromAdaptation(this._lastAudioAdaptation);
174
+ var lastVideoPosition = getLastAvailablePositionFromAdaptation(this._lastVideoAdaptation);
175
175
  if (typeof lastAudioPosition !== "number" ||
176
176
  typeof lastVideoPosition !== "number") {
177
177
  return this._manifest.getMaximumSafePosition();
@@ -181,20 +181,58 @@ var MaximumPositionCalculator = /** @class */ (function () {
181
181
  }
182
182
  }
183
183
  };
184
+ /**
185
+ * Returns an estimate of the actual ending position once
186
+ * the full content is available.
187
+ * Returns `undefined` if that could not be determined, for various reasons.
188
+ * @returns {number|undefined}
189
+ */
190
+ MaximumPositionCalculator.prototype.getEndingPosition = function () {
191
+ var _a, _b;
192
+ if (!this._manifest.isDynamic) {
193
+ return this.getMaximumAvailablePosition();
194
+ }
195
+ if (this._lastVideoAdaptation === undefined ||
196
+ this._lastAudioAdaptation === undefined) {
197
+ return undefined;
198
+ }
199
+ else if (this._lastAudioAdaptation === null) {
200
+ if (this._lastVideoAdaptation === null) {
201
+ return undefined;
202
+ }
203
+ else {
204
+ return (_a = getEndingPositionFromAdaptation(this._lastVideoAdaptation)) !== null && _a !== void 0 ? _a : undefined;
205
+ }
206
+ }
207
+ else if (this._lastVideoAdaptation === null) {
208
+ return (_b = getEndingPositionFromAdaptation(this._lastAudioAdaptation)) !== null && _b !== void 0 ? _b : undefined;
209
+ }
210
+ else {
211
+ var lastAudioPosition = getEndingPositionFromAdaptation(this._lastAudioAdaptation);
212
+ var lastVideoPosition = getEndingPositionFromAdaptation(this._lastVideoAdaptation);
213
+ if (typeof lastAudioPosition !== "number" ||
214
+ typeof lastVideoPosition !== "number") {
215
+ return undefined;
216
+ }
217
+ else {
218
+ return Math.min(lastAudioPosition, lastVideoPosition);
219
+ }
220
+ }
221
+ };
184
222
  return MaximumPositionCalculator;
185
223
  }());
186
224
  /**
187
- * Returns "last time of reference" from the adaptation given.
225
+ * Returns last currently available position from the Adaptation given.
188
226
  * `undefined` if a time could not be found.
189
- * Null if the Adaptation has no segments (it could be that it didn't started or
227
+ * `null` if the Adaptation has no segments (it could be that it didn't started or
190
228
  * that it already finished for example).
191
229
  *
192
- * We consider the earliest last time from every representations in the given
193
- * adaptation.
230
+ * We consider the earliest last available position from every Representation
231
+ * in the given Adaptation.
194
232
  * @param {Object} adaptation
195
233
  * @returns {Number|undefined|null}
196
234
  */
197
- function getLastPositionFromAdaptation(adaptation) {
235
+ function getLastAvailablePositionFromAdaptation(adaptation) {
198
236
  var representations = adaptation.representations;
199
237
  var min = null;
200
238
  /**
@@ -207,18 +245,52 @@ function getLastPositionFromAdaptation(adaptation) {
207
245
  for (var i = 0; i < representations.length; i++) {
208
246
  if (representations[i].index !== lastIndex) {
209
247
  lastIndex = representations[i].index;
210
- var lastPosition = representations[i].index.getLastPosition();
248
+ var lastPosition = representations[i].index.getLastAvailablePosition();
211
249
  if (lastPosition === undefined) { // we cannot tell
212
250
  return undefined;
213
251
  }
214
252
  if (lastPosition !== null) {
215
- min = min == null ? lastPosition :
253
+ min = isNullOrUndefined(min) ? lastPosition :
216
254
  Math.min(min, lastPosition);
217
255
  }
218
256
  }
219
257
  }
220
- if (min === null) { // It means that all positions were null === no segments (yet?)
221
- return null;
258
+ return min;
259
+ }
260
+ /**
261
+ * Returns ending time from the Adaptation given, once all its segments are
262
+ * available.
263
+ * `undefined` if a time could not be found.
264
+ * `null` if the Adaptation has no segments (it could be that it already
265
+ * finished for example).
266
+ *
267
+ * We consider the earliest ending time from every Representation in the given
268
+ * Adaptation.
269
+ * @param {Object} adaptation
270
+ * @returns {Number|undefined|null}
271
+ */
272
+ function getEndingPositionFromAdaptation(adaptation) {
273
+ var representations = adaptation.representations;
274
+ var min = null;
275
+ /**
276
+ * Some Manifest parsers use the exact same `IRepresentationIndex` reference
277
+ * for each Representation of a given Adaptation, because in the actual source
278
+ * Manifest file, indexing data is often defined at Adaptation-level.
279
+ * This variable allows to optimize the logic here when this is the case.
280
+ */
281
+ var lastIndex;
282
+ for (var i = 0; i < representations.length; i++) {
283
+ if (representations[i].index !== lastIndex) {
284
+ lastIndex = representations[i].index;
285
+ var lastPosition = representations[i].index.getEnd();
286
+ if (lastPosition === undefined) { // we cannot tell
287
+ return undefined;
288
+ }
289
+ if (lastPosition !== null) {
290
+ min = isNullOrUndefined(min) ? lastPosition :
291
+ Math.min(min, lastPosition);
292
+ }
293
+ }
222
294
  }
223
295
  return min;
224
296
  }
@@ -108,7 +108,7 @@ export default function initializeDirectfileContent(_a) {
108
108
  * Observable trying to avoid various stalling situations, emitting "stalled"
109
109
  * events when it cannot, as well as "unstalled" events when it get out of one.
110
110
  */
111
- var stallAvoider$ = StallAvoider(playbackObserver, null, EMPTY, EMPTY);
111
+ var stallAvoider$ = StallAvoider(playbackObserver, null, speed, EMPTY, EMPTY);
112
112
  /**
113
113
  * Emit a "loaded" events once the initial play has been performed and the
114
114
  * media can begin playback.
@@ -106,7 +106,7 @@ export default function createMediaSourceLoader(_a) {
106
106
  * Observable trying to avoid various stalling situations, emitting "stalled"
107
107
  * events when it cannot, as well as "unstalled" events when it get out of one.
108
108
  */
109
- var stallAvoider$ = StallAvoider(playbackObserver, manifest, lockedStream$, discontinuityUpdate$);
109
+ var stallAvoider$ = StallAvoider(playbackObserver, manifest, speed, lockedStream$, discontinuityUpdate$);
110
110
  /**
111
111
  * Emit a "loaded" events once the initial play has been performed and the
112
112
  * media can begin playback.
@@ -15,6 +15,7 @@
15
15
  */
16
16
  import { Observable } from "rxjs";
17
17
  import Manifest, { Period } from "../../manifest";
18
+ import { IReadOnlySharedReference } from "../../utils/reference";
18
19
  import { PlaybackObserver } from "../api";
19
20
  import { IBufferType } from "../segment_buffers";
20
21
  import { IStalledEvent, IUnstalledEvent, IWarningEvent } from "./types";
@@ -67,9 +68,10 @@ export interface IDiscontinuityTimeInfo {
67
68
  * encountered and exited.
68
69
  * @param {object} playbackObserver - emit the current playback conditions.
69
70
  * @param {Object} manifest - The Manifest of the currently-played content.
71
+ * @param {Object} speed - The last speed set by the user
72
+ * @param {Observable} lockedStream$
70
73
  * @param {Observable} discontinuityUpdate$ - Observable emitting encountered
71
74
  * discontinuities for loaded Period and buffer types.
72
- * @param {Function} setCurrentTime
73
75
  * @returns {Observable}
74
76
  */
75
- export default function StallAvoider(playbackObserver: PlaybackObserver, manifest: Manifest | null, lockedStream$: Observable<ILockedStreamEvent>, discontinuityUpdate$: Observable<IDiscontinuityEvent>): Observable<IStalledEvent | IUnstalledEvent | IWarningEvent>;
77
+ export default function StallAvoider(playbackObserver: PlaybackObserver, manifest: Manifest | null, speed: IReadOnlySharedReference<number>, lockedStream$: Observable<ILockedStreamEvent>, discontinuityUpdate$: Observable<IDiscontinuityEvent>): Observable<IStalledEvent | IUnstalledEvent | IWarningEvent>;