rx-player 3.29.0-dev.2022091600 → 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 (184) hide show
  1. package/CHANGELOG.md +22 -10
  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 +9 -10
  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 +5656 -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 +3 -11
  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/core/stream/orchestrator/stream_orchestrator.ts +0 -1
  129. package/src/default_config.ts +12 -0
  130. package/src/experimental/tools/VideoThumbnailLoader/video_thumbnail_loader.ts +1 -0
  131. package/src/manifest/manifest.ts +11 -2
  132. package/src/manifest/representation.ts +15 -0
  133. package/src/manifest/representation_index/__tests__/static.test.ts +1 -1
  134. package/src/manifest/representation_index/static.ts +3 -3
  135. package/src/manifest/representation_index/types.ts +33 -15
  136. package/src/manifest/update_period_in_place.ts +1 -0
  137. package/src/parsers/manifest/dash/common/indexes/base.ts +22 -23
  138. package/src/parsers/manifest/dash/common/indexes/get_init_segment.ts +6 -4
  139. package/src/parsers/manifest/dash/common/indexes/get_segments_from_timeline.ts +5 -5
  140. package/src/parsers/manifest/dash/common/indexes/list.ts +19 -20
  141. package/src/parsers/manifest/dash/common/indexes/template.ts +23 -27
  142. package/src/parsers/manifest/dash/common/indexes/timeline/timeline_representation_index.ts +25 -23
  143. package/src/parsers/manifest/dash/common/indexes/tokens.ts +7 -18
  144. package/src/parsers/manifest/dash/common/parse_mpd.ts +2 -4
  145. package/src/parsers/manifest/dash/common/parse_representation_index.ts +1 -6
  146. package/src/parsers/manifest/dash/common/parse_representations.ts +9 -0
  147. package/src/parsers/manifest/dash/common/resolve_base_urls.ts +5 -9
  148. package/src/parsers/manifest/dash/js-parser/node_parsers/BaseURL.ts +2 -29
  149. package/src/parsers/manifest/dash/js-parser/node_parsers/__tests__/AdaptationSet.test.ts +7 -11
  150. package/src/parsers/manifest/dash/node_parser_types.ts +0 -7
  151. package/src/parsers/manifest/dash/wasm-parser/rs/events.rs +3 -1
  152. package/src/parsers/manifest/dash/wasm-parser/rs/processor/attributes.rs +1 -8
  153. package/src/parsers/manifest/dash/wasm-parser/ts/generators/BaseURL.ts +0 -13
  154. package/src/parsers/manifest/dash/wasm-parser/ts/types.ts +8 -0
  155. package/src/parsers/manifest/local/parse_local_manifest.ts +1 -0
  156. package/src/parsers/manifest/local/representation_index.ts +2 -2
  157. package/src/parsers/manifest/metaplaylist/metaplaylist_parser.ts +7 -1
  158. package/src/parsers/manifest/smooth/create_parser.ts +17 -13
  159. package/src/parsers/manifest/smooth/representation_index.ts +2 -2
  160. package/src/parsers/manifest/types.ts +26 -1
  161. package/src/parsers/manifest/utils/__tests__/get_first_time_from_adaptations.test.ts +15 -0
  162. package/src/parsers/manifest/utils/__tests__/get_last_time_from_adaptation.test.ts +15 -0
  163. package/src/parsers/texttracks/ttml/html/apply_extent.ts +8 -1
  164. package/src/parsers/texttracks/ttml/html/apply_origin.ts +9 -1
  165. package/src/parsers/texttracks/ttml/html/create_element.ts +2 -2
  166. package/src/transports/dash/construct_segment_url.ts +28 -0
  167. package/src/transports/dash/image_pipelines.ts +5 -2
  168. package/src/transports/dash/segment_loader.ts +5 -2
  169. package/src/transports/dash/text_loader.ts +5 -2
  170. package/src/transports/dash/text_parser.ts +3 -1
  171. package/src/transports/local/segment_loader.ts +3 -2
  172. package/src/transports/metaplaylist/pipelines.ts +28 -9
  173. package/src/transports/smooth/pipelines.ts +12 -6
  174. package/src/transports/smooth/utils.ts +13 -1
  175. package/src/transports/types.ts +6 -3
  176. package/src/utils/__tests__/event_emitter.test.ts +72 -67
  177. package/src/utils/__tests__/initialization_segment_cache.test.ts +7 -7
  178. package/src/utils/__tests__/resolve_url.test.ts +27 -23
  179. package/src/utils/event_emitter.ts +1 -3
  180. package/src/utils/resolve_url.ts +11 -8
  181. package/dist/_esm5.processed/core/fetchers/utils/try_urls_with_backoff.d.ts +0 -85
  182. package/dist/_esm5.processed/core/fetchers/utils/try_urls_with_backoff.js +0 -264
  183. package/dummy +0 -1
  184. package/src/core/fetchers/utils/try_urls_with_backoff.ts +0 -287
