hls.js 1.5.14-0.canary.10515 → 1.5.14
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 +3 -4
- package/dist/hls-demo.js +38 -41
- package/dist/hls-demo.js.map +1 -1
- package/dist/hls.js +2903 -4542
- package/dist/hls.js.d.ts +112 -186
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +2284 -3295
- 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 +1804 -2817
- 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 +4652 -6293
- 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 +38 -38
- package/src/config.ts +2 -5
- package/src/controller/abr-controller.ts +25 -39
- package/src/controller/audio-stream-controller.ts +136 -156
- package/src/controller/audio-track-controller.ts +1 -1
- package/src/controller/base-playlist-controller.ts +10 -27
- package/src/controller/base-stream-controller.ts +107 -263
- package/src/controller/buffer-controller.ts +98 -252
- package/src/controller/buffer-operation-queue.ts +19 -16
- package/src/controller/cap-level-controller.ts +2 -3
- package/src/controller/cmcd-controller.ts +14 -51
- package/src/controller/content-steering-controller.ts +15 -29
- package/src/controller/eme-controller.ts +23 -10
- package/src/controller/error-controller.ts +22 -28
- package/src/controller/fps-controller.ts +3 -8
- package/src/controller/fragment-finders.ts +16 -44
- package/src/controller/fragment-tracker.ts +25 -58
- package/src/controller/gap-controller.ts +16 -43
- package/src/controller/id3-track-controller.ts +35 -45
- package/src/controller/latency-controller.ts +13 -18
- package/src/controller/level-controller.ts +19 -37
- package/src/controller/stream-controller.ts +83 -100
- package/src/controller/subtitle-stream-controller.ts +47 -35
- package/src/controller/subtitle-track-controller.ts +3 -5
- package/src/controller/timeline-controller.ts +22 -20
- package/src/crypt/aes-crypto.ts +2 -21
- package/src/crypt/decrypter.ts +16 -32
- package/src/crypt/fast-aes-key.ts +5 -28
- package/src/demux/audio/aacdemuxer.ts +5 -5
- package/src/demux/audio/ac3-demuxer.ts +4 -5
- package/src/demux/audio/adts.ts +4 -9
- package/src/demux/audio/base-audio-demuxer.ts +14 -16
- package/src/demux/audio/mp3demuxer.ts +3 -4
- package/src/demux/audio/mpegaudio.ts +1 -1
- package/src/demux/id3.ts +411 -0
- package/src/demux/inject-worker.ts +4 -38
- package/src/demux/mp4demuxer.ts +7 -7
- package/src/demux/sample-aes.ts +0 -2
- package/src/demux/transmuxer-interface.ts +83 -106
- package/src/demux/transmuxer-worker.ts +77 -111
- package/src/demux/transmuxer.ts +22 -46
- package/src/demux/tsdemuxer.ts +62 -122
- package/src/demux/video/avc-video-parser.ts +121 -210
- package/src/demux/video/base-video-parser.ts +2 -135
- package/src/demux/video/exp-golomb.ts +208 -0
- package/src/errors.ts +0 -2
- package/src/events.ts +1 -8
- package/src/exports-named.ts +1 -1
- package/src/hls.ts +48 -97
- package/src/loader/date-range.ts +5 -71
- package/src/loader/fragment-loader.ts +21 -23
- package/src/loader/fragment.ts +4 -8
- package/src/loader/key-loader.ts +1 -3
- package/src/loader/level-details.ts +6 -6
- package/src/loader/level-key.ts +9 -10
- package/src/loader/m3u8-parser.ts +144 -138
- package/src/loader/playlist-loader.ts +7 -5
- package/src/remux/mp4-generator.ts +1 -196
- package/src/remux/mp4-remuxer.ts +84 -55
- package/src/remux/passthrough-remuxer.ts +8 -23
- package/src/task-loop.ts +2 -5
- package/src/types/component-api.ts +1 -3
- package/src/types/demuxer.ts +0 -3
- package/src/types/events.ts +6 -19
- package/src/types/fragment-tracker.ts +2 -2
- package/src/types/general.ts +6 -0
- package/src/types/media-playlist.ts +1 -9
- package/src/types/remuxer.ts +1 -1
- package/src/utils/attr-list.ts +9 -96
- package/src/utils/buffer-helper.ts +31 -12
- package/src/utils/cea-608-parser.ts +3 -1
- package/src/utils/codecs.ts +5 -34
- package/src/utils/discontinuities.ts +47 -21
- package/src/utils/fetch-loader.ts +1 -1
- package/src/utils/hdr.ts +7 -4
- package/src/utils/imsc1-ttml-parser.ts +1 -1
- package/src/utils/keysystem-util.ts +6 -1
- package/src/utils/level-helper.ts +44 -71
- package/src/utils/logger.ts +23 -58
- package/src/utils/mp4-tools.ts +3 -5
- package/src/utils/rendition-helper.ts +74 -100
- package/src/utils/variable-substitution.ts +19 -0
- package/src/utils/webvtt-parser.ts +12 -2
- package/src/crypt/decrypter-aes-mode.ts +0 -4
- package/src/demux/video/hevc-video-parser.ts +0 -749
- package/src/utils/encryption-methods-util.ts +0 -21
- package/src/utils/hash.ts +0 -10
- package/src/utils/utf8-utils.ts +0 -18
- package/src/version.ts +0 -1
@@ -1,15 +1,15 @@
|
|
1
1
|
import { Events } from '../events';
|
2
|
-
import
|
2
|
+
import Hls from '../hls';
|
3
3
|
import { Cmcd } from '@svta/common-media-library/cmcd/Cmcd';
|
4
4
|
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
|
-
import type { Fragment
|
12
|
+
import type { Fragment } from '../loader/fragment';
|
13
13
|
import type { BufferCreatedData, MediaAttachedData } from '../types/events';
|
14
14
|
import type {
|
15
15
|
FragmentLoaderContext,
|
@@ -81,7 +81,7 @@ export default class CMCDController implements ComponentAPI {
|
|
81
81
|
// @ts-ignore
|
82
82
|
this.hls = this.config = this.audioBuffer = this.videoBuffer = null;
|
83
83
|
// @ts-ignore
|
84
|
-
this.onWaiting = this.onPlaying =
|
84
|
+
this.onWaiting = this.onPlaying = null;
|
85
85
|
}
|
86
86
|
|
87
87
|
private onMediaAttached(
|
@@ -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
|
|
@@ -209,11 +205,11 @@ export default class CMCDController implements ComponentAPI {
|
|
209
205
|
*/
|
210
206
|
private applyFragmentData = (context: FragmentLoaderContext) => {
|
211
207
|
try {
|
212
|
-
const
|
213
|
-
const level = this.hls.levels[
|
214
|
-
const ot = this.getObjectType(
|
208
|
+
const fragment = context.frag;
|
209
|
+
const level = this.hls.levels[fragment.level];
|
210
|
+
const ot = this.getObjectType(fragment);
|
215
211
|
const data: Cmcd = {
|
216
|
-
d:
|
212
|
+
d: fragment.duration * 1000,
|
217
213
|
ot,
|
218
214
|
};
|
219
215
|
|
@@ -227,45 +223,12 @@ export default class CMCDController implements ComponentAPI {
|
|
227
223
|
data.bl = this.getBufferLength(ot);
|
228
224
|
}
|
229
225
|
|
230
|
-
const next = part ? this.getNextPart(part) : this.getNextFrag(frag);
|
231
|
-
|
232
|
-
if (next?.url && next.url !== frag.url) {
|
233
|
-
data.nor = next.url;
|
234
|
-
}
|
235
|
-
|
236
226
|
this.apply(context, data);
|
237
227
|
} catch (error) {
|
238
|
-
|
228
|
+
logger.warn('Could not generate segment CMCD data.', error);
|
239
229
|
}
|
240
230
|
};
|
241
231
|
|
242
|
-
private getNextFrag(fragment: Fragment): Fragment | undefined {
|
243
|
-
const levelDetails = this.hls.levels[fragment.level]?.details;
|
244
|
-
if (levelDetails) {
|
245
|
-
const index = (fragment.sn as number) - levelDetails.startSN;
|
246
|
-
return levelDetails.fragments[index + 1];
|
247
|
-
}
|
248
|
-
|
249
|
-
return undefined;
|
250
|
-
}
|
251
|
-
|
252
|
-
private getNextPart(part: Part): Part | undefined {
|
253
|
-
const { index, fragment } = part;
|
254
|
-
const partList = this.hls.levels[fragment.level]?.details?.partList;
|
255
|
-
|
256
|
-
if (partList) {
|
257
|
-
const { sn } = fragment;
|
258
|
-
for (let i = partList.length - 1; i >= 0; i--) {
|
259
|
-
const p = partList[i];
|
260
|
-
if (p.index === index && p.fragment.sn === sn) {
|
261
|
-
return partList[i + 1];
|
262
|
-
}
|
263
|
-
}
|
264
|
-
}
|
265
|
-
|
266
|
-
return undefined;
|
267
|
-
}
|
268
|
-
|
269
232
|
/**
|
270
233
|
* The CMCD object type.
|
271
234
|
*/
|
@@ -324,7 +287,7 @@ export default class CMCDController implements ComponentAPI {
|
|
324
287
|
* Get the buffer length for a media type in milliseconds
|
325
288
|
*/
|
326
289
|
private getBufferLength(type: CmcdObjectType) {
|
327
|
-
const media = this.media;
|
290
|
+
const media = this.hls.media;
|
328
291
|
const buffer =
|
329
292
|
type === CmcdObjectType.AUDIO ? this.audioBuffer : this.videoBuffer;
|
330
293
|
|
@@ -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,15 +48,13 @@ 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 = '.';
|
59
|
-
private
|
57
|
+
private pathwayPriority: string[] | null = null;
|
60
58
|
private timeToLoad: number = 300;
|
61
59
|
private reloadTimer: number = -1;
|
62
60
|
private updated: number = 0;
|
@@ -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
|
|
@@ -92,23 +90,6 @@ export default class ContentSteeringController
|
|
92
90
|
hls.off(Events.ERROR, this.onError, this);
|
93
91
|
}
|
94
92
|
|
95
|
-
pathways() {
|
96
|
-
return (this.levels || []).reduce((pathways, level) => {
|
97
|
-
if (pathways.indexOf(level.pathwayId) === -1) {
|
98
|
-
pathways.push(level.pathwayId);
|
99
|
-
}
|
100
|
-
return pathways;
|
101
|
-
}, [] as string[]);
|
102
|
-
}
|
103
|
-
|
104
|
-
get pathwayPriority(): string[] | null {
|
105
|
-
return this._pathwayPriority;
|
106
|
-
}
|
107
|
-
|
108
|
-
set pathwayPriority(pathwayPriority: string[]) {
|
109
|
-
this.updatePathwayPriority(pathwayPriority);
|
110
|
-
}
|
111
|
-
|
112
93
|
startLoad() {
|
113
94
|
this.started = true;
|
114
95
|
this.clearTimeout();
|
@@ -195,7 +176,7 @@ export default class ContentSteeringController
|
|
195
176
|
errorAction.flags === ErrorActionFlags.MoveAllAlternatesMatchingHost
|
196
177
|
) {
|
197
178
|
const levels = this.levels;
|
198
|
-
let pathwayPriority = this.
|
179
|
+
let pathwayPriority = this.pathwayPriority;
|
199
180
|
let errorPathway = this.pathwayId;
|
200
181
|
if (data.context) {
|
201
182
|
const { groupId, pathwayId, type } = data.context;
|
@@ -210,14 +191,19 @@ export default class ContentSteeringController
|
|
210
191
|
}
|
211
192
|
if (!pathwayPriority && levels) {
|
212
193
|
// If PATHWAY-PRIORITY was not provided, list pathways for error handling
|
213
|
-
pathwayPriority =
|
194
|
+
pathwayPriority = levels.reduce((pathways, level) => {
|
195
|
+
if (pathways.indexOf(level.pathwayId) === -1) {
|
196
|
+
pathways.push(level.pathwayId);
|
197
|
+
}
|
198
|
+
return pathways;
|
199
|
+
}, [] as string[]);
|
214
200
|
}
|
215
201
|
if (pathwayPriority && pathwayPriority.length > 1) {
|
216
202
|
this.updatePathwayPriority(pathwayPriority);
|
217
203
|
errorAction.resolved = this.pathwayId !== errorPathway;
|
218
204
|
}
|
219
205
|
if (!errorAction.resolved) {
|
220
|
-
|
206
|
+
logger.warn(
|
221
207
|
`Could not resolve ${data.details} ("${
|
222
208
|
data.error.message
|
223
209
|
}") with content-steering for Pathway: ${errorPathway} levels: ${
|
@@ -259,7 +245,7 @@ export default class ContentSteeringController
|
|
259
245
|
}
|
260
246
|
|
261
247
|
private updatePathwayPriority(pathwayPriority: string[]) {
|
262
|
-
this.
|
248
|
+
this.pathwayPriority = pathwayPriority;
|
263
249
|
let levels: Level[] | undefined;
|
264
250
|
|
265
251
|
// Evaluate if we should remove the pathway from the penalized list
|
@@ -456,7 +442,7 @@ export default class ContentSteeringController
|
|
456
442
|
) => {
|
457
443
|
this.log(`Loaded steering manifest: "${url}"`);
|
458
444
|
const steeringData = response.data as SteeringManifest;
|
459
|
-
if (steeringData
|
445
|
+
if (steeringData.VERSION !== 1) {
|
460
446
|
this.log(`Steering VERSION ${steeringData.VERSION} not supported!`);
|
461
447
|
return;
|
462
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,
|
@@ -19,7 +19,7 @@ import {
|
|
19
19
|
KeySystems,
|
20
20
|
requestMediaKeySystemAccess,
|
21
21
|
} from '../utils/mediakeys-helper';
|
22
|
-
import { strToUtf8array } from '../utils/
|
22
|
+
import { strToUtf8array } from '../utils/keysystem-util';
|
23
23
|
import { base64Decode } from '../utils/numeric-encoding-utils';
|
24
24
|
import { DecryptData, LevelKey } from '../loader/level-key';
|
25
25
|
import Hex from '../utils/hex';
|
@@ -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,12 +8,12 @@ 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';
|
15
15
|
import type { ErrorData } from '../types/events';
|
16
|
-
import type { Fragment
|
16
|
+
import type { Fragment } from '../loader/fragment';
|
17
17
|
import type { LevelDetails } from '../loader/level-details';
|
18
18
|
|
19
19
|
export const enum NetworkErrorAction {
|
@@ -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
|
|
@@ -127,7 +129,10 @@ export default class ErrorController
|
|
127
129
|
case ErrorDetails.FRAG_PARSING_ERROR:
|
128
130
|
// ignore empty segment errors marked as gap
|
129
131
|
if (data.frag?.gap) {
|
130
|
-
data.errorAction =
|
132
|
+
data.errorAction = {
|
133
|
+
action: NetworkErrorAction.DoNothing,
|
134
|
+
flags: ErrorActionFlags.None,
|
135
|
+
};
|
131
136
|
return;
|
132
137
|
}
|
133
138
|
// falls through
|
@@ -215,13 +220,10 @@ export default class ErrorController
|
|
215
220
|
case ErrorDetails.BUFFER_ADD_CODEC_ERROR:
|
216
221
|
case ErrorDetails.REMUX_ALLOC_ERROR:
|
217
222
|
case ErrorDetails.BUFFER_APPEND_ERROR:
|
218
|
-
|
219
|
-
|
220
|
-
data.
|
221
|
-
|
222
|
-
data.level ?? hls.loadLevel,
|
223
|
-
);
|
224
|
-
}
|
223
|
+
data.errorAction = this.getLevelSwitchAction(
|
224
|
+
data,
|
225
|
+
data.level ?? hls.loadLevel,
|
226
|
+
);
|
225
227
|
return;
|
226
228
|
case ErrorDetails.INTERNAL_EXCEPTION:
|
227
229
|
case ErrorDetails.BUFFER_APPENDING_ERROR:
|
@@ -230,7 +232,10 @@ export default class ErrorController
|
|
230
232
|
case ErrorDetails.BUFFER_STALLED_ERROR:
|
231
233
|
case ErrorDetails.BUFFER_SEEK_OVER_HOLE:
|
232
234
|
case ErrorDetails.BUFFER_NUDGE_ON_STALL:
|
233
|
-
data.errorAction =
|
235
|
+
data.errorAction = {
|
236
|
+
action: NetworkErrorAction.DoNothing,
|
237
|
+
flags: ErrorActionFlags.None,
|
238
|
+
};
|
234
239
|
return;
|
235
240
|
}
|
236
241
|
|
@@ -384,7 +389,7 @@ export default class ErrorController
|
|
384
389
|
const levelDetails = levels[candidate].details;
|
385
390
|
if (levelDetails) {
|
386
391
|
const fragCandidate = findFragmentByPTS(
|
387
|
-
data.frag
|
392
|
+
data.frag,
|
388
393
|
levelDetails.fragments,
|
389
394
|
data.frag.start,
|
390
395
|
);
|
@@ -508,14 +513,3 @@ export default class ErrorController
|
|
508
513
|
}
|
509
514
|
}
|
510
515
|
}
|
511
|
-
|
512
|
-
export function createDoNothingErrorAction(resolved?: boolean): IErrorAction {
|
513
|
-
const errorAction: IErrorAction = {
|
514
|
-
action: NetworkErrorAction.DoNothing,
|
515
|
-
flags: ErrorActionFlags.None,
|
516
|
-
};
|
517
|
-
if (resolved) {
|
518
|
-
errorAction.resolved = true;
|
519
|
-
}
|
520
|
-
return errorAction;
|
521
|
-
}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { Events } from '../events';
|
2
|
+
import { logger } from '../utils/logger';
|
2
3
|
import type { ComponentAPI } from '../types/component-api';
|
3
4
|
import type Hls from '../hls';
|
4
5
|
import type { MediaAttachingData } from '../types/events';
|
@@ -27,12 +28,10 @@ class FPSController implements ComponentAPI {
|
|
27
28
|
|
28
29
|
protected registerListeners() {
|
29
30
|
this.hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
|
30
|
-
this.hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
31
31
|
}
|
32
32
|
|
33
33
|
protected unregisterListeners() {
|
34
34
|
this.hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);
|
35
|
-
this.hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
36
35
|
}
|
37
36
|
|
38
37
|
destroy() {
|
@@ -66,10 +65,6 @@ class FPSController implements ComponentAPI {
|
|
66
65
|
}
|
67
66
|
}
|
68
67
|
|
69
|
-
private onMediaDetaching() {
|
70
|
-
this.media = null;
|
71
|
-
}
|
72
|
-
|
73
68
|
checkFPS(
|
74
69
|
video: HTMLVideoElement,
|
75
70
|
decodedFrames: number,
|
@@ -89,13 +84,13 @@ class FPSController implements ComponentAPI {
|
|
89
84
|
totalDroppedFrames: droppedFrames,
|
90
85
|
});
|
91
86
|
if (droppedFPS > 0) {
|
92
|
-
//
|
87
|
+
// logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
|
93
88
|
if (
|
94
89
|
currentDropped >
|
95
90
|
hls.config.fpsDroppedMonitoringThreshold * currentDecoded
|
96
91
|
) {
|
97
92
|
let currentLevel = hls.currentLevel;
|
98
|
-
|
93
|
+
logger.warn(
|
99
94
|
'drop FPS ratio greater than max allowed value for currentLevel: ' +
|
100
95
|
currentLevel,
|
101
96
|
);
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import BinarySearch from '../utils/binary-search';
|
2
|
-
import
|
3
|
-
import type { LevelDetails } from '../loader/level-details';
|
2
|
+
import { Fragment } from '../loader/fragment';
|
4
3
|
|
5
4
|
/**
|
6
5
|
* Returns first fragment whose endPdt value exceeds the given PDT, or null.
|
@@ -9,10 +8,10 @@ import type { LevelDetails } from '../loader/level-details';
|
|
9
8
|
* @param maxFragLookUpTolerance - The amount of time that a fragment's start/end can be within in order to be considered contiguous
|
10
9
|
*/
|
11
10
|
export function findFragmentByPDT(
|
12
|
-
fragments:
|
11
|
+
fragments: Array<Fragment>,
|
13
12
|
PDTValue: number | null,
|
14
13
|
maxFragLookUpTolerance: number,
|
15
|
-
):
|
14
|
+
): Fragment | null {
|
16
15
|
if (
|
17
16
|
PDTValue === null ||
|
18
17
|
!Array.isArray(fragments) ||
|
@@ -55,27 +54,23 @@ export function findFragmentByPDT(
|
|
55
54
|
* @returns a matching fragment or null
|
56
55
|
*/
|
57
56
|
export function findFragmentByPTS(
|
58
|
-
fragPrevious:
|
59
|
-
fragments:
|
57
|
+
fragPrevious: Fragment | null,
|
58
|
+
fragments: Array<Fragment>,
|
60
59
|
bufferEnd: number = 0,
|
61
60
|
maxFragLookUpTolerance: number = 0,
|
62
61
|
nextFragLookupTolerance: number = 0.005,
|
63
|
-
):
|
64
|
-
let fragNext:
|
62
|
+
): Fragment | null {
|
63
|
+
let fragNext: Fragment | null = null;
|
65
64
|
if (fragPrevious) {
|
66
|
-
fragNext =
|
65
|
+
fragNext =
|
66
|
+
fragments[
|
67
|
+
(fragPrevious.sn as number) - (fragments[0].sn as number) + 1
|
68
|
+
] || null;
|
67
69
|
// check for buffer-end rounding error
|
68
|
-
const bufferEdgeError =
|
70
|
+
const bufferEdgeError = fragPrevious.endDTS - bufferEnd;
|
69
71
|
if (bufferEdgeError > 0 && bufferEdgeError < 0.0000015) {
|
70
72
|
bufferEnd += 0.0000015;
|
71
73
|
}
|
72
|
-
if (
|
73
|
-
fragNext &&
|
74
|
-
fragPrevious.level !== fragNext.level &&
|
75
|
-
fragNext.end <= fragPrevious.end
|
76
|
-
) {
|
77
|
-
fragNext = fragments[2 + fragPrevious.sn - fragments[0].sn] || null;
|
78
|
-
}
|
79
74
|
} else if (bufferEnd === 0 && fragments[0].start === 0) {
|
80
75
|
fragNext = fragments[0];
|
81
76
|
}
|
@@ -140,7 +135,7 @@ function fragmentWithinFastStartSwitch(
|
|
140
135
|
export function fragmentWithinToleranceTest(
|
141
136
|
bufferEnd = 0,
|
142
137
|
maxFragLookUpTolerance = 0,
|
143
|
-
candidate:
|
138
|
+
candidate: Fragment,
|
144
139
|
) {
|
145
140
|
// eagerly accept an accurate match (no tolerance)
|
146
141
|
if (
|
@@ -194,7 +189,7 @@ export function fragmentWithinToleranceTest(
|
|
194
189
|
export function pdtWithinToleranceTest(
|
195
190
|
pdtBufferEnd: number,
|
196
191
|
maxFragLookUpTolerance: number,
|
197
|
-
candidate:
|
192
|
+
candidate: Fragment,
|
198
193
|
): boolean {
|
199
194
|
const candidateLookupTolerance =
|
200
195
|
Math.min(
|
@@ -208,9 +203,9 @@ export function pdtWithinToleranceTest(
|
|
208
203
|
}
|
209
204
|
|
210
205
|
export function findFragWithCC(
|
211
|
-
fragments:
|
206
|
+
fragments: Fragment[],
|
212
207
|
cc: number,
|
213
|
-
):
|
208
|
+
): Fragment | null {
|
214
209
|
return BinarySearch.search(fragments, (candidate) => {
|
215
210
|
if (candidate.cc < cc) {
|
216
211
|
return 1;
|
@@ -221,26 +216,3 @@ export function findFragWithCC(
|
|
221
216
|
}
|
222
217
|
});
|
223
218
|
}
|
224
|
-
|
225
|
-
export function findNearestWithCC(
|
226
|
-
details: LevelDetails | undefined,
|
227
|
-
cc: number,
|
228
|
-
fragment: MediaFragment,
|
229
|
-
): MediaFragment | null {
|
230
|
-
if (details) {
|
231
|
-
if (details.startCC <= cc && details.endCC >= cc) {
|
232
|
-
const start = fragment.start;
|
233
|
-
const end = fragment.end;
|
234
|
-
return BinarySearch.search(details.fragments, (candidate) => {
|
235
|
-
if (candidate.cc < cc || candidate.end <= start) {
|
236
|
-
return 1;
|
237
|
-
} else if (candidate.cc > cc || candidate.start >= end) {
|
238
|
-
return -1;
|
239
|
-
} else {
|
240
|
-
return 0;
|
241
|
-
}
|
242
|
-
});
|
243
|
-
}
|
244
|
-
}
|
245
|
-
return null;
|
246
|
-
}
|