@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,302 @@
1
+ import { Events, type HlsListeners } from '../events';
2
+ import {
3
+ eventAssetToString,
4
+ getInterstitialUrl,
5
+ type InterstitialAssetId,
6
+ type InterstitialAssetItem,
7
+ type InterstitialEvent,
8
+ type InterstitialId,
9
+ } from '../loader/interstitial-event';
10
+ import { BufferHelper } from '../utils/buffer-helper';
11
+ import type { HlsConfig } from '../config';
12
+ import type { InterstitialScheduleEventItem } from '../controller/interstitials-schedule';
13
+ import type Hls from '../hls';
14
+ import type { BufferCodecsData, MediaAttachingData } from '../types/events';
15
+
16
+ export interface InterstitialPlayer {
17
+ bufferedEnd: number;
18
+ currentTime: number;
19
+ duration: number;
20
+ assetPlayers: (HlsAssetPlayer | null)[];
21
+ playingIndex: number;
22
+ scheduleItem: InterstitialScheduleEventItem | null;
23
+ }
24
+
25
+ export type HlsAssetPlayerConfig = Partial<HlsConfig> &
26
+ Required<Pick<HlsConfig, 'assetPlayerId' | 'primarySessionId'>>;
27
+
28
+ export class HlsAssetPlayer {
29
+ public hls: Hls | null;
30
+ public interstitial: InterstitialEvent;
31
+ public readonly assetItem: InterstitialAssetItem;
32
+ public tracks: Partial<BufferCodecsData> | null = null;
33
+ private hasDetails: boolean = false;
34
+ private mediaAttached: HTMLMediaElement | null = null;
35
+ private _currentTime?: number;
36
+ private _bufferedEosTime?: number;
37
+
38
+ constructor(
39
+ HlsPlayerClass: typeof Hls,
40
+ userConfig: HlsAssetPlayerConfig,
41
+ interstitial: InterstitialEvent,
42
+ assetItem: InterstitialAssetItem,
43
+ ) {
44
+ const hls = (this.hls = new HlsPlayerClass(userConfig));
45
+ this.interstitial = interstitial;
46
+ this.assetItem = assetItem;
47
+ const detailsLoaded = () => {
48
+ this.hasDetails = true;
49
+ };
50
+ hls.once(Events.LEVEL_LOADED, detailsLoaded);
51
+ hls.once(Events.AUDIO_TRACK_LOADED, detailsLoaded);
52
+ hls.once(Events.SUBTITLE_TRACK_LOADED, detailsLoaded);
53
+ hls.on(Events.MEDIA_ATTACHING, (name, { media }) => {
54
+ this.removeMediaListeners();
55
+ this.mediaAttached = media;
56
+ const event = this.interstitial;
57
+ if (event.playoutLimit) {
58
+ media.addEventListener('timeupdate', this.checkPlayout);
59
+ if (this.appendInPlace) {
60
+ hls.on(Events.BUFFER_APPENDED, () => {
61
+ const bufferedEnd = this.bufferedEnd;
62
+ if (this.reachedPlayout(bufferedEnd)) {
63
+ this._bufferedEosTime = bufferedEnd;
64
+ hls.trigger(Events.BUFFERED_TO_END, undefined);
65
+ }
66
+ });
67
+ }
68
+ }
69
+ });
70
+ }
71
+
72
+ get appendInPlace(): boolean {
73
+ return this.interstitial.appendInPlace;
74
+ }
75
+
76
+ loadSource() {
77
+ const hls = this.hls;
78
+ if (!hls) {
79
+ return;
80
+ }
81
+ if (!hls.url) {
82
+ let uri: string = this.assetItem.uri;
83
+ try {
84
+ uri = getInterstitialUrl(uri, hls.config.primarySessionId || '').href;
85
+ } catch (error) {
86
+ // Ignore error parsing ASSET_URI or adding _HLS_primary_id to it. The
87
+ // issue should surface as an INTERSTITIAL_ASSET_ERROR loading the asset.
88
+ }
89
+ hls.loadSource(uri);
90
+ } else if (hls.levels.length && !(hls as any).started) {
91
+ hls.startLoad(-1, true);
92
+ }
93
+ }
94
+
95
+ bufferedInPlaceToEnd(media?: HTMLMediaElement | null) {
96
+ if (!this.appendInPlace) {
97
+ return false;
98
+ }
99
+ if (this.hls?.bufferedToEnd) {
100
+ return true;
101
+ }
102
+ if (!media) {
103
+ return false;
104
+ }
105
+ const duration = Math.min(this._bufferedEosTime || Infinity, this.duration);
106
+ const start = this.timelineOffset;
107
+ const bufferInfo = BufferHelper.bufferInfo(media, start, 0);
108
+ const bufferedEnd = this.getAssetTime(bufferInfo.end);
109
+ return bufferedEnd >= duration - 0.02;
110
+ }
111
+
112
+ private checkPlayout = () => {
113
+ if (this.reachedPlayout(this.currentTime) && this.hls) {
114
+ this.hls.trigger(Events.PLAYOUT_LIMIT_REACHED, {});
115
+ }
116
+ };
117
+
118
+ private reachedPlayout(time: number): boolean {
119
+ const interstitial = this.interstitial;
120
+ const playoutLimit = interstitial.playoutLimit;
121
+ return this.startOffset + time >= playoutLimit;
122
+ }
123
+
124
+ get destroyed(): boolean {
125
+ return !this.hls?.userConfig;
126
+ }
127
+
128
+ get assetId(): InterstitialAssetId {
129
+ return this.assetItem.identifier;
130
+ }
131
+
132
+ get interstitialId(): InterstitialId {
133
+ return this.assetItem.parentIdentifier;
134
+ }
135
+
136
+ get media(): HTMLMediaElement | null {
137
+ return this.hls?.media || null;
138
+ }
139
+
140
+ get bufferedEnd(): number {
141
+ const media = this.media || this.mediaAttached;
142
+ if (!media) {
143
+ if (this._bufferedEosTime) {
144
+ return this._bufferedEosTime;
145
+ }
146
+ return this.currentTime;
147
+ }
148
+ const bufferInfo = BufferHelper.bufferInfo(media, media.currentTime, 0.001);
149
+ return this.getAssetTime(bufferInfo.end);
150
+ }
151
+
152
+ get currentTime(): number {
153
+ const media = this.media || this.mediaAttached;
154
+ if (!media) {
155
+ return this._currentTime || 0;
156
+ }
157
+ return this.getAssetTime(media.currentTime);
158
+ }
159
+
160
+ get duration(): number {
161
+ const duration = this.assetItem.duration;
162
+ if (!duration) {
163
+ return 0;
164
+ }
165
+ const playoutLimit = this.interstitial.playoutLimit;
166
+ if (playoutLimit) {
167
+ const assetPlayout = playoutLimit - this.startOffset;
168
+ if (assetPlayout > 0 && assetPlayout < duration) {
169
+ return assetPlayout;
170
+ }
171
+ }
172
+ return duration;
173
+ }
174
+
175
+ get remaining(): number {
176
+ const duration = this.duration;
177
+ if (!duration) {
178
+ return 0;
179
+ }
180
+ return Math.max(0, duration - this.currentTime);
181
+ }
182
+
183
+ get startOffset(): number {
184
+ return this.assetItem.startOffset;
185
+ }
186
+
187
+ get timelineOffset(): number {
188
+ return this.hls?.config.timelineOffset || 0;
189
+ }
190
+
191
+ set timelineOffset(value: number) {
192
+ const timelineOffset = this.timelineOffset;
193
+ if (value !== timelineOffset) {
194
+ const diff = value - timelineOffset;
195
+ if (Math.abs(diff) > 1 / 90000 && this.hls) {
196
+ if (this.hasDetails) {
197
+ throw new Error(
198
+ `Cannot set timelineOffset after playlists are loaded`,
199
+ );
200
+ }
201
+ this.hls.config.timelineOffset = value;
202
+ }
203
+ }
204
+ }
205
+
206
+ private getAssetTime(time: number): number {
207
+ const timelineOffset = this.timelineOffset;
208
+ const duration = this.duration;
209
+ return Math.min(Math.max(0, time - timelineOffset), duration);
210
+ }
211
+
212
+ private removeMediaListeners() {
213
+ const media = this.mediaAttached;
214
+ if (media) {
215
+ this._currentTime = media.currentTime;
216
+ this.bufferSnapShot();
217
+ media.removeEventListener('timeupdate', this.checkPlayout);
218
+ }
219
+ }
220
+
221
+ private bufferSnapShot() {
222
+ if (this.mediaAttached) {
223
+ if (this.hls?.bufferedToEnd) {
224
+ this._bufferedEosTime = this.bufferedEnd;
225
+ }
226
+ }
227
+ }
228
+
229
+ destroy() {
230
+ this.removeMediaListeners();
231
+ if (this.hls) {
232
+ this.hls.destroy();
233
+ }
234
+ this.hls = null;
235
+ // @ts-ignore
236
+ this.tracks = this.mediaAttached = this.checkPlayout = null;
237
+ }
238
+
239
+ attachMedia(data: HTMLMediaElement | MediaAttachingData) {
240
+ this.loadSource();
241
+ this.hls?.attachMedia(data);
242
+ }
243
+
244
+ detachMedia() {
245
+ this.removeMediaListeners();
246
+ this.mediaAttached = null;
247
+ this.hls?.detachMedia();
248
+ }
249
+
250
+ resumeBuffering() {
251
+ this.hls?.resumeBuffering();
252
+ }
253
+
254
+ pauseBuffering() {
255
+ this.hls?.pauseBuffering();
256
+ }
257
+
258
+ transferMedia() {
259
+ this.bufferSnapShot();
260
+ return this.hls?.transferMedia() || null;
261
+ }
262
+
263
+ resetDetails() {
264
+ const hls = this.hls;
265
+ if (hls && this.hasDetails) {
266
+ hls.stopLoad();
267
+ const deleteDetails = (obj) => delete obj.details;
268
+ hls.levels.forEach(deleteDetails);
269
+ hls.allAudioTracks.forEach(deleteDetails);
270
+ hls.allSubtitleTracks.forEach(deleteDetails);
271
+ this.hasDetails = false;
272
+ }
273
+ }
274
+
275
+ on<E extends keyof HlsListeners, Context = undefined>(
276
+ event: E,
277
+ listener: HlsListeners[E],
278
+ context?: Context,
279
+ ) {
280
+ this.hls?.on(event, listener);
281
+ }
282
+
283
+ once<E extends keyof HlsListeners, Context = undefined>(
284
+ event: E,
285
+ listener: HlsListeners[E],
286
+ context?: Context,
287
+ ) {
288
+ this.hls?.once(event, listener);
289
+ }
290
+
291
+ off<E extends keyof HlsListeners, Context = undefined>(
292
+ event: E,
293
+ listener: HlsListeners[E],
294
+ context?: Context,
295
+ ) {
296
+ this.hls?.off(event, listener);
297
+ }
298
+
299
+ toString(): string {
300
+ return `HlsAssetPlayer: ${eventAssetToString(this.assetItem)} ${this.hls?.sessionId} ${this.appendInPlace ? 'append-in-place' : ''}`;
301
+ }
302
+ }