@zenvor/hls.js 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +472 -0
  3. package/dist/hls-demo.js +26995 -0
  4. package/dist/hls-demo.js.map +1 -0
  5. package/dist/hls.d.mts +4204 -0
  6. package/dist/hls.d.ts +4204 -0
  7. package/dist/hls.js +40050 -0
  8. package/dist/hls.js.d.ts +4204 -0
  9. package/dist/hls.js.map +1 -0
  10. package/dist/hls.light.js +27145 -0
  11. package/dist/hls.light.js.map +1 -0
  12. package/dist/hls.light.min.js +2 -0
  13. package/dist/hls.light.min.js.map +1 -0
  14. package/dist/hls.light.mjs +26392 -0
  15. package/dist/hls.light.mjs.map +1 -0
  16. package/dist/hls.min.js +2 -0
  17. package/dist/hls.min.js.map +1 -0
  18. package/dist/hls.mjs +38956 -0
  19. package/dist/hls.mjs.map +1 -0
  20. package/dist/hls.worker.js +2 -0
  21. package/dist/hls.worker.js.map +1 -0
  22. package/package.json +143 -0
  23. package/src/config.ts +794 -0
  24. package/src/controller/abr-controller.ts +1019 -0
  25. package/src/controller/algo-data-controller.ts +794 -0
  26. package/src/controller/audio-stream-controller.ts +1099 -0
  27. package/src/controller/audio-track-controller.ts +454 -0
  28. package/src/controller/base-playlist-controller.ts +438 -0
  29. package/src/controller/base-stream-controller.ts +2526 -0
  30. package/src/controller/buffer-controller.ts +2015 -0
  31. package/src/controller/buffer-operation-queue.ts +159 -0
  32. package/src/controller/cap-level-controller.ts +367 -0
  33. package/src/controller/cmcd-controller.ts +422 -0
  34. package/src/controller/content-steering-controller.ts +622 -0
  35. package/src/controller/eme-controller.ts +1617 -0
  36. package/src/controller/error-controller.ts +627 -0
  37. package/src/controller/fps-controller.ts +146 -0
  38. package/src/controller/fragment-finders.ts +256 -0
  39. package/src/controller/fragment-tracker.ts +567 -0
  40. package/src/controller/gap-controller.ts +719 -0
  41. package/src/controller/id3-track-controller.ts +488 -0
  42. package/src/controller/interstitial-player.ts +302 -0
  43. package/src/controller/interstitials-controller.ts +2895 -0
  44. package/src/controller/interstitials-schedule.ts +698 -0
  45. package/src/controller/latency-controller.ts +294 -0
  46. package/src/controller/level-controller.ts +776 -0
  47. package/src/controller/stream-controller.ts +1597 -0
  48. package/src/controller/subtitle-stream-controller.ts +508 -0
  49. package/src/controller/subtitle-track-controller.ts +617 -0
  50. package/src/controller/timeline-controller.ts +677 -0
  51. package/src/crypt/aes-crypto.ts +36 -0
  52. package/src/crypt/aes-decryptor.ts +339 -0
  53. package/src/crypt/decrypter-aes-mode.ts +4 -0
  54. package/src/crypt/decrypter.ts +225 -0
  55. package/src/crypt/fast-aes-key.ts +39 -0
  56. package/src/define-plugin.d.ts +17 -0
  57. package/src/demux/audio/aacdemuxer.ts +126 -0
  58. package/src/demux/audio/ac3-demuxer.ts +170 -0
  59. package/src/demux/audio/adts.ts +249 -0
  60. package/src/demux/audio/base-audio-demuxer.ts +205 -0
  61. package/src/demux/audio/dolby.ts +21 -0
  62. package/src/demux/audio/mp3demuxer.ts +85 -0
  63. package/src/demux/audio/mpegaudio.ts +177 -0
  64. package/src/demux/chunk-cache.ts +42 -0
  65. package/src/demux/dummy-demuxed-track.ts +13 -0
  66. package/src/demux/inject-worker.ts +75 -0
  67. package/src/demux/mp4demuxer.ts +234 -0
  68. package/src/demux/sample-aes.ts +198 -0
  69. package/src/demux/transmuxer-interface.ts +449 -0
  70. package/src/demux/transmuxer-worker.ts +221 -0
  71. package/src/demux/transmuxer.ts +560 -0
  72. package/src/demux/tsdemuxer.ts +1256 -0
  73. package/src/demux/video/avc-video-parser.ts +401 -0
  74. package/src/demux/video/base-video-parser.ts +198 -0
  75. package/src/demux/video/exp-golomb.ts +153 -0
  76. package/src/demux/video/hevc-video-parser.ts +736 -0
  77. package/src/empty-es.js +5 -0
  78. package/src/empty.js +3 -0
  79. package/src/errors.ts +107 -0
  80. package/src/events.ts +548 -0
  81. package/src/exports-default.ts +3 -0
  82. package/src/exports-named.ts +81 -0
  83. package/src/hls.ts +1613 -0
  84. package/src/is-supported.ts +54 -0
  85. package/src/loader/date-range.ts +207 -0
  86. package/src/loader/fragment-loader.ts +403 -0
  87. package/src/loader/fragment.ts +487 -0
  88. package/src/loader/interstitial-asset-list.ts +162 -0
  89. package/src/loader/interstitial-event.ts +337 -0
  90. package/src/loader/key-loader.ts +439 -0
  91. package/src/loader/level-details.ts +203 -0
  92. package/src/loader/level-key.ts +259 -0
  93. package/src/loader/load-stats.ts +17 -0
  94. package/src/loader/m3u8-parser.ts +1072 -0
  95. package/src/loader/playlist-loader.ts +839 -0
  96. package/src/polyfills/number.ts +15 -0
  97. package/src/remux/aac-helper.ts +81 -0
  98. package/src/remux/mp4-generator.ts +1380 -0
  99. package/src/remux/mp4-remuxer.ts +1261 -0
  100. package/src/remux/passthrough-remuxer.ts +434 -0
  101. package/src/task-loop.ts +130 -0
  102. package/src/types/algo.ts +44 -0
  103. package/src/types/buffer.ts +105 -0
  104. package/src/types/component-api.ts +20 -0
  105. package/src/types/demuxer.ts +208 -0
  106. package/src/types/events.ts +574 -0
  107. package/src/types/fragment-tracker.ts +23 -0
  108. package/src/types/level.ts +268 -0
  109. package/src/types/loader.ts +198 -0
  110. package/src/types/media-playlist.ts +92 -0
  111. package/src/types/network-details.ts +3 -0
  112. package/src/types/remuxer.ts +104 -0
  113. package/src/types/track.ts +12 -0
  114. package/src/types/transmuxer.ts +46 -0
  115. package/src/types/tuples.ts +6 -0
  116. package/src/types/vtt.ts +11 -0
  117. package/src/utils/arrays.ts +22 -0
  118. package/src/utils/attr-list.ts +192 -0
  119. package/src/utils/binary-search.ts +46 -0
  120. package/src/utils/buffer-helper.ts +173 -0
  121. package/src/utils/cea-608-parser.ts +1413 -0
  122. package/src/utils/chunker.ts +41 -0
  123. package/src/utils/codecs.ts +314 -0
  124. package/src/utils/cues.ts +96 -0
  125. package/src/utils/discontinuities.ts +174 -0
  126. package/src/utils/encryption-methods-util.ts +21 -0
  127. package/src/utils/error-helper.ts +95 -0
  128. package/src/utils/event-listener-helper.ts +16 -0
  129. package/src/utils/ewma-bandwidth-estimator.ts +97 -0
  130. package/src/utils/ewma.ts +43 -0
  131. package/src/utils/fetch-loader.ts +331 -0
  132. package/src/utils/global.ts +2 -0
  133. package/src/utils/hash.ts +10 -0
  134. package/src/utils/hdr.ts +67 -0
  135. package/src/utils/hex.ts +32 -0
  136. package/src/utils/imsc1-ttml-parser.ts +261 -0
  137. package/src/utils/keysystem-util.ts +45 -0
  138. package/src/utils/level-helper.ts +629 -0
  139. package/src/utils/logger.ts +120 -0
  140. package/src/utils/media-option-attributes.ts +49 -0
  141. package/src/utils/mediacapabilities-helper.ts +301 -0
  142. package/src/utils/mediakeys-helper.ts +210 -0
  143. package/src/utils/mediasource-helper.ts +37 -0
  144. package/src/utils/mp4-tools.ts +1473 -0
  145. package/src/utils/number.ts +3 -0
  146. package/src/utils/numeric-encoding-utils.ts +26 -0
  147. package/src/utils/output-filter.ts +46 -0
  148. package/src/utils/rendition-helper.ts +505 -0
  149. package/src/utils/safe-json-stringify.ts +22 -0
  150. package/src/utils/texttrack-utils.ts +164 -0
  151. package/src/utils/time-ranges.ts +17 -0
  152. package/src/utils/timescale-conversion.ts +46 -0
  153. package/src/utils/utf8-utils.ts +18 -0
  154. package/src/utils/variable-substitution.ts +105 -0
  155. package/src/utils/vttcue.ts +384 -0
  156. package/src/utils/vttparser.ts +497 -0
  157. package/src/utils/webvtt-parser.ts +166 -0
  158. package/src/utils/xhr-loader.ts +337 -0
  159. package/src/version.ts +1 -0
