hls.js 1.5.2-0.canary.9924 → 1.5.2
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-demo.js +0 -5
- package/dist/hls-demo.js.map +1 -1
- package/dist/hls.js +686 -762
- package/dist/hls.js.d.ts +47 -49
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +471 -563
- 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 +329 -409
- 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 +500 -559
- 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 +9 -9
- package/src/config.ts +2 -3
- package/src/controller/abr-controller.ts +22 -23
- package/src/controller/audio-stream-controller.ts +14 -11
- package/src/controller/audio-track-controller.ts +1 -1
- package/src/controller/base-playlist-controller.ts +7 -7
- package/src/controller/base-stream-controller.ts +29 -42
- package/src/controller/buffer-controller.ts +11 -10
- package/src/controller/cap-level-controller.ts +2 -1
- package/src/controller/content-steering-controller.ts +6 -8
- package/src/controller/eme-controller.ts +22 -9
- package/src/controller/error-controller.ts +8 -6
- package/src/controller/fps-controller.ts +3 -2
- package/src/controller/gap-controller.ts +10 -16
- package/src/controller/latency-controller.ts +11 -9
- package/src/controller/level-controller.ts +19 -8
- package/src/controller/stream-controller.ts +29 -20
- package/src/controller/subtitle-stream-controller.ts +14 -13
- package/src/controller/subtitle-track-controller.ts +3 -5
- package/src/controller/timeline-controller.ts +30 -23
- package/src/crypt/aes-crypto.ts +2 -21
- package/src/crypt/decrypter.ts +18 -32
- package/src/crypt/fast-aes-key.ts +5 -24
- package/src/demux/audio/adts.ts +4 -9
- package/src/demux/sample-aes.ts +0 -2
- package/src/demux/transmuxer-interface.ts +12 -4
- package/src/demux/transmuxer-worker.ts +4 -4
- package/src/demux/transmuxer.ts +3 -16
- package/src/demux/tsdemuxer.ts +17 -12
- package/src/hls.ts +20 -32
- package/src/loader/fragment-loader.ts +2 -9
- package/src/loader/key-loader.ts +0 -2
- package/src/loader/level-key.ts +9 -10
- package/src/remux/mp4-remuxer.ts +3 -4
- package/src/task-loop.ts +2 -5
- package/src/types/demuxer.ts +0 -1
- package/src/utils/codecs.ts +4 -33
- package/src/utils/logger.ts +24 -53
- package/src/crypt/decrypter-aes-mode.ts +0 -4
- package/src/utils/encryption-methods-util.ts +0 -21
package/package.json
CHANGED
@@ -67,10 +67,10 @@
|
|
67
67
|
"@babel/plugin-proposal-object-rest-spread": "7.20.7",
|
68
68
|
"@babel/plugin-proposal-optional-chaining": "7.21.0",
|
69
69
|
"@babel/plugin-transform-object-assign": "7.23.3",
|
70
|
-
"@babel/preset-env": "7.23.
|
70
|
+
"@babel/preset-env": "7.23.7",
|
71
71
|
"@babel/preset-typescript": "7.23.3",
|
72
72
|
"@babel/register": "7.23.7",
|
73
|
-
"@microsoft/api-documenter": "7.23.
|
73
|
+
"@microsoft/api-documenter": "7.23.16",
|
74
74
|
"@microsoft/api-extractor": "7.39.1",
|
75
75
|
"@rollup/plugin-alias": "5.1.0",
|
76
76
|
"@rollup/plugin-babel": "6.0.4",
|
@@ -78,17 +78,17 @@
|
|
78
78
|
"@rollup/plugin-node-resolve": "15.2.3",
|
79
79
|
"@rollup/plugin-replace": "5.0.5",
|
80
80
|
"@rollup/plugin-terser": "0.4.4",
|
81
|
-
"@rollup/plugin-typescript": "11.1.
|
81
|
+
"@rollup/plugin-typescript": "11.1.5",
|
82
82
|
"@svta/common-media-library": "0.6.1",
|
83
83
|
"@types/chai": "4.3.11",
|
84
84
|
"@types/chart.js": "2.9.41",
|
85
85
|
"@types/mocha": "10.0.6",
|
86
86
|
"@types/sinon-chai": "3.2.12",
|
87
|
-
"@typescript-eslint/eslint-plugin": "6.
|
88
|
-
"@typescript-eslint/parser": "6.
|
87
|
+
"@typescript-eslint/eslint-plugin": "6.17.0",
|
88
|
+
"@typescript-eslint/parser": "6.17.0",
|
89
89
|
"babel-loader": "9.1.3",
|
90
90
|
"babel-plugin-transform-remove-console": "6.9.4",
|
91
|
-
"chai": "4.
|
91
|
+
"chai": "4.3.10",
|
92
92
|
"chart.js": "2.9.4",
|
93
93
|
"chromedriver": "120.0.1",
|
94
94
|
"doctoc": "2.2.1",
|
@@ -119,7 +119,7 @@
|
|
119
119
|
"npm-run-all": "4.1.5",
|
120
120
|
"prettier": "3.1.1",
|
121
121
|
"promise-polyfill": "8.3.0",
|
122
|
-
"rollup": "4.9.
|
122
|
+
"rollup": "4.9.4",
|
123
123
|
"rollup-plugin-istanbul": "5.0.0",
|
124
124
|
"sauce-connect-launcher": "1.3.2",
|
125
125
|
"selenium-webdriver": "4.16.0",
|
@@ -128,7 +128,7 @@
|
|
128
128
|
"sinon-chai": "3.7.0",
|
129
129
|
"typescript": "5.3.3",
|
130
130
|
"url-toolkit": "2.2.5",
|
131
|
-
"wrangler": "3.
|
131
|
+
"wrangler": "3.22.4"
|
132
132
|
},
|
133
|
-
"version": "1.5.2
|
133
|
+
"version": "1.5.2"
|
134
134
|
}
|
package/src/config.ts
CHANGED
@@ -17,10 +17,10 @@ import XhrLoader from './utils/xhr-loader';
|
|
17
17
|
import FetchLoader, { fetchSupported } from './utils/fetch-loader';
|
18
18
|
import Cues from './utils/cues';
|
19
19
|
import { requestMediaKeySystemAccess } from './utils/mediakeys-helper';
|
20
|
+
import { ILogger, logger } from './utils/logger';
|
20
21
|
|
21
22
|
import type Hls from './hls';
|
22
23
|
import type { CuesInterface } from './utils/cues';
|
23
|
-
import type { ILogger } from './utils/logger';
|
24
24
|
import type { MediaKeyFunc, KeySystems } from './utils/mediakeys-helper';
|
25
25
|
import type {
|
26
26
|
FragmentLoaderContext,
|
@@ -558,7 +558,6 @@ function timelineConfig(): TimelineControllerConfig {
|
|
558
558
|
export function mergeConfig(
|
559
559
|
defaultConfig: HlsConfig,
|
560
560
|
userConfig: Partial<HlsConfig>,
|
561
|
-
logger: ILogger,
|
562
561
|
): HlsConfig {
|
563
562
|
if (
|
564
563
|
(userConfig.liveSyncDurationCount ||
|
@@ -665,7 +664,7 @@ function deepCpy(obj: any): any {
|
|
665
664
|
/**
|
666
665
|
* @ignore
|
667
666
|
*/
|
668
|
-
export function enableStreamingMode(config
|
667
|
+
export function enableStreamingMode(config) {
|
669
668
|
const currentLoader = config.loader;
|
670
669
|
if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
|
671
670
|
// If a developer has configured their own loader, respect that choice
|
@@ -2,7 +2,7 @@ import EwmaBandWidthEstimator from '../utils/ewma-bandwidth-estimator';
|
|
2
2
|
import { Events } from '../events';
|
3
3
|
import { ErrorDetails } from '../errors';
|
4
4
|
import { PlaylistLevelType } from '../types/loader';
|
5
|
-
import {
|
5
|
+
import { logger } from '../utils/logger';
|
6
6
|
import {
|
7
7
|
SUPPORTED_INFO_DEFAULT,
|
8
8
|
getMediaDecodingInfoPromise,
|
@@ -31,7 +31,7 @@ import type {
|
|
31
31
|
} from '../types/events';
|
32
32
|
import type { AbrComponentAPI } from '../types/component-api';
|
33
33
|
|
34
|
-
class AbrController
|
34
|
+
class AbrController implements AbrComponentAPI {
|
35
35
|
protected hls: Hls;
|
36
36
|
private lastLevelLoadSec: number = 0;
|
37
37
|
private lastLoadedFragLevel: number = -1;
|
@@ -48,7 +48,6 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
48
48
|
public bwEstimator: EwmaBandWidthEstimator;
|
49
49
|
|
50
50
|
constructor(hls: Hls) {
|
51
|
-
super('abr', hls.logger);
|
52
51
|
this.hls = hls;
|
53
52
|
this.bwEstimator = this.initEstimator();
|
54
53
|
this.registerListeners();
|
@@ -56,7 +55,7 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
56
55
|
|
57
56
|
public resetEstimator(abrEwmaDefaultEstimate?: number) {
|
58
57
|
if (abrEwmaDefaultEstimate) {
|
59
|
-
|
58
|
+
logger.log(`setting initial bwe to ${abrEwmaDefaultEstimate}`);
|
60
59
|
this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
|
61
60
|
}
|
62
61
|
this.firstSelection = -1;
|
@@ -287,7 +286,7 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
287
286
|
const level = levels[frag.level];
|
288
287
|
const expectedLen =
|
289
288
|
stats.total ||
|
290
|
-
Math.max(stats.loaded, Math.round((duration * level.
|
289
|
+
Math.max(stats.loaded, Math.round((duration * level.averageBitrate) / 8));
|
291
290
|
let timeStreaming = loadedFirstByte ? timeLoading - ttfb : timeLoading;
|
292
291
|
if (timeStreaming < 1 && loadedFirstByte) {
|
293
292
|
timeStreaming = Math.min(timeLoading, (stats.loaded * 8) / bwEstimate);
|
@@ -347,7 +346,7 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
347
346
|
// If there has been no loading progress, sample TTFB
|
348
347
|
this.bwEstimator.sampleTTFB(timeLoading);
|
349
348
|
}
|
350
|
-
const nextLoadLevelBitrate = levels[nextLoadLevel].
|
349
|
+
const nextLoadLevelBitrate = levels[nextLoadLevel].maxBitrate;
|
351
350
|
if (
|
352
351
|
this.getBwEstimate() * this.hls.config.abrBandWidthUpFactor >
|
353
352
|
nextLoadLevelBitrate
|
@@ -356,7 +355,7 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
356
355
|
}
|
357
356
|
|
358
357
|
this.clearTimer();
|
359
|
-
|
358
|
+
logger.warn(`[abr] Fragment ${frag.sn}${
|
360
359
|
part ? ' part ' + part.index : ''
|
361
360
|
} of level ${frag.level} is loading too slowly;
|
362
361
|
Time to underbuffer: ${bufferStarvationDelay.toFixed(3)} s
|
@@ -480,8 +479,8 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
480
479
|
}
|
481
480
|
const firstLevel = this.hls.firstLevel;
|
482
481
|
const clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
|
483
|
-
|
484
|
-
`Could not find best starting auto level. Defaulting to first in playlist ${firstLevel} clamped to ${clamped}`,
|
482
|
+
logger.warn(
|
483
|
+
`[abr] Could not find best starting auto level. Defaulting to first in playlist ${firstLevel} clamped to ${clamped}`,
|
485
484
|
);
|
486
485
|
return clamped;
|
487
486
|
}
|
@@ -592,8 +591,8 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
592
591
|
? Math.min(currentFragDuration, config.maxLoadingDelay)
|
593
592
|
: config.maxLoadingDelay;
|
594
593
|
maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
|
595
|
-
|
596
|
-
`bitrate test took ${Math.round(
|
594
|
+
logger.info(
|
595
|
+
`[abr] bitrate test took ${Math.round(
|
597
596
|
1000 * bitrateTestDelay,
|
598
597
|
)}ms, set first fragment max fetchDuration to ${Math.round(
|
599
598
|
1000 * maxStarvationDelay,
|
@@ -612,8 +611,8 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
612
611
|
bwFactor,
|
613
612
|
bwUpFactor,
|
614
613
|
);
|
615
|
-
|
616
|
-
|
614
|
+
logger.info(
|
615
|
+
`[abr] ${
|
617
616
|
bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty'
|
618
617
|
}, optimal quality level ${bestLevel}`,
|
619
618
|
);
|
@@ -692,7 +691,7 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
692
691
|
: videoRanges[0];
|
693
692
|
currentFrameRate = minFramerate;
|
694
693
|
currentBw = Math.max(currentBw, minBitrate);
|
695
|
-
|
694
|
+
logger.log(`[abr] picked start tier ${JSON.stringify(startTier)}`);
|
696
695
|
} else {
|
697
696
|
currentCodecSet = level?.codecSet;
|
698
697
|
currentVideoRange = level?.videoRange;
|
@@ -742,19 +741,19 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
742
741
|
const levels = this.hls.levels;
|
743
742
|
const index = levels.indexOf(levelInfo);
|
744
743
|
if (decodingInfo.error) {
|
745
|
-
|
746
|
-
`MediaCapabilities decodingInfo error: "${
|
744
|
+
logger.warn(
|
745
|
+
`[abr] MediaCapabilities decodingInfo error: "${
|
747
746
|
decodingInfo.error
|
748
747
|
}" for level ${index} ${JSON.stringify(decodingInfo)}`,
|
749
748
|
);
|
750
749
|
} else if (!decodingInfo.supported) {
|
751
|
-
|
752
|
-
`Unsupported MediaCapabilities decodingInfo result for level ${index} ${JSON.stringify(
|
750
|
+
logger.warn(
|
751
|
+
`[abr] Unsupported MediaCapabilities decodingInfo result for level ${index} ${JSON.stringify(
|
753
752
|
decodingInfo,
|
754
753
|
)}`,
|
755
754
|
);
|
756
755
|
if (index > -1 && levels.length > 1) {
|
757
|
-
|
756
|
+
logger.log(`[abr] Removing unsupported level ${index}`);
|
758
757
|
this.hls.removeLevel(index);
|
759
758
|
}
|
760
759
|
}
|
@@ -832,8 +831,8 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
832
831
|
(forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)
|
833
832
|
) {
|
834
833
|
if (levelsSkipped.length) {
|
835
|
-
|
836
|
-
`Skipped level(s) ${levelsSkipped.join(
|
834
|
+
logger.trace(
|
835
|
+
`[abr] Skipped level(s) ${levelsSkipped.join(
|
837
836
|
',',
|
838
837
|
)} of ${maxAutoLevel} max with CODECS and VIDEO-RANGE:"${
|
839
838
|
levels[levelsSkipped[0]].codecs
|
@@ -842,8 +841,8 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
842
841
|
}" ${currentVideoRange}`,
|
843
842
|
);
|
844
843
|
}
|
845
|
-
|
846
|
-
`switch candidate:${selectionBaseLevel}->${i} adjustedbw(${Math.round(
|
844
|
+
logger.info(
|
845
|
+
`[abr] switch candidate:${selectionBaseLevel}->${i} adjustedbw(${Math.round(
|
847
846
|
adjustedbw,
|
848
847
|
)})-bitrate=${Math.round(
|
849
848
|
adjustedbw - bitrate,
|
@@ -71,27 +71,30 @@ class AudioStreamController
|
|
71
71
|
hls,
|
72
72
|
fragmentTracker,
|
73
73
|
keyLoader,
|
74
|
-
'audio-stream-controller',
|
74
|
+
'[audio-stream-controller]',
|
75
75
|
PlaylistLevelType.AUDIO,
|
76
76
|
);
|
77
|
-
this.
|
77
|
+
this._registerListeners();
|
78
78
|
}
|
79
79
|
|
80
80
|
protected onHandlerDestroying() {
|
81
|
-
this.
|
81
|
+
this._unregisterListeners();
|
82
82
|
super.onHandlerDestroying();
|
83
83
|
this.mainDetails = null;
|
84
84
|
this.bufferedTrack = null;
|
85
85
|
this.switchingTrack = null;
|
86
86
|
}
|
87
87
|
|
88
|
-
|
89
|
-
super.registerListeners();
|
88
|
+
private _registerListeners() {
|
90
89
|
const { hls } = this;
|
90
|
+
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
91
|
+
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
92
|
+
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
91
93
|
hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
92
94
|
hls.on(Events.AUDIO_TRACKS_UPDATED, this.onAudioTracksUpdated, this);
|
93
95
|
hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
94
96
|
hls.on(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this);
|
97
|
+
hls.on(Events.ERROR, this.onError, this);
|
95
98
|
hls.on(Events.BUFFER_RESET, this.onBufferReset, this);
|
96
99
|
hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
97
100
|
hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
|
@@ -100,16 +103,16 @@ class AudioStreamController
|
|
100
103
|
hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
101
104
|
}
|
102
105
|
|
103
|
-
|
106
|
+
private _unregisterListeners() {
|
104
107
|
const { hls } = this;
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
super.unregisterListeners();
|
108
|
+
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
109
|
+
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
110
|
+
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
109
111
|
hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
110
112
|
hls.off(Events.AUDIO_TRACKS_UPDATED, this.onAudioTracksUpdated, this);
|
111
113
|
hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
112
114
|
hls.off(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this);
|
115
|
+
hls.off(Events.ERROR, this.onError, this);
|
113
116
|
hls.off(Events.BUFFER_RESET, this.onBufferReset, this);
|
114
117
|
hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
115
118
|
hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
|
@@ -710,7 +713,7 @@ class AudioStreamController
|
|
710
713
|
this.fragBufferedComplete(frag, part);
|
711
714
|
}
|
712
715
|
|
713
|
-
|
716
|
+
private onError(event: Events.ERROR, data: ErrorData) {
|
714
717
|
if (data.fatal) {
|
715
718
|
this.state = State.ERROR;
|
716
719
|
return;
|
@@ -5,7 +5,7 @@ import { computeReloadInterval, mergeDetails } from '../utils/level-helper';
|
|
5
5
|
import { ErrorData } from '../types/events';
|
6
6
|
import { getRetryDelay, isTimeoutError } from '../utils/error-helper';
|
7
7
|
import { NetworkErrorAction } from './error-controller';
|
8
|
-
import {
|
8
|
+
import { logger } from '../utils/logger';
|
9
9
|
import type { LevelDetails } from '../loader/level-details';
|
10
10
|
import type { MediaPlaylist } from '../types/media-playlist';
|
11
11
|
import type {
|
@@ -14,17 +14,17 @@ import type {
|
|
14
14
|
TrackLoadedData,
|
15
15
|
} from '../types/events';
|
16
16
|
|
17
|
-
export default class BasePlaylistController
|
18
|
-
extends Logger
|
19
|
-
implements NetworkComponentAPI
|
20
|
-
{
|
17
|
+
export default class BasePlaylistController implements NetworkComponentAPI {
|
21
18
|
protected hls: Hls;
|
22
19
|
protected timer: number = -1;
|
23
20
|
protected requestScheduled: number = -1;
|
24
21
|
protected canLoad: boolean = false;
|
22
|
+
protected log: (msg: any) => void;
|
23
|
+
protected warn: (msg: any) => void;
|
25
24
|
|
26
25
|
constructor(hls: Hls, logPrefix: string) {
|
27
|
-
|
26
|
+
this.log = logger.log.bind(logger, `${logPrefix}:`);
|
27
|
+
this.warn = logger.warn.bind(logger, `${logPrefix}:`);
|
28
28
|
this.hls = hls;
|
29
29
|
}
|
30
30
|
|
@@ -65,7 +65,7 @@ export default class BasePlaylistController
|
|
65
65
|
try {
|
66
66
|
uri = new self.URL(attr.URI, previous.url).href;
|
67
67
|
} catch (error) {
|
68
|
-
|
68
|
+
logger.warn(
|
69
69
|
`Could not construct new URL for Rendition Report: ${error}`,
|
70
70
|
);
|
71
71
|
uri = attr.URI || '';
|
@@ -1,15 +1,12 @@
|
|
1
1
|
import TaskLoop from '../task-loop';
|
2
2
|
import { FragmentState } from './fragment-tracker';
|
3
3
|
import { Bufferable, BufferHelper, BufferInfo } from '../utils/buffer-helper';
|
4
|
+
import { logger } from '../utils/logger';
|
4
5
|
import { Events } from '../events';
|
5
6
|
import { ErrorDetails, ErrorTypes } from '../errors';
|
6
7
|
import { ChunkMetadata } from '../types/transmuxer';
|
7
8
|
import { appendUint8Array } from '../utils/mp4-tools';
|
8
9
|
import { alignStream } from '../utils/discontinuities';
|
9
|
-
import {
|
10
|
-
isFullSegmentEncryption,
|
11
|
-
getAesModeFromFullSegmentMethod,
|
12
|
-
} from '../utils/encryption-methods-util';
|
13
10
|
import {
|
14
11
|
findFragmentByPDT,
|
15
12
|
findFragmentByPTS,
|
@@ -100,6 +97,12 @@ export default class BaseStreamController
|
|
100
97
|
protected startFragRequested: boolean = false;
|
101
98
|
protected decrypter: Decrypter;
|
102
99
|
protected initPTS: RationalTimestamp[] = [];
|
100
|
+
protected onvseeking: EventListener | null = null;
|
101
|
+
protected onvended: EventListener | null = null;
|
102
|
+
|
103
|
+
private readonly logPrefix: string = '';
|
104
|
+
protected log: (msg: any) => void;
|
105
|
+
protected warn: (msg: any) => void;
|
103
106
|
|
104
107
|
constructor(
|
105
108
|
hls: Hls,
|
@@ -108,32 +111,18 @@ export default class BaseStreamController
|
|
108
111
|
logPrefix: string,
|
109
112
|
playlistType: PlaylistLevelType,
|
110
113
|
) {
|
111
|
-
super(
|
114
|
+
super();
|
112
115
|
this.playlistType = playlistType;
|
116
|
+
this.logPrefix = logPrefix;
|
117
|
+
this.log = logger.log.bind(logger, `${logPrefix}:`);
|
118
|
+
this.warn = logger.warn.bind(logger, `${logPrefix}:`);
|
113
119
|
this.hls = hls;
|
114
120
|
this.fragmentLoader = new FragmentLoader(hls.config);
|
115
121
|
this.keyLoader = keyLoader;
|
116
122
|
this.fragmentTracker = fragmentTracker;
|
117
123
|
this.config = hls.config;
|
118
124
|
this.decrypter = new Decrypter(hls.config);
|
119
|
-
}
|
120
|
-
|
121
|
-
protected registerListeners() {
|
122
|
-
const { hls } = this;
|
123
|
-
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
124
|
-
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
125
|
-
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
126
125
|
hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
127
|
-
hls.on(Events.ERROR, this.onError, this);
|
128
|
-
}
|
129
|
-
|
130
|
-
protected unregisterListeners() {
|
131
|
-
const { hls } = this;
|
132
|
-
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
133
|
-
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
134
|
-
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
135
|
-
hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
136
|
-
hls.off(Events.ERROR, this.onError, this);
|
137
126
|
}
|
138
127
|
|
139
128
|
protected doTick() {
|
@@ -208,8 +197,10 @@ export default class BaseStreamController
|
|
208
197
|
data: MediaAttachedData,
|
209
198
|
) {
|
210
199
|
const media = (this.media = this.mediaBuffer = data.media);
|
211
|
-
|
212
|
-
|
200
|
+
this.onvseeking = this.onMediaSeeking.bind(this) as EventListener;
|
201
|
+
this.onvended = this.onMediaEnded.bind(this) as EventListener;
|
202
|
+
media.addEventListener('seeking', this.onvseeking);
|
203
|
+
media.addEventListener('ended', this.onvended);
|
213
204
|
const config = this.config;
|
214
205
|
if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
|
215
206
|
this.startLoad(config.startPosition);
|
@@ -224,9 +215,10 @@ export default class BaseStreamController
|
|
224
215
|
}
|
225
216
|
|
226
217
|
// remove video listeners
|
227
|
-
if (media) {
|
228
|
-
media.removeEventListener('seeking', this.
|
229
|
-
media.removeEventListener('ended', this.
|
218
|
+
if (media && this.onvseeking && this.onvended) {
|
219
|
+
media.removeEventListener('seeking', this.onvseeking);
|
220
|
+
media.removeEventListener('ended', this.onvended);
|
221
|
+
this.onvseeking = this.onvended = null;
|
230
222
|
}
|
231
223
|
if (this.keyLoader) {
|
232
224
|
this.keyLoader.detach();
|
@@ -237,11 +229,7 @@ export default class BaseStreamController
|
|
237
229
|
this.stopLoad();
|
238
230
|
}
|
239
231
|
|
240
|
-
protected
|
241
|
-
|
242
|
-
protected onError(event: Events.ERROR, data: ErrorData) {}
|
243
|
-
|
244
|
-
protected onMediaSeeking = () => {
|
232
|
+
protected onMediaSeeking() {
|
245
233
|
const { config, fragCurrent, media, mediaBuffer, state } = this;
|
246
234
|
const currentTime: number = media ? media.currentTime : 0;
|
247
235
|
const bufferInfo = BufferHelper.bufferInfo(
|
@@ -304,12 +292,12 @@ export default class BaseStreamController
|
|
304
292
|
|
305
293
|
// Async tick to speed up processing
|
306
294
|
this.tickImmediate();
|
307
|
-
}
|
295
|
+
}
|
308
296
|
|
309
|
-
protected onMediaEnded
|
297
|
+
protected onMediaEnded() {
|
310
298
|
// reset startPosition and lastCurrentTime to restart playback @ stream beginning
|
311
299
|
this.startPosition = this.lastCurrentTime = 0;
|
312
|
-
}
|
300
|
+
}
|
313
301
|
|
314
302
|
protected onManifestLoaded(
|
315
303
|
event: Events.MANIFEST_LOADED,
|
@@ -324,7 +312,7 @@ export default class BaseStreamController
|
|
324
312
|
this.stopLoad();
|
325
313
|
super.onHandlerDestroying();
|
326
314
|
// @ts-ignore
|
327
|
-
this.hls =
|
315
|
+
this.hls = null;
|
328
316
|
}
|
329
317
|
|
330
318
|
protected onHandlerDestroyed() {
|
@@ -498,7 +486,7 @@ export default class BaseStreamController
|
|
498
486
|
payload.byteLength > 0 &&
|
499
487
|
decryptData?.key &&
|
500
488
|
decryptData.iv &&
|
501
|
-
|
489
|
+
decryptData.method === 'AES-128'
|
502
490
|
) {
|
503
491
|
const startTime = self.performance.now();
|
504
492
|
// decrypt init segment data
|
@@ -507,7 +495,6 @@ export default class BaseStreamController
|
|
507
495
|
new Uint8Array(payload),
|
508
496
|
decryptData.key.buffer,
|
509
497
|
decryptData.iv.buffer,
|
510
|
-
getAesModeFromFullSegmentMethod(decryptData.method),
|
511
498
|
)
|
512
499
|
.catch((err) => {
|
513
500
|
hls.trigger(Events.ERROR, {
|
@@ -662,7 +649,7 @@ export default class BaseStreamController
|
|
662
649
|
if (frag.encrypted && !frag.decryptdata?.key) {
|
663
650
|
this.log(
|
664
651
|
`Loading key for ${frag.sn} of [${details.startSN}-${details.endSN}], ${
|
665
|
-
this.
|
652
|
+
this.logPrefix === '[stream-controller]' ? 'level' : 'track'
|
666
653
|
} ${frag.level}`,
|
667
654
|
);
|
668
655
|
this.state = State.KEY_LOADING;
|
@@ -702,7 +689,7 @@ export default class BaseStreamController
|
|
702
689
|
} of playlist [${details.startSN}-${
|
703
690
|
details.endSN
|
704
691
|
}] parts [0-${partIndex}-${partList.length - 1}] ${
|
705
|
-
this.
|
692
|
+
this.logPrefix === '[stream-controller]' ? 'level' : 'track'
|
706
693
|
}: ${frag.level}, target: ${parseFloat(
|
707
694
|
targetBufferTime.toFixed(3),
|
708
695
|
)}`,
|
@@ -761,7 +748,7 @@ export default class BaseStreamController
|
|
761
748
|
this.log(
|
762
749
|
`Loading fragment ${frag.sn} cc: ${frag.cc} ${
|
763
750
|
details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : ''
|
764
|
-
}${this.
|
751
|
+
}${this.logPrefix === '[stream-controller]' ? 'level' : 'track'}: ${
|
765
752
|
frag.level
|
766
753
|
}, target: ${parseFloat(targetBufferTime.toFixed(3))}`,
|
767
754
|
);
|
@@ -1563,7 +1550,7 @@ export default class BaseStreamController
|
|
1563
1550
|
errorAction.resolved = true;
|
1564
1551
|
}
|
1565
1552
|
} else {
|
1566
|
-
|
1553
|
+
logger.warn(
|
1567
1554
|
`${data.details} reached or exceeded max retry (${retryCount})`,
|
1568
1555
|
);
|
1569
1556
|
return;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Events } from '../events';
|
2
|
-
import {
|
2
|
+
import { logger } from '../utils/logger';
|
3
3
|
import { ErrorDetails, ErrorTypes } from '../errors';
|
4
4
|
import { BufferHelper } from '../utils/buffer-helper';
|
5
5
|
import {
|
@@ -42,7 +42,7 @@ interface BufferedChangeEvent extends Event {
|
|
42
42
|
readonly removedRanges?: TimeRanges;
|
43
43
|
}
|
44
44
|
|
45
|
-
export default class BufferController
|
45
|
+
export default class BufferController implements ComponentAPI {
|
46
46
|
// The level details used to determine duration, target-duration and live
|
47
47
|
private details: LevelDetails | null = null;
|
48
48
|
// cache the self generated object url to detect hijack of video tag
|
@@ -82,10 +82,17 @@ export default class BufferController extends Logger implements ComponentAPI {
|
|
82
82
|
public pendingTracks: TrackSet = {};
|
83
83
|
public sourceBuffer!: SourceBuffers;
|
84
84
|
|
85
|
+
protected log: (msg: any) => void;
|
86
|
+
protected warn: (msg: any, obj?: any) => void;
|
87
|
+
protected error: (msg: any, obj?: any) => void;
|
88
|
+
|
85
89
|
constructor(hls: Hls) {
|
86
|
-
super('buffer-controller', hls.logger);
|
87
90
|
this.hls = hls;
|
91
|
+
const logPrefix = '[buffer-controller]';
|
88
92
|
this.appendSource = hls.config.preferManagedMediaSource;
|
93
|
+
this.log = logger.log.bind(logger, logPrefix);
|
94
|
+
this.warn = logger.warn.bind(logger, logPrefix);
|
95
|
+
this.error = logger.error.bind(logger, logPrefix);
|
89
96
|
this._initSourceBuffer();
|
90
97
|
this.registerListeners();
|
91
98
|
}
|
@@ -103,12 +110,6 @@ export default class BufferController extends Logger implements ComponentAPI {
|
|
103
110
|
this.lastMpegAudioChunk = null;
|
104
111
|
// @ts-ignore
|
105
112
|
this.hls = null;
|
106
|
-
// @ts-ignore
|
107
|
-
this._onMediaSourceOpen = this._onMediaSourceClose = null;
|
108
|
-
// @ts-ignore
|
109
|
-
this._onMediaSourceEnded = null;
|
110
|
-
// @ts-ignore
|
111
|
-
this._onStartStreaming = this._onEndStreaming = null;
|
112
113
|
}
|
113
114
|
|
114
115
|
protected registerListeners() {
|
@@ -1003,7 +1004,7 @@ export default class BufferController extends Logger implements ComponentAPI {
|
|
1003
1004
|
private _onMediaEmptied = () => {
|
1004
1005
|
const { mediaSrc, _objectUrl } = this;
|
1005
1006
|
if (mediaSrc !== _objectUrl) {
|
1006
|
-
|
1007
|
+
logger.error(
|
1007
1008
|
`Media element src was set while attaching MediaSource (${_objectUrl} > ${mediaSrc})`,
|
1008
1009
|
);
|
1009
1010
|
}
|
@@ -12,6 +12,7 @@ import type {
|
|
12
12
|
LevelsUpdatedData,
|
13
13
|
} from '../types/events';
|
14
14
|
import StreamController from './stream-controller';
|
15
|
+
import { logger } from '../utils/logger';
|
15
16
|
import type { ComponentAPI } from '../types/component-api';
|
16
17
|
import type Hls from '../hls';
|
17
18
|
|
@@ -151,7 +152,7 @@ class CapLevelController implements ComponentAPI {
|
|
151
152
|
const hls = this.hls;
|
152
153
|
const maxLevel = this.getMaxLevel(levels.length - 1);
|
153
154
|
if (maxLevel !== this.autoLevelCapping) {
|
154
|
-
|
155
|
+
logger.log(
|
155
156
|
`Setting autoLevelCapping to ${maxLevel}: ${levels[maxLevel].height}p@${levels[maxLevel].bitrate} for media ${this.mediaWidth}x${this.mediaHeight}`,
|
156
157
|
);
|
157
158
|
}
|
@@ -3,7 +3,7 @@ import { Level } from '../types/level';
|
|
3
3
|
import { reassignFragmentLevelIndexes } from '../utils/level-helper';
|
4
4
|
import { AttrList } from '../utils/attr-list';
|
5
5
|
import { ErrorActionFlags, NetworkErrorAction } from './error-controller';
|
6
|
-
import {
|
6
|
+
import { logger } from '../utils/logger';
|
7
7
|
import {
|
8
8
|
PlaylistContextType,
|
9
9
|
type Loader,
|
@@ -48,11 +48,9 @@ export type UriReplacement = {
|
|
48
48
|
|
49
49
|
const PATHWAY_PENALTY_DURATION_MS = 300000;
|
50
50
|
|
51
|
-
export default class ContentSteeringController
|
52
|
-
extends Logger
|
53
|
-
implements NetworkComponentAPI
|
54
|
-
{
|
51
|
+
export default class ContentSteeringController implements NetworkComponentAPI {
|
55
52
|
private readonly hls: Hls;
|
53
|
+
private log: (msg: any) => void;
|
56
54
|
private loader: Loader<LoaderContext> | null = null;
|
57
55
|
private uri: string | null = null;
|
58
56
|
private pathwayId: string = '.';
|
@@ -68,8 +66,8 @@ export default class ContentSteeringController
|
|
68
66
|
private penalizedPathways: { [pathwayId: string]: number } = {};
|
69
67
|
|
70
68
|
constructor(hls: Hls) {
|
71
|
-
super('content-steering', hls.logger);
|
72
69
|
this.hls = hls;
|
70
|
+
this.log = logger.log.bind(logger, `[content-steering]:`);
|
73
71
|
this.registerListeners();
|
74
72
|
}
|
75
73
|
|
@@ -205,7 +203,7 @@ export default class ContentSteeringController
|
|
205
203
|
errorAction.resolved = this.pathwayId !== errorPathway;
|
206
204
|
}
|
207
205
|
if (!errorAction.resolved) {
|
208
|
-
|
206
|
+
logger.warn(
|
209
207
|
`Could not resolve ${data.details} ("${
|
210
208
|
data.error.message
|
211
209
|
}") with content-steering for Pathway: ${errorPathway} levels: ${
|
@@ -444,7 +442,7 @@ export default class ContentSteeringController
|
|
444
442
|
) => {
|
445
443
|
this.log(`Loaded steering manifest: "${url}"`);
|
446
444
|
const steeringData = response.data as SteeringManifest;
|
447
|
-
if (steeringData
|
445
|
+
if (steeringData.VERSION !== 1) {
|
448
446
|
this.log(`Steering VERSION ${steeringData.VERSION} not supported!`);
|
449
447
|
return;
|
450
448
|
}
|