hls.js 1.6.0-beta.1.0.canary.10767 → 1.6.0-beta.1.0.canary.10770
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.
- package/dist/hls.d.mts +2 -0
- package/dist/hls.d.ts +2 -0
- package/dist/hls.js +53 -23
- package/dist/hls.js.d.ts +2 -0
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +39 -17
- package/dist/hls.light.js.map +1 -1
- package/dist/hls.light.min.js +1 -1
- package/dist/hls.light.min.js.map +1 -1
- package/dist/hls.light.mjs +37 -17
- package/dist/hls.light.mjs.map +1 -1
- package/dist/hls.min.js +1 -1
- package/dist/hls.min.js.map +1 -1
- package/dist/hls.mjs +51 -23
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/package.json +2 -2
- package/src/controller/audio-stream-controller.ts +6 -4
- package/src/controller/audio-track-controller.ts +10 -1
- package/src/controller/base-stream-controller.ts +21 -6
- package/src/controller/level-controller.ts +3 -1
- package/src/controller/stream-controller.ts +12 -4
- package/src/controller/subtitle-stream-controller.ts +4 -1
- package/src/controller/subtitle-track-controller.ts +12 -1
- package/src/loader/level-details.ts +12 -0
- package/src/loader/playlist-loader.ts +13 -5
@@ -601,6 +601,15 @@ export default class BaseStreamController
|
|
601
601
|
}
|
602
602
|
}
|
603
603
|
|
604
|
+
protected waitForLive(levelInfo: Level) {
|
605
|
+
const details = levelInfo.details;
|
606
|
+
return (
|
607
|
+
details?.live &&
|
608
|
+
details.type !== 'EVENT' &&
|
609
|
+
(this.levelLastLoaded !== levelInfo || details.expired)
|
610
|
+
);
|
611
|
+
}
|
612
|
+
|
604
613
|
protected flushMainBuffer(
|
605
614
|
startOffset: number,
|
606
615
|
endOffset: number,
|
@@ -1077,7 +1086,7 @@ export default class BaseStreamController
|
|
1077
1086
|
const { level: levelIndex, sn, part: partIndex } = chunkMeta;
|
1078
1087
|
if (!levels?.[levelIndex]) {
|
1079
1088
|
this.warn(
|
1080
|
-
`Levels object was unset while buffering fragment ${sn} of
|
1089
|
+
`Levels object was unset while buffering fragment ${sn} of ${this.playlistLabel()} ${levelIndex}. The current chunk will not be buffered.`,
|
1081
1090
|
);
|
1082
1091
|
return null;
|
1083
1092
|
}
|
@@ -1643,6 +1652,7 @@ export default class BaseStreamController
|
|
1643
1652
|
// Leave this.startPosition at -1, so that we can use `getInitialLiveFragment` logic when startPosition has
|
1644
1653
|
// not been specified via the config or an as an argument to startLoad (#3736).
|
1645
1654
|
startPosition = this.hls.liveSyncPosition || sliding;
|
1655
|
+
this.startPosition = -1;
|
1646
1656
|
} else {
|
1647
1657
|
this.log(`setting startPosition to 0 by default`);
|
1648
1658
|
this.startPosition = startPosition = 0;
|
@@ -1666,9 +1676,14 @@ export default class BaseStreamController
|
|
1666
1676
|
}
|
1667
1677
|
|
1668
1678
|
private handleFragLoadAborted(frag: Fragment, part: Part | undefined) {
|
1669
|
-
if (
|
1679
|
+
if (
|
1680
|
+
this.transmuxer &&
|
1681
|
+
frag.type === this.playlistType &&
|
1682
|
+
isMediaFragment(frag) &&
|
1683
|
+
frag.stats.aborted
|
1684
|
+
) {
|
1670
1685
|
this.warn(
|
1671
|
-
`Fragment ${frag.sn}${part ? ' part ' + part.index : ''} of
|
1686
|
+
`Fragment ${frag.sn}${part ? ' part ' + part.index : ''} of ${this.playlistLabel()} ${
|
1672
1687
|
frag.level
|
1673
1688
|
} was aborted`,
|
1674
1689
|
);
|
@@ -1861,7 +1876,7 @@ export default class BaseStreamController
|
|
1861
1876
|
|
1862
1877
|
protected resetWhenMissingContext(chunkMeta: ChunkMetadata) {
|
1863
1878
|
this.warn(
|
1864
|
-
`The loading context changed while buffering fragment ${chunkMeta.sn} of
|
1879
|
+
`The loading context changed while buffering fragment ${chunkMeta.sn} of ${this.playlistLabel()} ${chunkMeta.level}. This chunk will not be buffered.`,
|
1865
1880
|
);
|
1866
1881
|
this.removeUnbufferedFrags();
|
1867
1882
|
this.resetStartWhenNotLoaded(this.levelLastLoaded);
|
@@ -1930,7 +1945,7 @@ export default class BaseStreamController
|
|
1930
1945
|
);
|
1931
1946
|
if (!parsed && this.transmuxer?.error === null) {
|
1932
1947
|
const error = new Error(
|
1933
|
-
`Found no media in fragment ${frag.sn} of
|
1948
|
+
`Found no media in fragment ${frag.sn} of ${this.playlistLabel()} ${frag.level} resetting transmuxer to fallback to playlist timing`,
|
1934
1949
|
);
|
1935
1950
|
if (level.fragmentError === 0) {
|
1936
1951
|
// Mark and track the odd empty segment as a gap to avoid reloading
|
@@ -1943,7 +1958,7 @@ export default class BaseStreamController
|
|
1943
1958
|
fatal: false,
|
1944
1959
|
error,
|
1945
1960
|
frag,
|
1946
|
-
reason: `Found no media in msn ${frag.sn} of
|
1961
|
+
reason: `Found no media in msn ${frag.sn} of ${this.playlistLabel()} "${level.url}"`,
|
1947
1962
|
});
|
1948
1963
|
if (!this.hls) {
|
1949
1964
|
return;
|
@@ -648,6 +648,8 @@ export default class LevelController extends BasePlaylistController {
|
|
648
648
|
}
|
649
649
|
|
650
650
|
const pathwayId = currentLevel.attrs['PATHWAY-ID'];
|
651
|
+
const details = currentLevel.details;
|
652
|
+
const age = details?.age;
|
651
653
|
this.log(
|
652
654
|
`Loading level index ${currentLevelIndex}${
|
653
655
|
hlsUrlParameters?.msn !== undefined
|
@@ -656,7 +658,7 @@ export default class LevelController extends BasePlaylistController {
|
|
656
658
|
' part ' +
|
657
659
|
hlsUrlParameters.part
|
658
660
|
: ''
|
659
|
-
}
|
661
|
+
}${pathwayId ? ' Pathway ' + pathwayId : ''}${age && details.live ? ' age ' + age.toFixed(1) + (details.type ? ' ' + details.type || '' : '') : ''} ${url}`,
|
660
662
|
);
|
661
663
|
|
662
664
|
// console.log('Current audio track group ID:', this.hls.audioTracks[this.hls.audioTrack].groupId);
|
@@ -155,7 +155,11 @@ export default class StreamController
|
|
155
155
|
this._hasEnoughToStart = false;
|
156
156
|
}
|
157
157
|
// if startPosition undefined but lastCurrentTime set, set startPosition to last currentTime
|
158
|
-
if (
|
158
|
+
if (
|
159
|
+
lastCurrentTime > 0 &&
|
160
|
+
startPosition === -1 &&
|
161
|
+
!skipSeekToStartPosition
|
162
|
+
) {
|
159
163
|
this.log(
|
160
164
|
`Override startPosition with lastCurrentTime @${lastCurrentTime.toFixed(
|
161
165
|
3,
|
@@ -186,7 +190,9 @@ export default class StreamController
|
|
186
190
|
const details = currentLevel?.details;
|
187
191
|
if (
|
188
192
|
details &&
|
189
|
-
(!details.live ||
|
193
|
+
(!details.live ||
|
194
|
+
(this.levelLastLoaded === currentLevel &&
|
195
|
+
!this.waitForLive(currentLevel)))
|
190
196
|
) {
|
191
197
|
if (this.waitForCdnTuneIn(details)) {
|
192
198
|
break;
|
@@ -287,10 +293,11 @@ export default class StreamController
|
|
287
293
|
if (
|
288
294
|
!levelDetails ||
|
289
295
|
this.state === State.WAITING_LEVEL ||
|
290
|
-
|
296
|
+
this.waitForLive(levelInfo)
|
291
297
|
) {
|
292
298
|
this.level = level;
|
293
299
|
this.state = State.WAITING_LEVEL;
|
300
|
+
this.startFragRequested = false;
|
294
301
|
return;
|
295
302
|
}
|
296
303
|
|
@@ -649,7 +656,8 @@ export default class StreamController
|
|
649
656
|
const level = data.levelInfo;
|
650
657
|
if (
|
651
658
|
!level.details ||
|
652
|
-
(level.details.live &&
|
659
|
+
(level.details.live &&
|
660
|
+
(this.levelLastLoaded !== level || level.details.expired)) ||
|
653
661
|
this.waitForCdnTuneIn(level.details)
|
654
662
|
) {
|
655
663
|
this.state = State.WAITING_LEVEL;
|
@@ -18,8 +18,8 @@ import {
|
|
18
18
|
} from '../utils/encryption-methods-util';
|
19
19
|
import { addSliding } from '../utils/level-helper';
|
20
20
|
import { subtitleOptionsIdentical } from '../utils/media-option-attributes';
|
21
|
-
import type Hls from '../hls';
|
22
21
|
import type { FragmentTracker } from './fragment-tracker';
|
22
|
+
import type Hls from '../hls';
|
23
23
|
import type KeyLoader from '../loader/key-loader';
|
24
24
|
import type { LevelDetails } from '../loader/level-details';
|
25
25
|
import type { NetworkComponentAPI } from '../types/component-api';
|
@@ -425,6 +425,9 @@ export class SubtitleStreamController
|
|
425
425
|
if (!track || !levels.length || !track.details) {
|
426
426
|
return;
|
427
427
|
}
|
428
|
+
if (this.waitForLive(track)) {
|
429
|
+
return;
|
430
|
+
}
|
428
431
|
const { config } = this;
|
429
432
|
const currentTime = this.getLoadPosition();
|
430
433
|
const bufferedInfo = BufferHelper.bufferedInfo(
|
@@ -447,7 +447,18 @@ class SubtitleTrackController extends BasePlaylistController {
|
|
447
447
|
);
|
448
448
|
}
|
449
449
|
}
|
450
|
-
|
450
|
+
const details = currentTrack.details;
|
451
|
+
const age = details?.age;
|
452
|
+
this.log(
|
453
|
+
`Loading subtitle ${id} "${currentTrack.name}" lang:${currentTrack.lang} group:${groupId}${
|
454
|
+
hlsUrlParameters?.msn !== undefined
|
455
|
+
? ' at sn ' +
|
456
|
+
hlsUrlParameters.msn +
|
457
|
+
' part ' +
|
458
|
+
hlsUrlParameters.part
|
459
|
+
: ''
|
460
|
+
}${age && details.live ? ' age ' + age.toFixed(1) + (details.type ? ' ' + details.type || '' : '') : ''} ${url}`,
|
461
|
+
);
|
451
462
|
this.hls.trigger(Events.SUBTITLE_TRACK_LOADING, {
|
452
463
|
url,
|
453
464
|
id,
|
@@ -160,4 +160,16 @@ export class LevelDetails {
|
|
160
160
|
}
|
161
161
|
return this.endSN;
|
162
162
|
}
|
163
|
+
|
164
|
+
get expired(): boolean {
|
165
|
+
if (this.live && this.age) {
|
166
|
+
const playlistWindowDuration = this.partEnd - this.fragmentStart;
|
167
|
+
return (
|
168
|
+
this.age >
|
169
|
+
Math.max(playlistWindowDuration, this.totalduration) +
|
170
|
+
this.levelTargetDuration
|
171
|
+
);
|
172
|
+
}
|
173
|
+
return false;
|
174
|
+
}
|
163
175
|
}
|
@@ -240,17 +240,25 @@ class PlaylistLoader implements NetworkComponentAPI {
|
|
240
240
|
// Check if a loader for this context already exists
|
241
241
|
let loader = this.getInternalLoader(context);
|
242
242
|
if (loader) {
|
243
|
+
const logger = this.hls.logger;
|
243
244
|
const loaderContext = loader.context as PlaylistLoaderContext;
|
244
245
|
if (
|
245
246
|
loaderContext &&
|
246
|
-
loaderContext.
|
247
|
-
loaderContext.
|
247
|
+
loaderContext.levelOrTrack === context.levelOrTrack &&
|
248
|
+
(loaderContext.url === context.url ||
|
249
|
+
(loaderContext.deliveryDirectives && !context.deliveryDirectives))
|
248
250
|
) {
|
249
|
-
// same URL can't overlap
|
250
|
-
|
251
|
+
// same URL can't overlap, or wait for blocking request
|
252
|
+
if (loaderContext.url === context.url) {
|
253
|
+
logger.log(`[playlist-loader]: playlist request ongoing`);
|
254
|
+
} else {
|
255
|
+
logger.log(
|
256
|
+
`[playlist-loader]: ignore ${context.url} in favor of ${loaderContext.url}`,
|
257
|
+
);
|
258
|
+
}
|
251
259
|
return;
|
252
260
|
}
|
253
|
-
|
261
|
+
logger.log(
|
254
262
|
`[playlist-loader]: aborting previous loader for type: ${context.type}`,
|
255
263
|
);
|
256
264
|
loader.abort();
|