@@ -0,0 +1,454 @@
1
+ import BasePlaylistController from './base-playlist-controller';
2
+ import { ErrorDetails, ErrorTypes } from '../errors';
3
+ import { Events } from '../events';
4
+ import { PlaylistContextType } from '../types/loader';
5
+ import { mediaAttributesIdentical } from '../utils/media-option-attributes';
6
+ import {
7
+ audioMatchPredicate,
8
+ findClosestLevelWithAudioGroup,
9
+ findMatchingOption,
10
+ matchesOption,
11
+ useAlternateAudio,
12
+ } from '../utils/rendition-helper';
13
+ import type Hls from '../hls';
14
+ import type {
15
+ AudioTrackLoadedData,
16
+ AudioTracksUpdatedData,
17
+ ErrorData,
18
+ LevelLoadingData,
19
+ LevelSwitchingData,
20
+ ManifestParsedData,
21
+ } from '../types/events';
22
+ import type { HlsUrlParameters } from '../types/level';
23
+ import type {
24
+ AudioSelectionOption,
25
+ MediaPlaylist,
26
+ } from '../types/media-playlist';
27
+
28
+ class AudioTrackController extends BasePlaylistController {
29
+ private tracks: MediaPlaylist[] = [];
30
+ private groupIds: (string | undefined)[] | null = null;
31
+ private tracksInGroup: MediaPlaylist[] = [];
32
+ private trackId: number = -1;
33
+ private currentTrack: MediaPlaylist | null = null;
34
+ private selectDefaultTrack: boolean = true;
35
+
36
+ constructor(hls: Hls) {
37
+ super(hls, 'audio-track-controller');
38
+ this.registerListeners();
39
+ }
40
+
41
+ private registerListeners() {
42
+ const { hls } = this;
43
+ hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
44
+ hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
45
+ hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
46
+ hls.on(Events.LEVEL_SWITCHING, this.onLevelSwitching, this);
47
+ hls.on(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this);
48
+ hls.on(Events.ERROR, this.onError, this);
49
+ }
50
+
51
+ private unregisterListeners() {
52
+ const { hls } = this;
53
+ hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
54
+ hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
55
+ hls.off(Events.LEVEL_LOADING, this.onLevelLoading, this);
56
+ hls.off(Events.LEVEL_SWITCHING, this.onLevelSwitching, this);
57
+ hls.off(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this);
58
+ hls.off(Events.ERROR, this.onError, this);
59
+ }
60
+
61
+ public destroy() {
62
+ this.unregisterListeners();
63
+ this.tracks.length = 0;
64
+ this.tracksInGroup.length = 0;
65
+ this.currentTrack = null;
66
+ super.destroy();
67
+ }
68
+
69
+ protected onManifestLoading(): void {
70
+ this.tracks = [];
71
+ this.tracksInGroup = [];
72
+ this.groupIds = null;
73
+ this.currentTrack = null;
74
+ this.trackId = -1;
75
+ this.selectDefaultTrack = true;
76
+ }
77
+
78
+ protected onManifestParsed(
79
+ event: Events.MANIFEST_PARSED,
80
+ data: ManifestParsedData,
81
+ ): void {
82
+ this.tracks = data.audioTracks || [];
83
+ }
84
+
85
+ protected onAudioTrackLoaded(
86
+ event: Events.AUDIO_TRACK_LOADED,
87
+ data: AudioTrackLoadedData,
88
+ ): void {
89
+ const { id, groupId, details } = data;
90
+ const trackInActiveGroup = this.tracksInGroup[id];
91
+
92
+ if (
93
+ !trackInActiveGroup ||
94
+ trackInActiveGroup.groupId !== (groupId as string | undefined)
95
+ ) {
96
+ this.warn(
97
+ `Audio track with id:${id} and group:${groupId} not found in active group ${trackInActiveGroup?.groupId}`,
98
+ );
99
+ return;
100
+ }
101
+
102
+ const curDetails = trackInActiveGroup.details;
103
+ trackInActiveGroup.details = data.details;
104
+ this.log(
105
+ `Audio track ${id} "${trackInActiveGroup.name}" lang:${trackInActiveGroup.lang} group:${groupId} loaded [${details.startSN}-${details.endSN}]`,
106
+ );
107
+
108
+ if (id === this.trackId) {
109
+ this.playlistLoaded(id, data, curDetails);
110
+ }
111
+ }
112
+
113
+ protected onLevelLoading(
114
+ event: Events.LEVEL_LOADING,
115
+ data: LevelLoadingData,
116
+ ): void {
117
+ this.switchLevel(data.level);
118
+ }
119
+
120
+ protected onLevelSwitching(
121
+ event: Events.LEVEL_SWITCHING,
122
+ data: LevelSwitchingData,
123
+ ): void {
124
+ this.switchLevel(data.level);
125
+ }
126
+
127
+ private switchLevel(levelIndex: number) {
128
+ const levelInfo = this.hls.levels[levelIndex];
129
+ if (!levelInfo) {
130
+ return;
131
+ }
132
+ const audioGroups = levelInfo.audioGroups || null;
133
+ const currentGroups = this.groupIds;
134
+ let currentTrack = this.currentTrack;
135
+ if (
136
+ !audioGroups ||
137
+ currentGroups?.length !== audioGroups?.length ||
138
+ audioGroups?.some((groupId) => currentGroups?.indexOf(groupId) === -1)
139
+ ) {
140
+ this.groupIds = audioGroups;
141
+ this.trackId = -1;
142
+ this.currentTrack = null;
143
+
144
+ const audioTracks = this.tracks.filter(
145
+ (track): boolean =>
146
+ !audioGroups || audioGroups.indexOf(track.groupId) !== -1,
147
+ );
148
+ if (audioTracks.length) {
149
+ // Disable selectDefaultTrack if there are no default tracks
150
+ if (
151
+ this.selectDefaultTrack &&
152
+ !audioTracks.some((track) => track.default)
153
+ ) {
154
+ this.selectDefaultTrack = false;
155
+ }
156
+ // track.id should match hls.audioTracks index
157
+ audioTracks.forEach((track, i) => {
158
+ track.id = i;
159
+ });
160
+ } else if (!currentTrack && !this.tracksInGroup.length) {
161
+ // Do not dispatch AUDIO_TRACKS_UPDATED when there were and are no tracks
162
+ return;
163
+ }
164
+ this.tracksInGroup = audioTracks;
165
+
166
+ // Find preferred track
167
+ const audioPreference = this.hls.config.audioPreference;
168
+ if (!currentTrack && audioPreference) {
169
+ const groupIndex = findMatchingOption(
170
+ audioPreference,
171
+ audioTracks,
172
+ audioMatchPredicate,
173
+ );
174
+ if (groupIndex > -1) {
175
+ currentTrack = audioTracks[groupIndex];
176
+ } else {
177
+ const allIndex = findMatchingOption(audioPreference, this.tracks);
178
+ currentTrack = this.tracks[allIndex];
179
+ }
180
+ }
181
+
182
+ // Select initial track
183
+ let trackId = this.findTrackId(currentTrack);
184
+ if (trackId === -1 && currentTrack) {
185
+ trackId = this.findTrackId(null);
186
+ }
187
+
188
+ // Dispatch events and load track if needed
189
+ const audioTracksUpdated: AudioTracksUpdatedData = { audioTracks };
190
+ this.log(
191
+ `Updating audio tracks, ${
192
+ audioTracks.length
193
+ } track(s) found in group(s): ${audioGroups?.join(',')}`,
194
+ );
195
+ this.hls.trigger(Events.AUDIO_TRACKS_UPDATED, audioTracksUpdated);
196
+
197
+ const selectedTrackId = this.trackId;
198
+ if (trackId !== -1 && selectedTrackId === -1) {
199
+ this.setAudioTrack(trackId);
200
+ } else if (audioTracks.length && selectedTrackId === -1) {
201
+ const error = new Error(
202
+ `No audio track selected for current audio group-ID(s): ${this.groupIds?.join(
203
+ ',',
204
+ )} track count: ${audioTracks.length}`,
205
+ );
206
+ this.warn(error.message);
207
+
208
+ this.hls.trigger(Events.ERROR, {
209
+ type: ErrorTypes.MEDIA_ERROR,
210
+ details: ErrorDetails.AUDIO_TRACK_LOAD_ERROR,
211
+ fatal: true,
212
+ error,
213
+ });
214
+ }
215
+ }
216
+ }
217
+
218
+ protected onError(event: Events.ERROR, data: ErrorData): void {
219
+ if (data.fatal || !data.context) {
220
+ return;
221
+ }
222
+
223
+ if (
224
+ data.context.type === PlaylistContextType.AUDIO_TRACK &&
225
+ data.context.id === this.trackId &&
226
+ (!this.groupIds || this.groupIds.indexOf(data.context.groupId) !== -1)
227
+ ) {
228
+ this.checkRetry(data);
229
+ }
230
+ }
231
+
232
+ get allAudioTracks(): MediaPlaylist[] {
233
+ return this.tracks;
234
+ }
235
+
236
+ get audioTracks(): MediaPlaylist[] {
237
+ return this.tracksInGroup;
238
+ }
239
+
240
+ get audioTrack(): number {
241
+ return this.trackId;
242
+ }
243
+
244
+ set audioTrack(newId: number) {
245
+ // If audio track is selected from API then don't choose from the manifest default track
246
+ this.selectDefaultTrack = false;
247
+ this.setAudioTrack(newId);
248
+ }
249
+
250
+ get nextAudioTrack(): number {
251
+ return this.trackId;
252
+ }
253
+
254
+ set nextAudioTrack(newId: number) {
255
+ // If audio track is selected from API then don't choose from the manifest default track
256
+ this.selectDefaultTrack = false;
257
+ this.setAudioTrack(newId, false);
258
+ }
259
+
260
+ public setAudioOption(
261
+ audioOption: MediaPlaylist | AudioSelectionOption | undefined,
262
+ ): MediaPlaylist | null {
263
+ const hls = this.hls;
264
+ hls.config.audioPreference = audioOption;
265
+ if (audioOption) {
266
+ const allAudioTracks = this.allAudioTracks;
267
+ this.selectDefaultTrack = false;
268
+ if (allAudioTracks.length) {
269
+ // First see if current option matches (no switch op)
270
+ const currentTrack = this.currentTrack;
271
+ if (
272
+ currentTrack &&
273
+ matchesOption(audioOption, currentTrack, audioMatchPredicate)
274
+ ) {
275
+ return currentTrack;
276
+ }
277
+ // Find option in available tracks (tracksInGroup)
278
+ const groupIndex = findMatchingOption(
279
+ audioOption,
280
+ this.tracksInGroup,
281
+ audioMatchPredicate,
282
+ );
283
+ if (groupIndex > -1) {
284
+ const track = this.tracksInGroup[groupIndex];
285
+ this.setAudioTrack(groupIndex);
286
+ return track;
287
+ } else if (currentTrack) {
288
+ // Find option in nearest level audio group
289
+ let searchIndex = hls.loadLevel;
290
+ if (searchIndex === -1) {
291
+ searchIndex = hls.firstAutoLevel;
292
+ }
293
+ const switchIndex = findClosestLevelWithAudioGroup(
294
+ audioOption,
295
+ hls.levels,
296
+ allAudioTracks,
297
+ searchIndex,
298
+ audioMatchPredicate,
299
+ );
300
+ if (switchIndex === -1) {
301
+ // could not find matching variant
302
+ return null;
303
+ }
304
+ // and switch level to acheive the audio group switch
305
+ hls.nextLoadLevel = switchIndex;
306
+ }
307
+ if (audioOption.channels || audioOption.audioCodec) {
308
+ // Could not find a match with codec / channels predicate
309
+ // Find a match without channels or codec
310
+ const withoutCodecAndChannelsMatch = findMatchingOption(
311
+ audioOption,
312
+ allAudioTracks,
313
+ );
314
+ if (withoutCodecAndChannelsMatch > -1) {
315
+ return allAudioTracks[withoutCodecAndChannelsMatch];
316
+ }
317
+ }
318
+ }
319
+ }
320
+ return null;
321
+ }
322
+
323
+ private setAudioTrack(newId: number, flushImmediate: boolean = true): void {
324
+ const tracks = this.tracksInGroup;
325
+
326
+ // check if level idx is valid
327
+ if (newId < 0 || newId >= tracks.length) {
328
+ this.warn(`Invalid audio track id: ${newId}`);
329
+ return;
330
+ }
331
+
332
+ this.selectDefaultTrack = false;
333
+ const lastTrack = this.currentTrack;
334
+ const track = tracks[newId];
335
+ const trackLoaded = track.details && !track.details.live;
336
+ if (newId === this.trackId && track === lastTrack && trackLoaded) {
337
+ return;
338
+ }
339
+ this.log(
340
+ `Switching to audio-track ${newId} "${track.name}" lang:${track.lang} group:${track.groupId} channels:${track.channels}`,
341
+ );
342
+ this.trackId = newId;
343
+ this.currentTrack = track;
344
+ this.hls.trigger(Events.AUDIO_TRACK_SWITCHING, {
345
+ ...track,
346
+ flushImmediate,
347
+ });
348
+ // Do not reload track unless live
349
+ if (trackLoaded) {
350
+ return;
351
+ }
352
+ const hlsUrlParameters = this.switchParams(
353
+ track.url,
354
+ lastTrack?.details,
355
+ track.details,
356
+ );
357
+ this.loadPlaylist(hlsUrlParameters);
358
+ }
359
+
360
+ private findTrackId(currentTrack: MediaPlaylist | null): number {
361
+ const audioTracks = this.tracksInGroup;
362
+ for (let i = 0; i < audioTracks.length; i++) {
363
+ const track = audioTracks[i];
364
+ if (this.selectDefaultTrack && !track.default) {
365
+ continue;
366
+ }
367
+ if (
368
+ !currentTrack ||
369
+ matchesOption(currentTrack, track, audioMatchPredicate)
370
+ ) {
371
+ return i;
372
+ }
373
+ }
374
+ if (currentTrack) {
375
+ const { name, lang, assocLang, characteristics, audioCodec, channels } =
376
+ currentTrack;
377
+ for (let i = 0; i < audioTracks.length; i++) {
378
+ const track = audioTracks[i];
379
+ if (
380
+ matchesOption(
381
+ { name, lang, assocLang, characteristics, audioCodec, channels },
382
+ track,
383
+ audioMatchPredicate,
384
+ )
385
+ ) {
386
+ return i;
387
+ }
388
+ }
389
+ for (let i = 0; i < audioTracks.length; i++) {
390
+ const track = audioTracks[i];
391
+ if (
392
+ mediaAttributesIdentical(currentTrack.attrs, track.attrs, [
393
+ 'LANGUAGE',
394
+ 'ASSOC-LANGUAGE',
395
+ 'CHARACTERISTICS',
396
+ ])
397
+ ) {
398
+ return i;
399
+ }
400
+ }
401
+ for (let i = 0; i < audioTracks.length; i++) {
402
+ const track = audioTracks[i];
403
+ if (
404
+ mediaAttributesIdentical(currentTrack.attrs, track.attrs, [
405
+ 'LANGUAGE',
406
+ ])
407
+ ) {
408
+ return i;
409
+ }
410
+ }
411
+ }
412
+ return -1;
413
+ }
414
+
415
+ protected loadPlaylist(hlsUrlParameters?: HlsUrlParameters): void {
416
+ super.loadPlaylist();
417
+ const audioTrack = this.currentTrack;
418
+ if (!this.shouldLoadPlaylist(audioTrack)) {
419
+ return;
420
+ }
421
+ // Do not load audio rendition with URI matching main variant URI
422
+ if (useAlternateAudio(audioTrack.url, this.hls)) {
423
+ this.scheduleLoading(audioTrack, hlsUrlParameters);
424
+ }
425
+ }
426
+
427
+ protected loadingPlaylist(
428
+ audioTrack: MediaPlaylist,
429
+ hlsUrlParameters: HlsUrlParameters | undefined,
430
+ ) {
431
+ super.loadingPlaylist(audioTrack, hlsUrlParameters);
432
+ const id = audioTrack.id;
433
+ const groupId = audioTrack.groupId as string;
434
+ const url = this.getUrlWithDirectives(audioTrack.url, hlsUrlParameters);
435
+ const details = audioTrack.details;
436
+ const age = details?.age;
437
+ this.log(
438
+ `Loading audio-track ${id} "${audioTrack.name}" lang:${audioTrack.lang} group:${groupId}${
439
+ hlsUrlParameters?.msn !== undefined
440
+ ? ' at sn ' + hlsUrlParameters.msn + ' part ' + hlsUrlParameters.part
441
+ : ''
442
+ }${age && details.live ? ' age ' + age.toFixed(1) + (details.type ? ' ' + details.type || '' : '') : ''} ${url}`,
443
+ );
444
+ this.hls.trigger(Events.AUDIO_TRACK_LOADING, {
445
+ url,
446
+ id,
447
+ groupId,
448
+ deliveryDirectives: hlsUrlParameters || null,
449
+ track: audioTrack,
450
+ });
451
+ }
452
+ }
453
+
454
+ export default AudioTrackController;