hls.js 1.5.5-0.canary.9997 → 1.5.5
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/README.md +0 -1
- package/dist/hls-demo.js +0 -10
- package/dist/hls-demo.js.map +1 -1
- package/dist/hls.js +1134 -2043
- package/dist/hls.js.d.ts +50 -65
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +852 -1141
- 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 +686 -974
- 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 +847 -1741
- 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 +20 -20
- package/src/config.ts +2 -3
- package/src/controller/abr-controller.ts +20 -21
- package/src/controller/audio-stream-controller.ts +16 -15
- package/src/controller/audio-track-controller.ts +1 -1
- package/src/controller/base-playlist-controller.ts +8 -20
- package/src/controller/base-stream-controller.ts +33 -149
- package/src/controller/buffer-controller.ts +11 -11
- package/src/controller/cap-level-controller.ts +2 -1
- package/src/controller/cmcd-controller.ts +6 -27
- 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 +18 -12
- package/src/controller/stream-controller.ts +32 -25
- 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 +37 -71
- package/src/demux/video/avc-video-parser.ts +119 -208
- package/src/demux/video/base-video-parser.ts +2 -134
- package/src/demux/video/exp-golomb.ts +208 -0
- package/src/events.ts +0 -7
- package/src/hls.ts +34 -42
- 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/loader/playlist-loader.ts +5 -4
- package/src/remux/mp4-generator.ts +1 -196
- package/src/remux/mp4-remuxer.ts +7 -23
- package/src/task-loop.ts +2 -5
- package/src/types/component-api.ts +0 -2
- package/src/types/demuxer.ts +0 -3
- package/src/types/events.ts +0 -4
- package/src/utils/codecs.ts +4 -33
- package/src/utils/logger.ts +24 -54
- package/src/crypt/decrypter-aes-mode.ts +0 -4
- package/src/demux/video/hevc-video-parser.ts +0 -746
- package/src/utils/encryption-methods-util.ts +0 -21
@@ -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,8 +97,12 @@ export default class BaseStreamController
|
|
100
97
|
protected startFragRequested: boolean = false;
|
101
98
|
protected decrypter: Decrypter;
|
102
99
|
protected initPTS: RationalTimestamp[] = [];
|
103
|
-
protected
|
104
|
-
|
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;
|
105
106
|
|
106
107
|
constructor(
|
107
108
|
hls: Hls,
|
@@ -110,32 +111,18 @@ export default class BaseStreamController
|
|
110
111
|
logPrefix: string,
|
111
112
|
playlistType: PlaylistLevelType,
|
112
113
|
) {
|
113
|
-
super(
|
114
|
+
super();
|
114
115
|
this.playlistType = playlistType;
|
116
|
+
this.logPrefix = logPrefix;
|
117
|
+
this.log = logger.log.bind(logger, `${logPrefix}:`);
|
118
|
+
this.warn = logger.warn.bind(logger, `${logPrefix}:`);
|
115
119
|
this.hls = hls;
|
116
120
|
this.fragmentLoader = new FragmentLoader(hls.config);
|
117
121
|
this.keyLoader = keyLoader;
|
118
122
|
this.fragmentTracker = fragmentTracker;
|
119
123
|
this.config = hls.config;
|
120
124
|
this.decrypter = new Decrypter(hls.config);
|
121
|
-
}
|
122
|
-
|
123
|
-
protected registerListeners() {
|
124
|
-
const { hls } = this;
|
125
|
-
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
126
|
-
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
127
|
-
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
128
125
|
hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
129
|
-
hls.on(Events.ERROR, this.onError, this);
|
130
|
-
}
|
131
|
-
|
132
|
-
protected unregisterListeners() {
|
133
|
-
const { hls } = this;
|
134
|
-
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
135
|
-
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
136
|
-
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
137
|
-
hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
138
|
-
hls.off(Events.ERROR, this.onError, this);
|
139
126
|
}
|
140
127
|
|
141
128
|
protected doTick() {
|
@@ -163,14 +150,6 @@ export default class BaseStreamController
|
|
163
150
|
this.state = State.STOPPED;
|
164
151
|
}
|
165
152
|
|
166
|
-
public pauseBuffering() {
|
167
|
-
this.buffering = false;
|
168
|
-
}
|
169
|
-
|
170
|
-
public resumeBuffering() {
|
171
|
-
this.buffering = true;
|
172
|
-
}
|
173
|
-
|
174
153
|
protected _streamEnded(
|
175
154
|
bufferInfo: BufferInfo,
|
176
155
|
levelDetails: LevelDetails,
|
@@ -218,8 +197,10 @@ export default class BaseStreamController
|
|
218
197
|
data: MediaAttachedData,
|
219
198
|
) {
|
220
199
|
const media = (this.media = this.mediaBuffer = data.media);
|
221
|
-
|
222
|
-
|
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);
|
223
204
|
const config = this.config;
|
224
205
|
if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
|
225
206
|
this.startLoad(config.startPosition);
|
@@ -234,9 +215,10 @@ export default class BaseStreamController
|
|
234
215
|
}
|
235
216
|
|
236
217
|
// remove video listeners
|
237
|
-
if (media) {
|
238
|
-
media.removeEventListener('seeking', this.
|
239
|
-
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;
|
240
222
|
}
|
241
223
|
if (this.keyLoader) {
|
242
224
|
this.keyLoader.detach();
|
@@ -247,11 +229,7 @@ export default class BaseStreamController
|
|
247
229
|
this.stopLoad();
|
248
230
|
}
|
249
231
|
|
250
|
-
protected
|
251
|
-
|
252
|
-
protected onError(event: Events.ERROR, data: ErrorData) {}
|
253
|
-
|
254
|
-
protected onMediaSeeking = () => {
|
232
|
+
protected onMediaSeeking() {
|
255
233
|
const { config, fragCurrent, media, mediaBuffer, state } = this;
|
256
234
|
const currentTime: number = media ? media.currentTime : 0;
|
257
235
|
const bufferInfo = BufferHelper.bufferInfo(
|
@@ -305,21 +283,6 @@ export default class BaseStreamController
|
|
305
283
|
);
|
306
284
|
|
307
285
|
this.lastCurrentTime = currentTime;
|
308
|
-
if (!this.loadingParts) {
|
309
|
-
const bufferEnd = Math.max(bufferInfo.end, currentTime);
|
310
|
-
const shouldLoadParts = this.shouldLoadParts(
|
311
|
-
this.getLevelDetails(),
|
312
|
-
bufferEnd,
|
313
|
-
);
|
314
|
-
if (shouldLoadParts) {
|
315
|
-
this.log(
|
316
|
-
`LL-Part loading ON after seeking to ${currentTime.toFixed(
|
317
|
-
2,
|
318
|
-
)} with buffer @${bufferEnd.toFixed(2)}`,
|
319
|
-
);
|
320
|
-
this.loadingParts = shouldLoadParts;
|
321
|
-
}
|
322
|
-
}
|
323
286
|
}
|
324
287
|
|
325
288
|
// in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
|
@@ -329,17 +292,12 @@ export default class BaseStreamController
|
|
329
292
|
|
330
293
|
// Async tick to speed up processing
|
331
294
|
this.tickImmediate();
|
332
|
-
}
|
295
|
+
}
|
333
296
|
|
334
|
-
protected onMediaEnded
|
297
|
+
protected onMediaEnded() {
|
335
298
|
// reset startPosition and lastCurrentTime to restart playback @ stream beginning
|
336
299
|
this.startPosition = this.lastCurrentTime = 0;
|
337
|
-
|
338
|
-
this.hls.trigger(Events.MEDIA_ENDED, {
|
339
|
-
stalled: false,
|
340
|
-
});
|
341
|
-
}
|
342
|
-
};
|
300
|
+
}
|
343
301
|
|
344
302
|
protected onManifestLoaded(
|
345
303
|
event: Events.MANIFEST_LOADED,
|
@@ -354,7 +312,7 @@ export default class BaseStreamController
|
|
354
312
|
this.stopLoad();
|
355
313
|
super.onHandlerDestroying();
|
356
314
|
// @ts-ignore
|
357
|
-
this.hls =
|
315
|
+
this.hls = null;
|
358
316
|
}
|
359
317
|
|
360
318
|
protected onHandlerDestroyed() {
|
@@ -528,7 +486,7 @@ export default class BaseStreamController
|
|
528
486
|
payload.byteLength > 0 &&
|
529
487
|
decryptData?.key &&
|
530
488
|
decryptData.iv &&
|
531
|
-
|
489
|
+
decryptData.method === 'AES-128'
|
532
490
|
) {
|
533
491
|
const startTime = self.performance.now();
|
534
492
|
// decrypt init segment data
|
@@ -537,7 +495,6 @@ export default class BaseStreamController
|
|
537
495
|
new Uint8Array(payload),
|
538
496
|
decryptData.key.buffer,
|
539
497
|
decryptData.iv.buffer,
|
540
|
-
getAesModeFromFullSegmentMethod(decryptData.method),
|
541
498
|
)
|
542
499
|
.catch((err) => {
|
543
500
|
hls.trigger(Events.ERROR, {
|
@@ -692,7 +649,7 @@ export default class BaseStreamController
|
|
692
649
|
if (frag.encrypted && !frag.decryptdata?.key) {
|
693
650
|
this.log(
|
694
651
|
`Loading key for ${frag.sn} of [${details.startSN}-${details.endSN}], ${
|
695
|
-
this.
|
652
|
+
this.logPrefix === '[stream-controller]' ? 'level' : 'track'
|
696
653
|
} ${frag.level}`,
|
697
654
|
);
|
698
655
|
this.state = State.KEY_LOADING;
|
@@ -716,23 +673,8 @@ export default class BaseStreamController
|
|
716
673
|
this.keyLoader.loadClear(frag, details.encryptedFragments);
|
717
674
|
}
|
718
675
|
|
719
|
-
const fragPrevious = this.fragPrevious;
|
720
|
-
if (
|
721
|
-
frag.sn !== 'initSegment' &&
|
722
|
-
(!fragPrevious || frag.sn !== fragPrevious.sn)
|
723
|
-
) {
|
724
|
-
const shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
|
725
|
-
if (shouldLoadParts !== this.loadingParts) {
|
726
|
-
this.log(
|
727
|
-
`LL-Part loading ${
|
728
|
-
shouldLoadParts ? 'ON' : 'OFF'
|
729
|
-
} loading sn ${fragPrevious?.sn}->${frag.sn}`,
|
730
|
-
);
|
731
|
-
this.loadingParts = shouldLoadParts;
|
732
|
-
}
|
733
|
-
}
|
734
676
|
targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
|
735
|
-
if (this.
|
677
|
+
if (this.config.lowLatencyMode && frag.sn !== 'initSegment') {
|
736
678
|
const partList = details.partList;
|
737
679
|
if (partList && progressCallback) {
|
738
680
|
if (targetBufferTime > frag.end && details.fragmentHint) {
|
@@ -747,7 +689,7 @@ export default class BaseStreamController
|
|
747
689
|
} of playlist [${details.startSN}-${
|
748
690
|
details.endSN
|
749
691
|
}] parts [0-${partIndex}-${partList.length - 1}] ${
|
750
|
-
this.
|
692
|
+
this.logPrefix === '[stream-controller]' ? 'level' : 'track'
|
751
693
|
}: ${frag.level}, target: ${parseFloat(
|
752
694
|
targetBufferTime.toFixed(3),
|
753
695
|
)}`,
|
@@ -803,22 +745,10 @@ export default class BaseStreamController
|
|
803
745
|
}
|
804
746
|
}
|
805
747
|
|
806
|
-
if (frag.sn !== 'initSegment' && this.loadingParts) {
|
807
|
-
this.log(
|
808
|
-
`LL-Part loading OFF after next part miss @${targetBufferTime.toFixed(
|
809
|
-
2,
|
810
|
-
)}`,
|
811
|
-
);
|
812
|
-
this.loadingParts = false;
|
813
|
-
} else if (!frag.url) {
|
814
|
-
// Selected fragment hint for part but not loading parts
|
815
|
-
return Promise.resolve(null);
|
816
|
-
}
|
817
|
-
|
818
748
|
this.log(
|
819
749
|
`Loading fragment ${frag.sn} cc: ${frag.cc} ${
|
820
750
|
details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : ''
|
821
|
-
}${this.
|
751
|
+
}${this.logPrefix === '[stream-controller]' ? 'level' : 'track'}: ${
|
822
752
|
frag.level
|
823
753
|
}, target: ${parseFloat(targetBufferTime.toFixed(3))}`,
|
824
754
|
);
|
@@ -942,50 +872,9 @@ export default class BaseStreamController
|
|
942
872
|
if (part) {
|
943
873
|
part.stats.parsing.end = now;
|
944
874
|
}
|
945
|
-
// See if part loading should be disabled/enabled based on buffer and playback position.
|
946
|
-
if (frag.sn !== 'initSegment') {
|
947
|
-
const levelDetails = this.getLevelDetails();
|
948
|
-
const loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
|
949
|
-
const shouldLoadParts =
|
950
|
-
loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
|
951
|
-
if (shouldLoadParts !== this.loadingParts) {
|
952
|
-
this.log(
|
953
|
-
`LL-Part loading ${
|
954
|
-
shouldLoadParts ? 'ON' : 'OFF'
|
955
|
-
} after parsing segment ending @${frag.end.toFixed(2)}`,
|
956
|
-
);
|
957
|
-
this.loadingParts = shouldLoadParts;
|
958
|
-
}
|
959
|
-
}
|
960
|
-
|
961
875
|
this.updateLevelTiming(frag, part, level, chunkMeta.partial);
|
962
876
|
}
|
963
877
|
|
964
|
-
private shouldLoadParts(
|
965
|
-
details: LevelDetails | undefined,
|
966
|
-
bufferEnd: number,
|
967
|
-
): boolean {
|
968
|
-
if (this.config.lowLatencyMode) {
|
969
|
-
if (!details) {
|
970
|
-
return this.loadingParts;
|
971
|
-
}
|
972
|
-
if (details?.partList) {
|
973
|
-
// Buffer must be ahead of first part + duration of parts after last segment
|
974
|
-
// and playback must be at or past segment adjacent to part list
|
975
|
-
const firstPart = details.partList[0];
|
976
|
-
const safePartStart =
|
977
|
-
firstPart.end + (details.fragmentHint?.duration || 0);
|
978
|
-
if (
|
979
|
-
bufferEnd >= safePartStart &&
|
980
|
-
this.lastCurrentTime > firstPart.start - firstPart.fragment.duration
|
981
|
-
) {
|
982
|
-
return true;
|
983
|
-
}
|
984
|
-
}
|
985
|
-
}
|
986
|
-
return false;
|
987
|
-
}
|
988
|
-
|
989
878
|
protected getCurrentContext(
|
990
879
|
chunkMeta: ChunkMetadata,
|
991
880
|
): { frag: Fragment; part: Part | null; level: Level } | null {
|
@@ -1167,8 +1056,7 @@ export default class BaseStreamController
|
|
1167
1056
|
// find fragment index, contiguous with end of buffer position
|
1168
1057
|
const { config } = this;
|
1169
1058
|
const start = fragments[0].start;
|
1170
|
-
|
1171
|
-
let frag: Fragment | null = null;
|
1059
|
+
let frag;
|
1172
1060
|
|
1173
1061
|
if (levelDetails.live) {
|
1174
1062
|
const initialLiveManifestSize = config.initialLiveManifestSize;
|
@@ -1188,10 +1076,6 @@ export default class BaseStreamController
|
|
1188
1076
|
this.startPosition === -1) ||
|
1189
1077
|
pos < start
|
1190
1078
|
) {
|
1191
|
-
if (canLoadParts && !this.loadingParts) {
|
1192
|
-
this.log(`LL-Part loading ON for initial live fragment`);
|
1193
|
-
this.loadingParts = true;
|
1194
|
-
}
|
1195
1079
|
frag = this.getInitialLiveFragment(levelDetails, fragments);
|
1196
1080
|
this.startPosition = this.nextLoadPosition = frag
|
1197
1081
|
? this.hls.liveSyncPosition || frag.start
|
@@ -1204,7 +1088,7 @@ export default class BaseStreamController
|
|
1204
1088
|
|
1205
1089
|
// If we haven't run into any special cases already, just load the fragment most closely matching the requested position
|
1206
1090
|
if (!frag) {
|
1207
|
-
const end =
|
1091
|
+
const end = config.lowLatencyMode
|
1208
1092
|
? levelDetails.partEnd
|
1209
1093
|
: levelDetails.fragmentEnd;
|
1210
1094
|
frag = this.getFragmentAtPosition(pos, end, levelDetails);
|
@@ -1387,7 +1271,7 @@ export default class BaseStreamController
|
|
1387
1271
|
const partList = levelDetails.partList;
|
1388
1272
|
|
1389
1273
|
const loadingParts = !!(
|
1390
|
-
|
1274
|
+
config.lowLatencyMode &&
|
1391
1275
|
partList?.length &&
|
1392
1276
|
fragmentHint
|
1393
1277
|
);
|
@@ -1666,7 +1550,7 @@ export default class BaseStreamController
|
|
1666
1550
|
errorAction.resolved = true;
|
1667
1551
|
}
|
1668
1552
|
} else {
|
1669
|
-
|
1553
|
+
logger.warn(
|
1670
1554
|
`${data.details} reached or exceeded max retry (${retryCount})`,
|
1671
1555
|
);
|
1672
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() {
|
@@ -295,7 +296,6 @@ export default class BufferController extends Logger implements ComponentAPI {
|
|
295
296
|
this.resetBuffer(type);
|
296
297
|
});
|
297
298
|
this._initSourceBuffer();
|
298
|
-
this.hls.resumeBuffering();
|
299
299
|
}
|
300
300
|
|
301
301
|
private resetBuffer(type: SourceBufferName) {
|
@@ -1004,7 +1004,7 @@ export default class BufferController extends Logger implements ComponentAPI {
|
|
1004
1004
|
private _onMediaEmptied = () => {
|
1005
1005
|
const { mediaSrc, _objectUrl } = this;
|
1006
1006
|
if (mediaSrc !== _objectUrl) {
|
1007
|
-
|
1007
|
+
logger.error(
|
1008
1008
|
`Media element src was set while attaching MediaSource (${_objectUrl} > ${mediaSrc})`,
|
1009
1009
|
);
|
1010
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,9 +5,9 @@ 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';
|
10
|
+
import { logger } from '../utils/logger';
|
11
11
|
import type { ComponentAPI } from '../types/component-api';
|
12
12
|
import type { Fragment } from '../loader/fragment';
|
13
13
|
import type { BufferCreatedData, MediaAttachedData } from '../types/events';
|
@@ -165,7 +165,7 @@ export default class CMCDController implements ComponentAPI {
|
|
165
165
|
data.su = this.buffering;
|
166
166
|
}
|
167
167
|
|
168
|
-
// TODO: Implement rtp, nrr, dl
|
168
|
+
// TODO: Implement rtp, nrr, nor, dl
|
169
169
|
|
170
170
|
const { includeKeys } = this;
|
171
171
|
if (includeKeys) {
|
@@ -175,18 +175,14 @@ export default class CMCDController implements ComponentAPI {
|
|
175
175
|
}, {});
|
176
176
|
}
|
177
177
|
|
178
|
-
const options: CmcdEncodeOptions = {
|
179
|
-
baseUrl: context.url,
|
180
|
-
};
|
181
|
-
|
182
178
|
if (this.useHeaders) {
|
183
179
|
if (!context.headers) {
|
184
180
|
context.headers = {};
|
185
181
|
}
|
186
182
|
|
187
|
-
appendCmcdHeaders(context.headers, data
|
183
|
+
appendCmcdHeaders(context.headers, data);
|
188
184
|
} else {
|
189
|
-
context.url = appendCmcdQuery(context.url, data
|
185
|
+
context.url = appendCmcdQuery(context.url, data);
|
190
186
|
}
|
191
187
|
}
|
192
188
|
|
@@ -200,7 +196,7 @@ export default class CMCDController implements ComponentAPI {
|
|
200
196
|
su: !this.initialized,
|
201
197
|
});
|
202
198
|
} catch (error) {
|
203
|
-
|
199
|
+
logger.warn('Could not generate manifest CMCD data.', error);
|
204
200
|
}
|
205
201
|
};
|
206
202
|
|
@@ -227,29 +223,12 @@ export default class CMCDController implements ComponentAPI {
|
|
227
223
|
data.bl = this.getBufferLength(ot);
|
228
224
|
}
|
229
225
|
|
230
|
-
const next = this.getNextFrag(fragment);
|
231
|
-
if (next) {
|
232
|
-
if (next.url && next.url !== fragment.url) {
|
233
|
-
data.nor = next.url;
|
234
|
-
}
|
235
|
-
}
|
236
|
-
|
237
226
|
this.apply(context, data);
|
238
227
|
} catch (error) {
|
239
|
-
|
228
|
+
logger.warn('Could not generate segment CMCD data.', error);
|
240
229
|
}
|
241
230
|
};
|
242
231
|
|
243
|
-
private getNextFrag(fragment: Fragment): Fragment | undefined {
|
244
|
-
const levelDetails = this.hls.levels[fragment.level]?.details;
|
245
|
-
if (levelDetails) {
|
246
|
-
const index = (fragment.sn as number) - levelDetails.startSN;
|
247
|
-
return levelDetails.fragments[index + 1];
|
248
|
-
}
|
249
|
-
|
250
|
-
return undefined;
|
251
|
-
}
|
252
|
-
|
253
232
|
/**
|
254
233
|
* The CMCD object type.
|
255
234
|
*/
|
@@ -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
|
}
|
@@ -5,7 +5,7 @@
|
|
5
5
|
*/
|
6
6
|
import { Events } from '../events';
|
7
7
|
import { ErrorTypes, ErrorDetails } from '../errors';
|
8
|
-
import {
|
8
|
+
import { logger } from '../utils/logger';
|
9
9
|
import {
|
10
10
|
getKeySystemsForConfig,
|
11
11
|
getSupportedMediaKeySystemConfigurations,
|
@@ -41,6 +41,9 @@ import type {
|
|
41
41
|
LoaderConfiguration,
|
42
42
|
LoaderContext,
|
43
43
|
} from '../types/loader';
|
44
|
+
|
45
|
+
const LOGGER_PREFIX = '[eme]';
|
46
|
+
|
44
47
|
interface KeySystemAccessPromises {
|
45
48
|
keySystemAccess: Promise<MediaKeySystemAccess>;
|
46
49
|
mediaKeys?: Promise<MediaKeys>;
|
@@ -65,7 +68,7 @@ export interface MediaKeySessionContext {
|
|
65
68
|
* @class
|
66
69
|
* @constructor
|
67
70
|
*/
|
68
|
-
class EMEController
|
71
|
+
class EMEController implements ComponentAPI {
|
69
72
|
public static CDMCleanupPromise: Promise<void> | void;
|
70
73
|
|
71
74
|
private readonly hls: Hls;
|
@@ -87,9 +90,15 @@ class EMEController extends Logger implements ComponentAPI {
|
|
87
90
|
private setMediaKeysQueue: Promise<void>[] = EMEController.CDMCleanupPromise
|
88
91
|
? [EMEController.CDMCleanupPromise]
|
89
92
|
: [];
|
93
|
+
private onMediaEncrypted = this._onMediaEncrypted.bind(this);
|
94
|
+
private onWaitingForKey = this._onWaitingForKey.bind(this);
|
95
|
+
|
96
|
+
private debug: (msg: any) => void = logger.debug.bind(logger, LOGGER_PREFIX);
|
97
|
+
private log: (msg: any) => void = logger.log.bind(logger, LOGGER_PREFIX);
|
98
|
+
private warn: (msg: any) => void = logger.warn.bind(logger, LOGGER_PREFIX);
|
99
|
+
private error: (msg: any) => void = logger.error.bind(logger, LOGGER_PREFIX);
|
90
100
|
|
91
101
|
constructor(hls: Hls) {
|
92
|
-
super('eme', hls.logger);
|
93
102
|
this.hls = hls;
|
94
103
|
this.config = hls.config;
|
95
104
|
this.registerListeners();
|
@@ -104,9 +113,13 @@ class EMEController extends Logger implements ComponentAPI {
|
|
104
113
|
config.licenseXhrSetup = config.licenseResponseCallback = undefined;
|
105
114
|
config.drmSystems = config.drmSystemOptions = {};
|
106
115
|
// @ts-ignore
|
107
|
-
this.hls =
|
116
|
+
this.hls =
|
117
|
+
this.onMediaEncrypted =
|
118
|
+
this.onWaitingForKey =
|
119
|
+
this.keyIdToKeySessionPromise =
|
120
|
+
null as any;
|
108
121
|
// @ts-ignore
|
109
|
-
this.
|
122
|
+
this.config = null;
|
110
123
|
}
|
111
124
|
|
112
125
|
private registerListeners() {
|
@@ -510,7 +523,7 @@ class EMEController extends Logger implements ComponentAPI {
|
|
510
523
|
return this.attemptKeySystemAccess(keySystemsToAttempt);
|
511
524
|
}
|
512
525
|
|
513
|
-
private
|
526
|
+
private _onMediaEncrypted(event: MediaEncryptedEvent) {
|
514
527
|
const { initDataType, initData } = event;
|
515
528
|
this.debug(`"${event.type}" event: init data type: "${initDataType}"`);
|
516
529
|
|
@@ -626,11 +639,11 @@ class EMEController extends Logger implements ComponentAPI {
|
|
626
639
|
);
|
627
640
|
}
|
628
641
|
keySessionContextPromise.catch((error) => this.handleError(error));
|
629
|
-
}
|
642
|
+
}
|
630
643
|
|
631
|
-
private
|
644
|
+
private _onWaitingForKey(event: Event) {
|
632
645
|
this.log(`"${event.type}" event`);
|
633
|
-
}
|
646
|
+
}
|
634
647
|
|
635
648
|
private attemptSetMediaKeys(
|
636
649
|
keySystem: KeySystems,
|
@@ -8,7 +8,7 @@ import {
|
|
8
8
|
} from '../utils/error-helper';
|
9
9
|
import { findFragmentByPTS } from './fragment-finders';
|
10
10
|
import { HdcpLevel, HdcpLevels } from '../types/level';
|
11
|
-
import {
|
11
|
+
import { logger } from '../utils/logger';
|
12
12
|
import type Hls from '../hls';
|
13
13
|
import type { RetryConfig } from '../config';
|
14
14
|
import type { NetworkComponentAPI } from '../types/component-api';
|
@@ -50,17 +50,19 @@ type PenalizedRendition = {
|
|
50
50
|
|
51
51
|
type PenalizedRenditions = { [key: number]: PenalizedRendition };
|
52
52
|
|
53
|
-
export default class ErrorController
|
54
|
-
extends Logger
|
55
|
-
implements NetworkComponentAPI
|
56
|
-
{
|
53
|
+
export default class ErrorController implements NetworkComponentAPI {
|
57
54
|
private readonly hls: Hls;
|
58
55
|
private playlistError: number = 0;
|
59
56
|
private penalizedRenditions: PenalizedRenditions = {};
|
57
|
+
private log: (msg: any) => void;
|
58
|
+
private warn: (msg: any) => void;
|
59
|
+
private error: (msg: any) => void;
|
60
60
|
|
61
61
|
constructor(hls: Hls) {
|
62
|
-
super('error-controller', hls.logger);
|
63
62
|
this.hls = hls;
|
63
|
+
this.log = logger.log.bind(logger, `[info]:`);
|
64
|
+
this.warn = logger.warn.bind(logger, `[warning]:`);
|
65
|
+
this.error = logger.error.bind(logger, `[error]:`);
|
64
66
|
this.registerListeners();
|
65
67
|
}
|
66
68
|
|