hls.js 1.5.2-0.canary.9934 → 1.5.3
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 +757 -883
- package/dist/hls.js.d.ts +47 -56
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +477 -600
- 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 +335 -446
- 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 +572 -681
- 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 +11 -11
- package/src/config.ts +2 -3
- package/src/controller/abr-controller.ts +22 -22
- 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 -47
- package/src/controller/buffer-controller.ts +11 -10
- package/src/controller/cap-level-controller.ts +2 -1
- package/src/controller/cmcd-controller.ts +3 -25
- 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 +16 -43
- package/src/controller/latency-controller.ts +11 -9
- package/src/controller/level-controller.ts +17 -5
- package/src/controller/stream-controller.ts +31 -24
- 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/events.ts +0 -7
- package/src/hls.ts +20 -33
- 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 +4 -20
- package/src/task-loop.ts +2 -5
- package/src/types/demuxer.ts +0 -1
- package/src/types/events.ts +0 -4
- 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,19 +78,19 @@
|
|
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.
|
82
|
-
"@svta/common-media-library": "0.6.
|
81
|
+
"@rollup/plugin-typescript": "11.1.5",
|
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
|
-
"chromedriver": "120.0.
|
93
|
+
"chromedriver": "120.0.1",
|
94
94
|
"doctoc": "2.2.1",
|
95
95
|
"es-check": "7.1.1",
|
96
96
|
"eslint": "8.56.0",
|
@@ -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.
|
133
|
+
"version": "1.5.3"
|
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;
|
@@ -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
|
}
|
@@ -773,7 +772,8 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
773
772
|
(!upSwitch &&
|
774
773
|
currentFrameRate > 0 &&
|
775
774
|
currentFrameRate < levelInfo.frameRate) ||
|
776
|
-
|
775
|
+
(levelInfo.supportedResult &&
|
776
|
+
!levelInfo.supportedResult.decodingInfoResults?.[0].smooth)
|
777
777
|
) {
|
778
778
|
levelsSkipped.push(i);
|
779
779
|
continue;
|
@@ -832,8 +832,8 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
832
832
|
(forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)
|
833
833
|
) {
|
834
834
|
if (levelsSkipped.length) {
|
835
|
-
|
836
|
-
`Skipped level(s) ${levelsSkipped.join(
|
835
|
+
logger.trace(
|
836
|
+
`[abr] Skipped level(s) ${levelsSkipped.join(
|
837
837
|
',',
|
838
838
|
)} of ${maxAutoLevel} max with CODECS and VIDEO-RANGE:"${
|
839
839
|
levels[levelsSkipped[0]].codecs
|
@@ -842,8 +842,8 @@ class AbrController extends Logger implements AbrComponentAPI {
|
|
842
842
|
}" ${currentVideoRange}`,
|
843
843
|
);
|
844
844
|
}
|
845
|
-
|
846
|
-
`switch candidate:${selectionBaseLevel}->${i} adjustedbw(${Math.round(
|
845
|
+
logger.info(
|
846
|
+
`[abr] switch candidate:${selectionBaseLevel}->${i} adjustedbw(${Math.round(
|
847
847
|
adjustedbw,
|
848
848
|
)})-bitrate=${Math.round(
|
849
849
|
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,17 +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
|
-
|
313
|
-
this.hls.trigger(Events.MEDIA_ENDED, {
|
314
|
-
stalled: false,
|
315
|
-
});
|
316
|
-
}
|
317
|
-
};
|
300
|
+
}
|
318
301
|
|
319
302
|
protected onManifestLoaded(
|
320
303
|
event: Events.MANIFEST_LOADED,
|
@@ -329,7 +312,7 @@ export default class BaseStreamController
|
|
329
312
|
this.stopLoad();
|
330
313
|
super.onHandlerDestroying();
|
331
314
|
// @ts-ignore
|
332
|
-
this.hls =
|
315
|
+
this.hls = null;
|
333
316
|
}
|
334
317
|
|
335
318
|
protected onHandlerDestroyed() {
|
@@ -503,7 +486,7 @@ export default class BaseStreamController
|
|
503
486
|
payload.byteLength > 0 &&
|
504
487
|
decryptData?.key &&
|
505
488
|
decryptData.iv &&
|
506
|
-
|
489
|
+
decryptData.method === 'AES-128'
|
507
490
|
) {
|
508
491
|
const startTime = self.performance.now();
|
509
492
|
// decrypt init segment data
|
@@ -512,7 +495,6 @@ export default class BaseStreamController
|
|
512
495
|
new Uint8Array(payload),
|
513
496
|
decryptData.key.buffer,
|
514
497
|
decryptData.iv.buffer,
|
515
|
-
getAesModeFromFullSegmentMethod(decryptData.method),
|
516
498
|
)
|
517
499
|
.catch((err) => {
|
518
500
|
hls.trigger(Events.ERROR, {
|
@@ -667,7 +649,7 @@ export default class BaseStreamController
|
|
667
649
|
if (frag.encrypted && !frag.decryptdata?.key) {
|
668
650
|
this.log(
|
669
651
|
`Loading key for ${frag.sn} of [${details.startSN}-${details.endSN}], ${
|
670
|
-
this.
|
652
|
+
this.logPrefix === '[stream-controller]' ? 'level' : 'track'
|
671
653
|
} ${frag.level}`,
|
672
654
|
);
|
673
655
|
this.state = State.KEY_LOADING;
|
@@ -707,7 +689,7 @@ export default class BaseStreamController
|
|
707
689
|
} of playlist [${details.startSN}-${
|
708
690
|
details.endSN
|
709
691
|
}] parts [0-${partIndex}-${partList.length - 1}] ${
|
710
|
-
this.
|
692
|
+
this.logPrefix === '[stream-controller]' ? 'level' : 'track'
|
711
693
|
}: ${frag.level}, target: ${parseFloat(
|
712
694
|
targetBufferTime.toFixed(3),
|
713
695
|
)}`,
|
@@ -766,7 +748,7 @@ export default class BaseStreamController
|
|
766
748
|
this.log(
|
767
749
|
`Loading fragment ${frag.sn} cc: ${frag.cc} ${
|
768
750
|
details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : ''
|
769
|
-
}${this.
|
751
|
+
}${this.logPrefix === '[stream-controller]' ? 'level' : 'track'}: ${
|
770
752
|
frag.level
|
771
753
|
}, target: ${parseFloat(targetBufferTime.toFixed(3))}`,
|
772
754
|
);
|
@@ -1568,7 +1550,7 @@ export default class BaseStreamController
|
|
1568
1550
|
errorAction.resolved = true;
|
1569
1551
|
}
|
1570
1552
|
} else {
|
1571
|
-
|
1553
|
+
logger.warn(
|
1572
1554
|
`${data.details} reached or exceeded max retry (${retryCount})`,
|
1573
1555
|
);
|
1574
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
|
}
|
@@ -5,7 +5,6 @@ import { CmcdObjectType } from '@svta/common-media-library/cmcd/CmcdObjectType';
|
|
5
5
|
import { CmcdStreamingFormat } from '@svta/common-media-library/cmcd/CmcdStreamingFormat';
|
6
6
|
import { appendCmcdHeaders } from '@svta/common-media-library/cmcd/appendCmcdHeaders';
|
7
7
|
import { appendCmcdQuery } from '@svta/common-media-library/cmcd/appendCmcdQuery';
|
8
|
-
import type { CmcdEncodeOptions } from '@svta/common-media-library/cmcd/CmcdEncodeOptions';
|
9
8
|
import { uuid } from '@svta/common-media-library/utils/uuid';
|
10
9
|
import { BufferHelper } from '../utils/buffer-helper';
|
11
10
|
import { logger } from '../utils/logger';
|
@@ -166,7 +165,7 @@ export default class CMCDController implements ComponentAPI {
|
|
166
165
|
data.su = this.buffering;
|
167
166
|
}
|
168
167
|
|
169
|
-
// TODO: Implement rtp, nrr, dl
|
168
|
+
// TODO: Implement rtp, nrr, nor, dl
|
170
169
|
|
171
170
|
const { includeKeys } = this;
|
172
171
|
if (includeKeys) {
|
@@ -176,18 +175,14 @@ export default class CMCDController implements ComponentAPI {
|
|
176
175
|
}, {});
|
177
176
|
}
|
178
177
|
|
179
|
-
const options: CmcdEncodeOptions = {
|
180
|
-
baseUrl: context.url,
|
181
|
-
};
|
182
|
-
|
183
178
|
if (this.useHeaders) {
|
184
179
|
if (!context.headers) {
|
185
180
|
context.headers = {};
|
186
181
|
}
|
187
182
|
|
188
|
-
appendCmcdHeaders(context.headers, data
|
183
|
+
appendCmcdHeaders(context.headers, data);
|
189
184
|
} else {
|
190
|
-
context.url = appendCmcdQuery(context.url, data
|
185
|
+
context.url = appendCmcdQuery(context.url, data);
|
191
186
|
}
|
192
187
|
}
|
193
188
|
|
@@ -228,29 +223,12 @@ export default class CMCDController implements ComponentAPI {
|
|
228
223
|
data.bl = this.getBufferLength(ot);
|
229
224
|
}
|
230
225
|
|
231
|
-
const next = this.getNextFrag(fragment);
|
232
|
-
if (next) {
|
233
|
-
if (next.url && next.url !== fragment.url) {
|
234
|
-
data.nor = next.url;
|
235
|
-
}
|
236
|
-
}
|
237
|
-
|
238
226
|
this.apply(context, data);
|
239
227
|
} catch (error) {
|
240
228
|
logger.warn('Could not generate segment CMCD data.', error);
|
241
229
|
}
|
242
230
|
};
|
243
231
|
|
244
|
-
private getNextFrag(fragment: Fragment): Fragment | undefined {
|
245
|
-
const levelDetails = this.hls.levels[fragment.level]?.details;
|
246
|
-
if (levelDetails) {
|
247
|
-
const index = (fragment.sn as number) - levelDetails.startSN;
|
248
|
-
return levelDetails.fragments[index + 1];
|
249
|
-
}
|
250
|
-
|
251
|
-
return undefined;
|
252
|
-
}
|
253
|
-
|
254
232
|
/**
|
255
233
|
* The CMCD object type.
|
256
234
|
*/
|