@@ -395,6 +395,18 @@ const DEFAULT_CONFIG = {
395
395
  */
396
396
  DEFAULT_MAX_MANIFEST_REQUEST_RETRY: 4,
397
397
 
398
+ /**
399
+ * Default delay, in seconds, during which a CDN will be "downgraded".
400
+ *
401
+ * For example in case of media content being available on multiple CDNs, the
402
+ * RxPlayer may decide that a CDN is less reliable (for example, it returned a
403
+ * server error) and should thus be avoided, at least for some time
404
+ *
405
+ * This value is the amount of time this CDN will be "less considered" than the
406
+ * alternatives.
407
+ */
408
+ DEFAULT_CDN_DOWNGRADE_TIME: 60,
409
+
398
410
  /**
399
411
  * The default number of times a segment request will be re-performed when
400
412
  * on error which justify a retry.
@@ -170,6 +170,7 @@ export default class VideoThumbnailLoader {
170
170
  const segmentFetcher = createSegmentFetcher(
171
171
  "video",
172
172
  loader.video,
173
+ null,
173
174
  // We don't care about the SegmentFetcher's lifecycle events
174
175
  {},
175
176
  { baseDelay: 0,
@@ -23,6 +23,7 @@ import {
23
23
  import arrayFind from "../utils/array_find";
24
24
  import EventEmitter from "../utils/event_emitter";
25
25
  import idGenerator from "../utils/id_generator";
26
+ import { getFilenameIndexInUrl } from "../utils/resolve_url";
26
27
  import warnOnce from "../utils/warn_once";
27
28
  import Adaptation from "./adaptation";
28
29
  import Period, {
@@ -612,14 +613,18 @@ export default class Manifest extends EventEmitter<IManifestEvents> {
612
613
  const newImageTracks = _imageTracks.map(({ mimeType, url }) => {
613
614
  const adaptationID = "gen-image-ada-" + generateSupplementaryTrackID();
614
615
  const representationID = "gen-image-rep-" + generateSupplementaryTrackID();
616
+ const indexOfFilename = getFilenameIndexInUrl(url);
617
+ const cdnUrl = url.substring(0, indexOfFilename);
618
+ const filename = url.substring(indexOfFilename);
615
619
  const newAdaptation = new Adaptation({ id: adaptationID,
616
620
  type: "image",
617
621
  representations: [{
618
622
  bitrate: 0,
623
+ cdnMetadata: [ { baseUrl: cdnUrl } ],
619
624
  id: representationID,
620
625
  mimeType,
621
626
  index: new StaticRepresentationIndex({
622
- media: url,
627
+ media: filename,
623
628
  }) }] },
624
629
  { isManuallyAdded: true });
625
630
  if (newAdaptation.representations.length > 0 && !newAdaptation.isSupported) {
@@ -664,6 +669,9 @@ export default class Manifest extends EventEmitter<IManifestEvents> {
664
669
  languages != null ? languages :
665
670
  [];
666
671
 
672
+ const indexOfFilename = getFilenameIndexInUrl(url);
673
+ const cdnUrl = url.substring(0, indexOfFilename);
674
+ const filename = url.substring(indexOfFilename);
667
675
  return allSubs.concat(langsToMapOn.map((_language) => {
668
676
  const adaptationID = "gen-text-ada-" + generateSupplementaryTrackID();
669
677
  const representationID = "gen-text-rep-" + generateSupplementaryTrackID();
@@ -673,11 +681,12 @@ export default class Manifest extends EventEmitter<IManifestEvents> {
673
681
  closedCaption,
674
682
  representations: [{
675
683
  bitrate: 0,
684
+ cdnMetadata: [{ baseUrl: cdnUrl }],
676
685
  id: representationID,
677
686
  mimeType,
678
687
  codecs,
679
688
  index: new StaticRepresentationIndex({
680
- media: url,
689
+ media: filename,
681
690
  }) }] },
682
691
  { isManuallyAdded: true });
683
692
  if (newAdaptation.representations.length > 0 && !newAdaptation.isSupported) {
@@ -17,6 +17,7 @@
17
17
  import { isCodecSupported } from "../compat";
18
18
  import log from "../log";
19
19
  import {
20
+ ICdnMetadata,
20
21
  IContentProtections,
21
22
  IParsedRepresentation,
22
23
  } from "../parsers/manifest";
@@ -41,6 +42,18 @@ class Representation {
41
42
  */
42
43
  public index : IRepresentationIndex;
43
44
 
45
+ /**
46
+ * Information on the CDN(s) on which requests should be done to request this
47
+ * Representation's initialization and media segments.
48
+ *
49
+ * `null` if there's no CDN involved here (e.g. resources are not requested
50
+ * through the network).
51
+ *
52
+ * An empty array means that no CDN are left to request the resource. As such,
53
+ * no resource can be loaded in that situation.
54
+ */
55
+ public cdnMetadata : ICdnMetadata[] | null;
56
+
44
57
  /** Bitrate this Representation is in, in bits per seconds. */
45
58
  public bitrate : number;
46
59
 
@@ -129,6 +142,8 @@ class Representation {
129
142
  this.hdrInfo = args.hdrInfo;
130
143
  }
131
144
 
145
+ this.cdnMetadata = args.cdnMetadata;
146
+
132
147
  this.index = args.index;
133
148
  this.isSupported = opts.type === "audio" ||
134
149
  opts.type === "video" ?
@@ -34,7 +34,7 @@ describe("manifest - StaticRepresentationIndex", () => {
34
34
  end: Number.MAX_VALUE,
35
35
  timescale: 1,
36
36
  privateInfos: {},
37
- mediaURLs: ["foo"] }]);
37
+ url: "foo" }]);
38
38
  });
