hls.js 1.6.0-beta.1.0.canary.10765 → 1.6.0-beta.1.0.canary.10767
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 +1 -0
- package/dist/hls.d.ts +1 -0
- package/dist/hls.js +45 -24
- package/dist/hls.js.d.ts +1 -0
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +38 -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 +38 -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 +45 -24
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/dist/hls.worker.js.map +1 -1
- package/package.json +1 -1
- package/src/controller/audio-stream-controller.ts +7 -7
- package/src/controller/base-stream-controller.ts +35 -20
- package/src/controller/stream-controller.ts +5 -5
- package/src/controller/subtitle-stream-controller.ts +9 -5
- package/src/hls.ts +4 -0
- package/src/loader/fragment.ts +5 -1
package/package.json
CHANGED
@@ -5,7 +5,7 @@ import ChunkCache from '../demux/chunk-cache';
|
|
5
5
|
import TransmuxerInterface from '../demux/transmuxer-interface';
|
6
6
|
import { ErrorDetails } from '../errors';
|
7
7
|
import { Events } from '../events';
|
8
|
-
import { ElementaryStreamTypes } from '../loader/fragment';
|
8
|
+
import { ElementaryStreamTypes, isMediaFragment } from '../loader/fragment';
|
9
9
|
import { Level } from '../types/level';
|
10
10
|
import { PlaylistContextType, PlaylistLevelType } from '../types/loader';
|
11
11
|
import { ChunkMetadata } from '../types/transmuxer';
|
@@ -409,8 +409,8 @@ class AudioStreamController
|
|
409
409
|
if (
|
410
410
|
this.startFragRequested &&
|
411
411
|
mainFragLoading &&
|
412
|
-
mainFragLoading
|
413
|
-
frag
|
412
|
+
isMediaFragment(mainFragLoading) &&
|
413
|
+
isMediaFragment(frag) &&
|
414
414
|
!frag.endList &&
|
415
415
|
(!trackDetails.live ||
|
416
416
|
(!this.loadingParts && targetBufferTime < this.hls.liveSyncPosition!))
|
@@ -694,7 +694,7 @@ class AudioStreamController
|
|
694
694
|
private onFragLoading(event: Events.FRAG_LOADING, data: FragLoadingData) {
|
695
695
|
if (
|
696
696
|
data.frag.type === PlaylistLevelType.MAIN &&
|
697
|
-
data.frag
|
697
|
+
isMediaFragment(data.frag)
|
698
698
|
) {
|
699
699
|
this.mainFragLoading = data;
|
700
700
|
if (this.state === State.IDLE) {
|
@@ -722,8 +722,8 @@ class AudioStreamController
|
|
722
722
|
);
|
723
723
|
return;
|
724
724
|
}
|
725
|
-
if (frag
|
726
|
-
this.fragPrevious = frag
|
725
|
+
if (isMediaFragment(frag)) {
|
726
|
+
this.fragPrevious = frag;
|
727
727
|
const track = this.switchingTrack;
|
728
728
|
if (track) {
|
729
729
|
this.bufferedTrack = track;
|
@@ -962,7 +962,7 @@ class AudioStreamController
|
|
962
962
|
fragState === FragmentState.NOT_LOADED ||
|
963
963
|
fragState === FragmentState.PARTIAL
|
964
964
|
) {
|
965
|
-
if (frag
|
965
|
+
if (!isMediaFragment(frag)) {
|
966
966
|
this._loadInitSegment(frag, track);
|
967
967
|
} else if (track.details?.live && !this.initPTS[frag.cc]) {
|
968
968
|
this.log(
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { NetworkErrorAction } from './error-controller';
|
1
|
+
import { ErrorActionFlags, NetworkErrorAction } from './error-controller';
|
2
2
|
import {
|
3
3
|
findFragmentByPDT,
|
4
4
|
findFragmentByPTS,
|
@@ -8,6 +8,12 @@ import { FragmentState } from './fragment-tracker';
|
|
8
8
|
import Decrypter from '../crypt/decrypter';
|
9
9
|
import { ErrorDetails, ErrorTypes } from '../errors';
|
10
10
|
import { Events } from '../events';
|
11
|
+
import {
|
12
|
+
type Fragment,
|
13
|
+
isMediaFragment,
|
14
|
+
type MediaFragment,
|
15
|
+
type Part,
|
16
|
+
} from '../loader/fragment';
|
11
17
|
import FragmentLoader from '../loader/fragment-loader';
|
12
18
|
import TaskLoop from '../task-loop';
|
13
19
|
import { PlaylistLevelType } from '../types/loader';
|
@@ -31,7 +37,6 @@ import type { FragmentTracker } from './fragment-tracker';
|
|
31
37
|
import type { HlsConfig } from '../config';
|
32
38
|
import type TransmuxerInterface from '../demux/transmuxer-interface';
|
33
39
|
import type Hls from '../hls';
|
34
|
-
import type { Fragment, MediaFragment, Part } from '../loader/fragment';
|
35
40
|
import type {
|
36
41
|
FragmentLoadProgressCallback,
|
37
42
|
LoadError,
|
@@ -714,7 +719,7 @@ export default class BaseStreamController
|
|
714
719
|
: '(detached)'
|
715
720
|
})`,
|
716
721
|
);
|
717
|
-
if (frag
|
722
|
+
if (isMediaFragment(frag)) {
|
718
723
|
if (frag.type !== PlaylistLevelType.SUBTITLE) {
|
719
724
|
const el = frag.elementaryStreams;
|
720
725
|
if (!Object.keys(el).some((type) => !!el[type])) {
|
@@ -803,7 +808,7 @@ export default class BaseStreamController
|
|
803
808
|
|
804
809
|
const fragPrevious = this.fragPrevious;
|
805
810
|
if (
|
806
|
-
frag
|
811
|
+
isMediaFragment(frag) &&
|
807
812
|
(!fragPrevious || frag.sn !== fragPrevious.sn)
|
808
813
|
) {
|
809
814
|
const shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
|
@@ -817,7 +822,7 @@ export default class BaseStreamController
|
|
817
822
|
}
|
818
823
|
}
|
819
824
|
targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
|
820
|
-
if (this.loadingParts && frag
|
825
|
+
if (this.loadingParts && isMediaFragment(frag)) {
|
821
826
|
const partList = details.partList;
|
822
827
|
if (partList && progressCallback) {
|
823
828
|
if (targetBufferTime > frag.end && details.fragmentHint) {
|
@@ -885,7 +890,7 @@ export default class BaseStreamController
|
|
885
890
|
}
|
886
891
|
}
|
887
892
|
|
888
|
-
if (frag
|
893
|
+
if (isMediaFragment(frag) && this.loadingParts) {
|
889
894
|
this.log(
|
890
895
|
`LL-Part loading OFF after next part miss @${targetBufferTime.toFixed(
|
891
896
|
2,
|
@@ -1661,7 +1666,7 @@ export default class BaseStreamController
|
|
1661
1666
|
}
|
1662
1667
|
|
1663
1668
|
private handleFragLoadAborted(frag: Fragment, part: Part | undefined) {
|
1664
|
-
if (this.transmuxer && frag
|
1669
|
+
if (this.transmuxer && isMediaFragment(frag) && frag.stats.aborted) {
|
1665
1670
|
this.warn(
|
1666
1671
|
`Fragment ${frag.sn}${part ? ' part ' + part.index : ''} of level ${
|
1667
1672
|
frag.level
|
@@ -1708,12 +1713,18 @@ export default class BaseStreamController
|
|
1708
1713
|
}
|
1709
1714
|
// keep retrying until the limit will be reached
|
1710
1715
|
const errorAction = data.errorAction;
|
1711
|
-
const { action, retryCount = 0, retryConfig } = errorAction || {};
|
1712
|
-
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1716
|
+
const { action, flags, retryCount = 0, retryConfig } = errorAction || {};
|
1717
|
+
const couldRetry = !!errorAction && !!retryConfig;
|
1718
|
+
const retry = couldRetry && action === NetworkErrorAction.RetryRequest;
|
1719
|
+
const noAlternate =
|
1720
|
+
couldRetry &&
|
1721
|
+
!errorAction.resolved &&
|
1722
|
+
flags === ErrorActionFlags.MoveAllAlternatesMatchingHost;
|
1723
|
+
if (!retry && noAlternate && isMediaFragment(frag) && !frag.endList) {
|
1724
|
+
this.resetFragmentErrors(filterType);
|
1725
|
+
this.treatAsGap(frag);
|
1726
|
+
errorAction.resolved = true;
|
1727
|
+
} else if ((retry || noAlternate) && retryCount < retryConfig.maxNumRetry) {
|
1717
1728
|
this.resetStartWhenNotLoaded(this.levelLastLoaded);
|
1718
1729
|
const delay = getRetryDelay(retryConfig, retryCount);
|
1719
1730
|
this.warn(
|
@@ -1742,9 +1753,7 @@ export default class BaseStreamController
|
|
1742
1753
|
);
|
1743
1754
|
return;
|
1744
1755
|
}
|
1745
|
-
} else if (
|
1746
|
-
errorAction?.action === NetworkErrorAction.SendAlternateToPenaltyBox
|
1747
|
-
) {
|
1756
|
+
} else if (action === NetworkErrorAction.SendAlternateToPenaltyBox) {
|
1748
1757
|
this.state = State.WAITING_LEVEL;
|
1749
1758
|
} else {
|
1750
1759
|
this.state = State.ERROR;
|
@@ -1925,10 +1934,7 @@ export default class BaseStreamController
|
|
1925
1934
|
);
|
1926
1935
|
if (level.fragmentError === 0) {
|
1927
1936
|
// Mark and track the odd empty segment as a gap to avoid reloading
|
1928
|
-
level
|
1929
|
-
frag.gap = true;
|
1930
|
-
this.fragmentTracker.removeFragment(frag);
|
1931
|
-
this.fragmentTracker.fragBuffered(frag, true);
|
1937
|
+
this.treatAsGap(frag, level);
|
1932
1938
|
}
|
1933
1939
|
this.warn(error.message);
|
1934
1940
|
this.hls.trigger(Events.ERROR, {
|
@@ -1970,6 +1976,15 @@ export default class BaseStreamController
|
|
1970
1976
|
)}]${part && frag.type === 'main' ? 'INDEPENDENT=' + (part.independent ? 'YES' : 'NO') : ''}`;
|
1971
1977
|
}
|
1972
1978
|
|
1979
|
+
private treatAsGap(frag: MediaFragment, level?: Level) {
|
1980
|
+
if (level) {
|
1981
|
+
level.fragmentError++;
|
1982
|
+
}
|
1983
|
+
frag.gap = true;
|
1984
|
+
this.fragmentTracker.removeFragment(frag);
|
1985
|
+
this.fragmentTracker.fragBuffered(frag, true);
|
1986
|
+
}
|
1987
|
+
|
1973
1988
|
protected resetTransmuxer() {
|
1974
1989
|
this.transmuxer?.reset();
|
1975
1990
|
}
|
@@ -6,7 +6,7 @@ import TransmuxerInterface from '../demux/transmuxer-interface';
|
|
6
6
|
import { ErrorDetails } from '../errors';
|
7
7
|
import { Events } from '../events';
|
8
8
|
import { changeTypeSupported } from '../is-supported';
|
9
|
-
import { ElementaryStreamTypes } from '../loader/fragment';
|
9
|
+
import { ElementaryStreamTypes, isMediaFragment } from '../loader/fragment';
|
10
10
|
import { PlaylistContextType, PlaylistLevelType } from '../types/loader';
|
11
11
|
import { ChunkMetadata } from '../types/transmuxer';
|
12
12
|
import { BufferHelper } from '../utils/buffer-helper';
|
@@ -319,7 +319,7 @@ export default class StreamController
|
|
319
319
|
this.couldBacktrack &&
|
320
320
|
!this.fragPrevious &&
|
321
321
|
frag &&
|
322
|
-
frag
|
322
|
+
isMediaFragment(frag) &&
|
323
323
|
this.fragmentTracker.getState(frag) !== FragmentState.OK
|
324
324
|
) {
|
325
325
|
const backtrackSn = (this.backtrackFragment ?? frag).sn as number;
|
@@ -378,7 +378,7 @@ export default class StreamController
|
|
378
378
|
fragState === FragmentState.NOT_LOADED ||
|
379
379
|
fragState === FragmentState.PARTIAL
|
380
380
|
) {
|
381
|
-
if (frag
|
381
|
+
if (!isMediaFragment(frag)) {
|
382
382
|
this._loadInitSegment(frag, level);
|
383
383
|
} else if (this.bitrateTest) {
|
384
384
|
this.log(
|
@@ -963,8 +963,8 @@ export default class StreamController
|
|
963
963
|
this.fragLastKbps = Math.round(
|
964
964
|
(8 * stats.total) / (stats.buffering.end - stats.loading.first),
|
965
965
|
);
|
966
|
-
if (frag
|
967
|
-
this.fragPrevious = frag
|
966
|
+
if (isMediaFragment(frag)) {
|
967
|
+
this.fragPrevious = frag;
|
968
968
|
}
|
969
969
|
this.fragBufferedComplete(frag, part);
|
970
970
|
}
|
@@ -3,6 +3,11 @@ import { findFragmentByPTS } from './fragment-finders';
|
|
3
3
|
import { FragmentState } from './fragment-tracker';
|
4
4
|
import { ErrorDetails, ErrorTypes } from '../errors';
|
5
5
|
import { Events } from '../events';
|
6
|
+
import {
|
7
|
+
type Fragment,
|
8
|
+
isMediaFragment,
|
9
|
+
type MediaFragment,
|
10
|
+
} from '../loader/fragment';
|
6
11
|
import { Level } from '../types/level';
|
7
12
|
import { PlaylistLevelType } from '../types/loader';
|
8
13
|
import { BufferHelper } from '../utils/buffer-helper';
|
@@ -15,7 +20,6 @@ import { addSliding } from '../utils/level-helper';
|
|
15
20
|
import { subtitleOptionsIdentical } from '../utils/media-option-attributes';
|
16
21
|
import type Hls from '../hls';
|
17
22
|
import type { FragmentTracker } from './fragment-tracker';
|
18
|
-
import type { Fragment, MediaFragment } from '../loader/fragment';
|
19
23
|
import type KeyLoader from '../loader/key-loader';
|
20
24
|
import type { LevelDetails } from '../loader/level-details';
|
21
25
|
import type { NetworkComponentAPI } from '../types/component-api';
|
@@ -126,8 +130,8 @@ export class SubtitleStreamController
|
|
126
130
|
data: SubtitleFragProcessed,
|
127
131
|
) {
|
128
132
|
const { frag, success } = data;
|
129
|
-
if (frag
|
130
|
-
this.fragPrevious = frag
|
133
|
+
if (isMediaFragment(frag)) {
|
134
|
+
this.fragPrevious = frag;
|
131
135
|
}
|
132
136
|
this.state = State.IDLE;
|
133
137
|
if (!success) {
|
@@ -466,7 +470,7 @@ export class SubtitleStreamController
|
|
466
470
|
return;
|
467
471
|
}
|
468
472
|
foundFrag = this.mapToInitFragWhenRequired(foundFrag) as Fragment;
|
469
|
-
if (foundFrag
|
473
|
+
if (isMediaFragment(foundFrag)) {
|
470
474
|
// Load earlier fragment in same discontinuity to make up for misaligned playlists and cues that extend beyond end of segment
|
471
475
|
const curSNIdx = foundFrag.sn - trackDetails.startSN;
|
472
476
|
const prevFrag = fragments[curSNIdx - 1];
|
@@ -492,7 +496,7 @@ export class SubtitleStreamController
|
|
492
496
|
level: Level,
|
493
497
|
targetBufferTime: number,
|
494
498
|
) {
|
495
|
-
if (frag
|
499
|
+
if (!isMediaFragment(frag)) {
|
496
500
|
this._loadInitSegment(frag, level);
|
497
501
|
} else {
|
498
502
|
super.loadFragment(frag, level, targetBufferTime);
|
package/src/hls.ts
CHANGED
@@ -432,6 +432,10 @@ export default class Hls implements HlsEventEmitter {
|
|
432
432
|
return;
|
433
433
|
}
|
434
434
|
this.logger.log(`attachMedia`);
|
435
|
+
if (this._media) {
|
436
|
+
this.logger.warn(`media must be detached before attaching`);
|
437
|
+
this.detachMedia();
|
438
|
+
}
|
435
439
|
const attachMediaSource = 'media' in data;
|
436
440
|
const media = attachMediaSource ? data.media : data;
|
437
441
|
const attachingData = attachMediaSource ? data : { media };
|
package/src/loader/fragment.ts
CHANGED
@@ -152,6 +152,10 @@ export type MediaFragmentRef = {
|
|
152
152
|
programDateTime: number | null;
|
153
153
|
};
|
154
154
|
|
155
|
+
export function isMediaFragment(frag: Fragment): frag is MediaFragment {
|
156
|
+
return frag.sn !== 'initSegment';
|
157
|
+
}
|
158
|
+
|
155
159
|
/**
|
156
160
|
* Object representing parsed data from an HLS Segment. Found in {@link hls.js#LevelDetails.fragments}.
|
157
161
|
*/
|
@@ -323,7 +327,7 @@ export class Fragment extends BaseSegment {
|
|
323
327
|
}
|
324
328
|
|
325
329
|
get ref(): MediaFragmentRef | null {
|
326
|
-
if (this
|
330
|
+
if (!isMediaFragment(this)) {
|
327
331
|
return null;
|
328
332
|
}
|
329
333
|
if (!this._ref) {
|