39
39
 
40
40
  it("should return no first position", () => {
@@ -28,13 +28,13 @@ export interface IStaticRepresentationIndexInfos { media: string }
28
28
  */
29
29
  export default class StaticRepresentationIndex implements IRepresentationIndex {
30
30
  /** URL at which the content is available. */
31
- private readonly _mediaURLs: string;
31
+ private readonly _url : string;
32
32
 
33
33
  /**
34
34
  * @param {Object} infos
35
35
  */
36
36
  constructor(infos : IStaticRepresentationIndexInfos) {
37
- this._mediaURLs = infos.media;
37
+ this._url = infos.media;
38
38
  }
39
39
 
40
40
  /**
@@ -54,7 +54,7 @@ export default class StaticRepresentationIndex implements IRepresentationIndex {
54
54
  return [{ id: "0",
55
55
  isInit: false,
56
56
  number: 0,
57
- mediaURLs: [this._mediaURLs],
57
+ url: this._url,
58
58
  time: 0,
59
59
  end: Number.MAX_VALUE,
60
60
  duration: Number.MAX_VALUE,
@@ -50,7 +50,7 @@ export interface ISmoothInitSegmentPrivateInfos {
50
50
  * Supplementary information specific to Smooth media segments (that is, every
51
51
  * segments but the initialization segment).
52
52
  */
53
- export interface ISmoothSegmentPrivateInfos {
53
+ export interface ISmoothMediaSegmentPrivateInfos {
54
54
  /**
55
55
  * Start time of the segment as announced in the Manifest, in the same
56
56
  * timescale than the one indicated through `ISmoothInitSegmentPrivateInfos`.
@@ -113,28 +113,28 @@ export interface ILocalManifestSegmentPrivateInfos {
113
113
  */
114
114
  export interface IPrivateInfos {
115
115
  /** Smooth-specific information allowing to generate an initialization segment. */
116
- smoothInitSegment? : ISmoothInitSegmentPrivateInfos | undefined;
116
+ smoothInitSegment? : ISmoothInitSegmentPrivateInfos;
117
117
 
118
118
  /** Smooth-specific information linked to all Smooth media segments. */
119
- smoothMediaSegment? : ISmoothSegmentPrivateInfos | undefined;
119
+ smoothMediaSegment? : ISmoothMediaSegmentPrivateInfos;
120
120
 
121
121
  /** Information that should be present on all MetaPlaylist segments. */
122
- metaplaylistInfos? : IMetaPlaylistPrivateInfos | undefined;
122
+ metaplaylistInfos? : IMetaPlaylistPrivateInfos;
123
123
 
124
124
  /**
125
125
  * Local Manifest-specific information allowing to request the
126
126
  * initialization segment.
127
127
  */
128
- localManifestInitSegment? : ILocalManifestInitSegmentPrivateInfos | undefined;
128
+ localManifestInitSegment? : ILocalManifestInitSegmentPrivateInfos;
129
129
 
130
130
  /** Local Manifest-specific information allowing to request any media segment. */
131
- localManifestSegment? : ILocalManifestSegmentPrivateInfos | undefined;
131
+ localManifestSegment? : ILocalManifestSegmentPrivateInfos;
132
132
 
133
133
  /**
134
134
  * Function allowing to know if a given emsg's event name has been
135
135
  * explicitely authorized.
136
136
  */
137
- isEMSGWhitelisted? : ((evt: IEMSG) => boolean) | undefined;
137
+ isEMSGWhitelisted? : ((evt: IEMSG) => boolean);
138
138
  }
139
139
 
140
140
  /** Represent a single Segment from a Representation. */
@@ -160,15 +160,10 @@ export interface ISegment {
160
160
  */
161
161
  isInit : boolean;
162
162
  /**
163
- * URLs where this segment is available. From the most to least prioritary.
164
- * `null` if no URL exists.
163
+ * Store supplementary information on a segment that can be later exploited by
164
+ * the transport logic.
165
165
  */
166
- mediaURLs : string[]|null;
167
- /**
168
- * Allows to store supplementary information on a segment that can be later
169
- * exploited by the transport logic.
170
- */
171
- privateInfos : IPrivateInfos | undefined;
166
+ privateInfos : IPrivateInfos;
172
167
  /**
173
168
  * Estimated time, in seconds, at which the concerned segment should be
174
169
  * offseted when decoded.
@@ -230,6 +225,29 @@ export interface ISegment {
230
225
  * generated.
231
226
  */
232
227
  complete : boolean;
228
+ /**
229
+ * Optional relative or absolute URL to load the resource.
230
+ *
231
+ * If the URL is absolute (it contains the scheme at the beginning), it is the
232
+ * complete URL on which the resource should be requested.
233
+ *
234
+ * If the URL is relative (it does not contain a scheme at the beginning), it
235
+ * should be relative to the chosen CDN that should be recuperated through
236
+ * another mean
237
+ *
238
+ * If `null`, it means either:
239
+ *
240
+ * - that there is no way to reach the resource through a URL.
241
+ *
242
+ * - that there may be an URL, but is already communicated through another
243
+ * mean, like the currently chosen CDN.
244
+ *
245
+ * An empty string is equivalent to indicating that the chosen CDN's URL
246
+ * should be directly requested instead.
247
+ * In that way, it is equivalent to setting it to `null`.
248
+ */
249
+ url : string | null;
250
+
233
251
  /**
234
252
  * Optional byte range to retrieve the Segment from its URL(s).
235
253
  * TODO this should probably moved to `privateInfos` as this is
@@ -59,6 +59,7 @@ export default function updatePeriodInPlace(oldPeriod : Period,
59
59
  log.warn(`Manifest: Representation "${oldRepresentations[k].id}" ` +
60
60
  "not found when merging.");
61
61
  } else {
62
+ oldRepresentation.cdnMetadata = newRepresentation.cdnMetadata;
62
63
  if (updateType === MANIFEST_UPDATE_TYPE.Full) {
63
64
  oldRepresentation.index._replace(newRepresentation.index);
64
65
  } else {
@@ -26,10 +26,9 @@ import {
26
26
  IIndexSegment,
27
27
  toIndexTime,
28
28
  } from "../../../utils/index_helpers";
29
- import { IResolvedBaseUrl } from "../resolve_base_urls";
30
29
  import getInitSegment from "./get_init_segment";
31
30
  import getSegmentsFromTimeline from "./get_segments_from_timeline";
32
- import { createIndexURLs } from "./tokens";
31
+ import { constructRepresentationUrl } from "./tokens";
33
32
 
34
33
  /**
35
34
  * Index property defined for a SegmentBase RepresentationIndex
@@ -53,17 +52,21 @@ export interface IBaseIndex {
53
52
  */
54
53
  indexTimeOffset : number;
55
54
  /** Information on the initialization segment. */
56
- initialization? : {
57
- /** URLs to access the initialization segment. */
58
- mediaURLs: string[] | null;
55
+ initialization : {
56
+ /**
57
+ * URL path, to add to the wanted CDN, to access the initialization segment.
58
+ * `null` if no URL exists.
59
+ */
60
+ url: string | null;
59
61
  /** possible byte range to request it. */
60
62
  range?: [number, number] | undefined;
61
63
  } | undefined;
62
64
  /**
63
- * Base URL(s) to access any segment. Can contain tokens to replace to convert
64
- * it to real URLs.
65
+ * URL base to access any segment.
66
+ * Can contain token to replace to convert it to real URLs.
67
+ * `null` if no URL exists.
65
68
  */
66
- mediaURLs : string[] | null;
69
+ segmentUrlTemplate : string | null;
67
70
  /** Number from which the first segments in this index starts with. */
68
71
  startNumber? : number | undefined;
69
72
  /** Every segments defined in this index. */
@@ -110,8 +113,6 @@ export interface IBaseIndexContextArgument {
110
113
  periodStart : number;
111
114
  /** End of the period concerned by this RepresentationIndex, in seconds. */
112
115
  periodEnd : number|undefined;
113
- /** Base URL for the Representation concerned. */
114
- representationBaseURLs : IResolvedBaseUrl[];
115
116
  /** ID of the Representation concerned. */
116
117
  representationId? : string | undefined;
117
118
  /** Bitrate of the Representation concerned. */
@@ -185,7 +186,6 @@ export default class BaseRepresentationIndex implements IRepresentationIndex {
185
186
  constructor(index : IBaseIndexIndexArgument, context : IBaseIndexContextArgument) {
186
187
  const { periodStart,
187
188
  periodEnd,
188
- representationBaseURLs,
189
189
  representationId,
190
190
  representationBitrate,
191
191
  isEMSGWhitelisted } = context;
@@ -196,13 +196,15 @@ export default class BaseRepresentationIndex implements IRepresentationIndex {
196
196
 
197
197
  const indexTimeOffset = presentationTimeOffset - periodStart * timescale;
198
198
 
199
- const urlSources : string[] = representationBaseURLs.map(b => b.url);
200
- const mediaURLs = createIndexURLs(urlSources,
201
- index.initialization !== undefined ?
202
- index.initialization.media :
203
- undefined,
204
- representationId,
205
- representationBitrate);
199
+ const initializationUrl = index.initialization?.media === undefined ?
200
+ null :
201
+ constructRepresentationUrl(index.initialization.media,
202
+ representationId,
203
+ representationBitrate);
204
+
205
+ const segmentUrlTemplate = index.media === undefined ?
206
+ null :
207
+ constructRepresentationUrl(index.media, representationId, representationBitrate);
206
208
 
207
209
  // TODO If indexRange is either undefined or behind the initialization segment
208
210
  // the following logic will not work.
@@ -217,11 +219,8 @@ export default class BaseRepresentationIndex implements IRepresentationIndex {
217
219
 
218
220
  this._index = { indexRange: index.indexRange,
219
221
  indexTimeOffset,
220
- initialization: { mediaURLs, range },
221
- mediaURLs: createIndexURLs(urlSources,
222
- index.media,
223
- representationId,
224
- representationBitrate),
222
+ initialization: { url: initializationUrl, range },
223
+ segmentUrlTemplate,
225
224
  startNumber: index.startNumber,
226
225
  timeline: index.timeline ?? [],
227
226
  timescale };
@@ -15,6 +15,7 @@
15
15
  */
16
16
 
17
17
  import { ISegment } from "../../../../../manifest";
18
+ import { IPrivateInfos } from "../../../../../manifest/representation_index/types";
18
19
  import { IEMSG } from "../../../../containers/isobmff";
19
20
 
20
21
  /**
@@ -25,7 +26,7 @@ import { IEMSG } from "../../../../containers/isobmff";
25
26
  */
26
27
  export default function getInitSegment(
27
28
  index: { timescale: number;
28
- initialization?: { mediaURLs: string[] | null;
29
+ initialization?: { url: string | null;
29
30
  range?: [number, number] | undefined; } |
30
31
  undefined;
31
32
  indexRange?: [number, number] | undefined;
@@ -33,10 +34,11 @@ export default function getInitSegment(
33
34
  isEMSGWhitelisted?: (inbandEvent: IEMSG) => boolean
34
35
  ) : ISegment {
35
36
  const { initialization } = index;
36
- let privateInfos;
37
+ const privateInfos : IPrivateInfos = {};
37
38
  if (isEMSGWhitelisted !== undefined) {
38
- privateInfos = { isEMSGWhitelisted };
39
+ privateInfos.isEMSGWhitelisted = isEMSGWhitelisted;
39
40
  }
41
+
40
42
  return { id: "init",
41
43
  isInit: true,
42
44
  time: 0,
@@ -46,7 +48,7 @@ export default function getInitSegment(
46
48
  range: initialization != null ? initialization.range :
47
49
  undefined,
48
50
  indexRange: index.indexRange,
49
- mediaURLs: initialization?.mediaURLs ?? null,
51
+ url: initialization?.url ?? null,
50
52
  complete: true,
51
53
  privateInfos,
52
54
  timestampOffset: -(index.indexTimeOffset / index.timescale) };
@@ -53,7 +53,7 @@ function getWantedRepeatIndex(
53
53
  */
54
54
  export default function getSegmentsFromTimeline(
55
55
  index : { availabilityTimeComplete? : boolean | undefined;
56
- mediaURLs : string[] | null;
56
+ segmentUrlTemplate : string | null;
57
57
  startNumber? : number | undefined;
58
58
  timeline : IIndexSegment[];
59
59
  timescale : number;
@@ -65,7 +65,7 @@ export default function getSegmentsFromTimeline(
65
65
  ) : ISegment[] {
66
66
  const scaledUp = toIndexTime(from, index);
67
67
  const scaledTo = toIndexTime(from + durationWanted, index);
68
- const { timeline, timescale, mediaURLs, startNumber } = index;
68
+ const { timeline, timescale, segmentUrlTemplate, startNumber } = index;
69
69
 
70
70
  let currentNumber = startNumber ?? 1;
71
71
  const segments : ISegment[] = [];
@@ -85,9 +85,9 @@ export default function getSegmentsFromTimeline(
85
85
  while (segmentTime < scaledTo && segmentNumberInCurrentRange <= repeat) {
86
86
  const segmentNumber = currentNumber + segmentNumberInCurrentRange;
87
87
 
88
- const detokenizedURLs = mediaURLs === null ?
88
+ const detokenizedURL = segmentUrlTemplate === null ?
89
89
  null :
90
- mediaURLs.map(createDashUrlDetokenizer(segmentTime, segmentNumber));
90
+ createDashUrlDetokenizer(segmentTime, segmentNumber)(segmentUrlTemplate);
91
91
 
92
92
  let time = segmentTime - index.indexTimeOffset;
93
93
  let realDuration = duration;
@@ -103,7 +103,7 @@ export default function getSegmentsFromTimeline(
103
103
  isInit: false,
104
104
  range,
105
105
  timescale: 1 as const,
106
- mediaURLs: detokenizedURLs,
106
+ url: detokenizedURL,
107
107
  number: segmentNumber,
108
108
  timestampOffset: -(index.indexTimeOffset / timescale),
109
109
  complete,
@@ -21,9 +21,8 @@ import {
21
21
  } from "../../../../../manifest";
22
22
  import { IEMSG } from "../../../../containers/isobmff";
23
23
  import { getTimescaledRange } from "../../../utils/index_helpers";
24
- import { IResolvedBaseUrl } from "../resolve_base_urls";
25
24
  import getInitSegment from "./get_init_segment";
26
- import { createIndexURLs } from "./tokens";
25
+ import { constructRepresentationUrl } from "./tokens";
27
26
 
28
27
  /**
29
28
  * Index property defined for a SegmentList RepresentationIndex
@@ -53,18 +52,21 @@ export interface IListIndex {
53
52
  indexTimeOffset : number;
54
53
  /** Information on the initialization segment. */
55
54
  initialization? : {
56
- /** URLs to access the initialization segment. */
57
- mediaURLs: string[] | null;
55
+ /**
56
+ * URL path, to add to the wanted CDN, to access the initialization segment.
57
+ * `null` if no URL exists.
58
+ */
59
+ url: string | null;
58
60
  /** possible byte range to request it. */
59
61
  range?: [number, number] | undefined;
60
62
  } | undefined;
61
63
  /** Information on the list of segments for this index. */
62
64
  list: Array<{
63
65
  /**
64
- * URLs of the segment.
66
+ * URL path, to add to the wanted CDN, to access this media segment.
65
67
  * `null` if no URL exists.
66
68
  */
67
- mediaURLs : string[] | null;
69
+ url : string | null;
68
70
  /** Possible byte-range of the segment. */
69
71
  mediaRange? : [number, number] | undefined;
70
72
  }>;
@@ -111,8 +113,6 @@ export interface IListIndexContextArgument {
111
113
  periodStart : number;
112
114
  /** End of the period concerned by this RepresentationIndex, in seconds. */
113
115
  periodEnd : number | undefined;
114
- /** Base URL for the Representation concerned. */
115
- representationBaseURLs : IResolvedBaseUrl[];
116
116
  /** ID of the Representation concerned. */
117
117
  representationId? : string | undefined;
118
118
  /** Bitrate of the Representation concerned. */
@@ -142,7 +142,6 @@ export default class ListRepresentationIndex implements IRepresentationIndex {
142
142
 
143
143
  const { periodStart,
144
144
  periodEnd,
145
- representationBaseURLs,
146
145
  representationId,
147
146
  representationBitrate,
148
147
  isEMSGWhitelisted } = context;
@@ -155,12 +154,15 @@ export default class ListRepresentationIndex implements IRepresentationIndex {
155
154
  const timescale = index.timescale ?? 1;
156
155
  const indexTimeOffset = presentationTimeOffset - periodStart * timescale;
157
156
 
158
- const urlSources : string[] = representationBaseURLs.map(b => b.url);
159
- const list = index.list.map((lItem) => ({
160
- mediaURLs: createIndexURLs(urlSources,
161
- lItem.media,
157
+ const initializationUrl = index.initialization?.media === undefined ?
158
+ null :
159
+ constructRepresentationUrl(index.initialization.media,
162
160
  representationId,
163
- representationBitrate),
161
+ representationBitrate);
162
+ const list = index.list.map((lItem) => ({
163
+ url: lItem.media === undefined ?
164
+ null :
165
+ constructRepresentationUrl(lItem.media, representationId, representationBitrate),
164
166
  mediaRange: lItem.mediaRange }));
165
167
  this._index = { list,
166
168
  timescale,
@@ -169,10 +171,7 @@ export default class ListRepresentationIndex implements IRepresentationIndex {
169
171
  indexRange: index.indexRange,
170
172
  initialization: index.initialization == null ?
171
173
  undefined :
172
- { mediaURLs: createIndexURLs(urlSources,
173
- index.initialization.media,
174
- representationId,
175
- representationBitrate),
174
+ { url: initializationUrl,
176
175
  range: index.initialization.range } };
177
176
  }
178
177
 
@@ -206,7 +205,7 @@ export default class ListRepresentationIndex implements IRepresentationIndex {
206
205
  let i = Math.floor(up / duration);
207
206
  while (i <= length) {
208
207
  const range = list[i].mediaRange;
209
- const mediaURLs = list[i].mediaURLs;
208
+ const url = list[i].url;
210
209
  const time = i * durationInSeconds + this._periodStart;
211
210
  const segment =
212
211
  { id: String(i),
@@ -216,7 +215,7 @@ export default class ListRepresentationIndex implements IRepresentationIndex {
216
215
  duration: durationInSeconds,
217
216
  timescale: 1 as const,
218
217
  end: time + durationInSeconds,
219
- mediaURLs,
218
+ url,
220
219
  timestampOffset: -(index.indexTimeOffset / timescale),
221
220
  complete: true,
222
221
  privateInfos: { isEMSGWhitelisted:
@@ -22,11 +22,10 @@ import {
22
22
  import assert from "../../../../../utils/assert";
23
23
  import { IEMSG } from "../../../../containers/isobmff";
24
24
  import ManifestBoundsCalculator from "../manifest_bounds_calculator";
25
- import { IResolvedBaseUrl } from "../resolve_base_urls";
26
25
  import getInitSegment from "./get_init_segment";
27
26
  import {
28
27
  createDashUrlDetokenizer,
29
- createIndexURLs,
28
+ constructRepresentationUrl,
30
29
  } from "./tokens";
31
30
  import { getSegmentTimeRoundingError } from "./utils";
32
31
 
@@ -52,8 +51,10 @@ export interface ITemplateIndex {
52
51
  indexRange?: [number, number] | undefined;
53
52
  /** Information on the initialization segment. */
54
53
  initialization? : {
55
- /** URLs to access the initialization segment. */
56
- mediaURLs: string[] | null;
54
+ /**
55
+ * URL path, to add to the wanted CDN, to access the initialization segment.
56
+ */
57
+ url: string | null;
57
58
  /** possible byte range to request it. */
58
59
  range?: [number, number] | undefined;
59
60
  } | undefined;
@@ -62,7 +63,7 @@ export interface ITemplateIndex {
62
63
  * Can contain token to replace to convert it to real URLs.
63
64
  * `null` if no URL exists.
64
65
  */
65
- mediaURLs : string[] | null;
66
+ url : string | null;
66
67
  /**
67
68
  * Temporal offset, in the current timescale (see timescale), to add to the
68
69
  * presentation time (time a segment has at decoding time) to obtain the
@@ -124,8 +125,6 @@ export interface ITemplateIndexContextArgument {
124
125
  periodEnd : number|undefined;
125
126
  /** Whether the corresponding Manifest can be updated and changed. */
126
127
  isDynamic : boolean;
127
- /** Base URL for the Representation concerned. */
128
- representationBaseURLs : IResolvedBaseUrl[];
129
128
  /** ID of the Representation concerned. */
130
129
  representationId? : string | undefined;
131
130
  /** Bitrate of the Representation concerned. */
@@ -174,18 +173,12 @@ export default class TemplateRepresentationIndex implements IRepresentationIndex
174
173
  isDynamic,
175
174
  periodEnd,
176
175
  periodStart,
177
- representationBaseURLs,
178
176
  representationId,
179
177
  representationBitrate,
180
178
  isEMSGWhitelisted } = context;
181
179
  const timescale = index.timescale ?? 1;
182
180
 
183
- const minBaseUrlAto = representationBaseURLs.length === 0 ?
184
- 0 :
185
- representationBaseURLs.reduce((acc, rbu) => {
186
- return Math.min(acc, rbu.availabilityTimeOffset);
187
- }, Infinity);
188
- this._availabilityTimeOffset = availabilityTimeOffset + minBaseUrlAto;
181
+ this._availabilityTimeOffset = availabilityTimeOffset;
189
182
 
190
183
  this._manifestBoundsCalculator = manifestBoundsCalculator;
191
184
  this._aggressiveMode = aggressiveMode;
@@ -200,22 +193,25 @@ export default class TemplateRepresentationIndex implements IRepresentationIndex
200
193
  throw new Error("Invalid SegmentTemplate: no duration");
201
194
  }
202
195
 
203
- const urlSources : string[] = representationBaseURLs.map(b => b.url);
196
+ const initializationUrl = index.initialization?.media === undefined ?
197
+ null :
198
+ constructRepresentationUrl(index.initialization.media,
199
+ representationId,
200
+ representationBitrate);
201
+
202
+ const segmentUrlTemplate = index.media === undefined ?
203
+ null :
204
+ constructRepresentationUrl(index.media, representationId, representationBitrate);
205
+
204
206
  this._index = { duration: index.duration,
205
207
  timescale,
206
208
  indexRange: index.indexRange,
207
209
  indexTimeOffset,
208
210
  initialization: index.initialization == null ?
209
211
  undefined :
210
- { mediaURLs: createIndexURLs(urlSources,
211
- index.initialization.media,
212
- representationId,
213
- representationBitrate),
212
+ { url: initializationUrl,
214
213
  range: index.initialization.range },
215
- mediaURLs: createIndexURLs(urlSources,
216
- index.media,
217
- representationId,
218
- representationBitrate),
214
+ url: segmentUrlTemplate,
219
215
  presentationTimeOffset,
220
216
  startNumber: index.startNumber };
221
217
  this._isDynamic = isDynamic;
@@ -244,7 +240,7 @@ export default class TemplateRepresentationIndex implements IRepresentationIndex
244
240
  const { duration,
245
241
  startNumber,
246
242
  timescale,
247
- mediaURLs } = index;
243
+ url } = index;
248
244
 
249
245
  const scaledStart = this._periodStart * timescale;
250
246
  const scaledEnd = this._scaledRelativePeriodEnd;
@@ -288,9 +284,9 @@ export default class TemplateRepresentationIndex implements IRepresentationIndex
288
284
  const realTime = timeFromPeriodStart + scaledStart;
289
285
  const manifestTime = timeFromPeriodStart + this._index.presentationTimeOffset;
290
286
 
291
- const detokenizedURLs = mediaURLs === null ?
287
+ const detokenizedURL = url === null ?
292
288
  null :
293
- mediaURLs.map(createDashUrlDetokenizer(manifestTime, realNumber));
289
+ createDashUrlDetokenizer(manifestTime, realNumber)(url);
294
290
 
295
291
  const args = { id: String(realNumber),
296
292
  number: realNumber,
@@ -300,7 +296,7 @@ export default class TemplateRepresentationIndex implements IRepresentationIndex
300
296
  timescale: 1 as const,
301
297
  isInit: false,
302
298
  scaledDuration: realDuration / timescale,
303
- mediaURLs: detokenizedURLs,
299
+ url: detokenizedURL,
304
300
  timestampOffset: -(index.indexTimeOffset / timescale),
305
301
  complete: true,
306
302
  privateInfos: {