@zenvor/hls.js 1.0.0
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/LICENSE +28 -0
- package/README.md +472 -0
- package/dist/hls-demo.js +26995 -0
- package/dist/hls-demo.js.map +1 -0
- package/dist/hls.d.mts +4204 -0
- package/dist/hls.d.ts +4204 -0
- package/dist/hls.js +40050 -0
- package/dist/hls.js.d.ts +4204 -0
- package/dist/hls.js.map +1 -0
- package/dist/hls.light.js +27145 -0
- package/dist/hls.light.js.map +1 -0
- package/dist/hls.light.min.js +2 -0
- package/dist/hls.light.min.js.map +1 -0
- package/dist/hls.light.mjs +26392 -0
- package/dist/hls.light.mjs.map +1 -0
- package/dist/hls.min.js +2 -0
- package/dist/hls.min.js.map +1 -0
- package/dist/hls.mjs +38956 -0
- package/dist/hls.mjs.map +1 -0
- package/dist/hls.worker.js +2 -0
- package/dist/hls.worker.js.map +1 -0
- package/package.json +143 -0
- package/src/config.ts +794 -0
- package/src/controller/abr-controller.ts +1019 -0
- package/src/controller/algo-data-controller.ts +794 -0
- package/src/controller/audio-stream-controller.ts +1099 -0
- package/src/controller/audio-track-controller.ts +454 -0
- package/src/controller/base-playlist-controller.ts +438 -0
- package/src/controller/base-stream-controller.ts +2526 -0
- package/src/controller/buffer-controller.ts +2015 -0
- package/src/controller/buffer-operation-queue.ts +159 -0
- package/src/controller/cap-level-controller.ts +367 -0
- package/src/controller/cmcd-controller.ts +422 -0
- package/src/controller/content-steering-controller.ts +622 -0
- package/src/controller/eme-controller.ts +1617 -0
- package/src/controller/error-controller.ts +627 -0
- package/src/controller/fps-controller.ts +146 -0
- package/src/controller/fragment-finders.ts +256 -0
- package/src/controller/fragment-tracker.ts +567 -0
- package/src/controller/gap-controller.ts +719 -0
- package/src/controller/id3-track-controller.ts +488 -0
- package/src/controller/interstitial-player.ts +302 -0
- package/src/controller/interstitials-controller.ts +2895 -0
- package/src/controller/interstitials-schedule.ts +698 -0
- package/src/controller/latency-controller.ts +294 -0
- package/src/controller/level-controller.ts +776 -0
- package/src/controller/stream-controller.ts +1597 -0
- package/src/controller/subtitle-stream-controller.ts +508 -0
- package/src/controller/subtitle-track-controller.ts +617 -0
- package/src/controller/timeline-controller.ts +677 -0
- package/src/crypt/aes-crypto.ts +36 -0
- package/src/crypt/aes-decryptor.ts +339 -0
- package/src/crypt/decrypter-aes-mode.ts +4 -0
- package/src/crypt/decrypter.ts +225 -0
- package/src/crypt/fast-aes-key.ts +39 -0
- package/src/define-plugin.d.ts +17 -0
- package/src/demux/audio/aacdemuxer.ts +126 -0
- package/src/demux/audio/ac3-demuxer.ts +170 -0
- package/src/demux/audio/adts.ts +249 -0
- package/src/demux/audio/base-audio-demuxer.ts +205 -0
- package/src/demux/audio/dolby.ts +21 -0
- package/src/demux/audio/mp3demuxer.ts +85 -0
- package/src/demux/audio/mpegaudio.ts +177 -0
- package/src/demux/chunk-cache.ts +42 -0
- package/src/demux/dummy-demuxed-track.ts +13 -0
- package/src/demux/inject-worker.ts +75 -0
- package/src/demux/mp4demuxer.ts +234 -0
- package/src/demux/sample-aes.ts +198 -0
- package/src/demux/transmuxer-interface.ts +449 -0
- package/src/demux/transmuxer-worker.ts +221 -0
- package/src/demux/transmuxer.ts +560 -0
- package/src/demux/tsdemuxer.ts +1256 -0
- package/src/demux/video/avc-video-parser.ts +401 -0
- package/src/demux/video/base-video-parser.ts +198 -0
- package/src/demux/video/exp-golomb.ts +153 -0
- package/src/demux/video/hevc-video-parser.ts +736 -0
- package/src/empty-es.js +5 -0
- package/src/empty.js +3 -0
- package/src/errors.ts +107 -0
- package/src/events.ts +548 -0
- package/src/exports-default.ts +3 -0
- package/src/exports-named.ts +81 -0
- package/src/hls.ts +1613 -0
- package/src/is-supported.ts +54 -0
- package/src/loader/date-range.ts +207 -0
- package/src/loader/fragment-loader.ts +403 -0
- package/src/loader/fragment.ts +487 -0
- package/src/loader/interstitial-asset-list.ts +162 -0
- package/src/loader/interstitial-event.ts +337 -0
- package/src/loader/key-loader.ts +439 -0
- package/src/loader/level-details.ts +203 -0
- package/src/loader/level-key.ts +259 -0
- package/src/loader/load-stats.ts +17 -0
- package/src/loader/m3u8-parser.ts +1072 -0
- package/src/loader/playlist-loader.ts +839 -0
- package/src/polyfills/number.ts +15 -0
- package/src/remux/aac-helper.ts +81 -0
- package/src/remux/mp4-generator.ts +1380 -0
- package/src/remux/mp4-remuxer.ts +1261 -0
- package/src/remux/passthrough-remuxer.ts +434 -0
- package/src/task-loop.ts +130 -0
- package/src/types/algo.ts +44 -0
- package/src/types/buffer.ts +105 -0
- package/src/types/component-api.ts +20 -0
- package/src/types/demuxer.ts +208 -0
- package/src/types/events.ts +574 -0
- package/src/types/fragment-tracker.ts +23 -0
- package/src/types/level.ts +268 -0
- package/src/types/loader.ts +198 -0
- package/src/types/media-playlist.ts +92 -0
- package/src/types/network-details.ts +3 -0
- package/src/types/remuxer.ts +104 -0
- package/src/types/track.ts +12 -0
- package/src/types/transmuxer.ts +46 -0
- package/src/types/tuples.ts +6 -0
- package/src/types/vtt.ts +11 -0
- package/src/utils/arrays.ts +22 -0
- package/src/utils/attr-list.ts +192 -0
- package/src/utils/binary-search.ts +46 -0
- package/src/utils/buffer-helper.ts +173 -0
- package/src/utils/cea-608-parser.ts +1413 -0
- package/src/utils/chunker.ts +41 -0
- package/src/utils/codecs.ts +314 -0
- package/src/utils/cues.ts +96 -0
- package/src/utils/discontinuities.ts +174 -0
- package/src/utils/encryption-methods-util.ts +21 -0
- package/src/utils/error-helper.ts +95 -0
- package/src/utils/event-listener-helper.ts +16 -0
- package/src/utils/ewma-bandwidth-estimator.ts +97 -0
- package/src/utils/ewma.ts +43 -0
- package/src/utils/fetch-loader.ts +331 -0
- package/src/utils/global.ts +2 -0
- package/src/utils/hash.ts +10 -0
- package/src/utils/hdr.ts +67 -0
- package/src/utils/hex.ts +32 -0
- package/src/utils/imsc1-ttml-parser.ts +261 -0
- package/src/utils/keysystem-util.ts +45 -0
- package/src/utils/level-helper.ts +629 -0
- package/src/utils/logger.ts +120 -0
- package/src/utils/media-option-attributes.ts +49 -0
- package/src/utils/mediacapabilities-helper.ts +301 -0
- package/src/utils/mediakeys-helper.ts +210 -0
- package/src/utils/mediasource-helper.ts +37 -0
- package/src/utils/mp4-tools.ts +1473 -0
- package/src/utils/number.ts +3 -0
- package/src/utils/numeric-encoding-utils.ts +26 -0
- package/src/utils/output-filter.ts +46 -0
- package/src/utils/rendition-helper.ts +505 -0
- package/src/utils/safe-json-stringify.ts +22 -0
- package/src/utils/texttrack-utils.ts +164 -0
- package/src/utils/time-ranges.ts +17 -0
- package/src/utils/timescale-conversion.ts +46 -0
- package/src/utils/utf8-utils.ts +18 -0
- package/src/utils/variable-substitution.ts +105 -0
- package/src/utils/vttcue.ts +384 -0
- package/src/utils/vttparser.ts +497 -0
- package/src/utils/webvtt-parser.ts +166 -0
- package/src/utils/xhr-loader.ts +337 -0
- package/src/version.ts +1 -0
package/src/hls.ts
ADDED
|
@@ -0,0 +1,1613 @@
|
|
|
1
|
+
import { uuid } from '@svta/common-media-library/utils/uuid';
|
|
2
|
+
import { EventEmitter } from 'eventemitter3';
|
|
3
|
+
import { buildAbsoluteURL } from 'url-toolkit';
|
|
4
|
+
import { enableStreamingMode, hlsDefaultConfig, mergeConfig } from './config';
|
|
5
|
+
import AlgoDataController from './controller/algo-data-controller';
|
|
6
|
+
import { FragmentTracker } from './controller/fragment-tracker';
|
|
7
|
+
import GapController from './controller/gap-controller';
|
|
8
|
+
import ID3TrackController from './controller/id3-track-controller';
|
|
9
|
+
import LatencyController from './controller/latency-controller';
|
|
10
|
+
import LevelController from './controller/level-controller';
|
|
11
|
+
import StreamController from './controller/stream-controller';
|
|
12
|
+
import { ErrorDetails, ErrorTypes } from './errors';
|
|
13
|
+
import { Events } from './events';
|
|
14
|
+
import { isMSESupported, isSupported } from './is-supported';
|
|
15
|
+
import KeyLoader from './loader/key-loader';
|
|
16
|
+
import PlaylistLoader from './loader/playlist-loader';
|
|
17
|
+
import { MetadataSchema } from './types/demuxer';
|
|
18
|
+
import { type HdcpLevel, isHdcpLevel, type Level } from './types/level';
|
|
19
|
+
import { PlaylistLevelType } from './types/loader';
|
|
20
|
+
import { enableLogs, type ILogger } from './utils/logger';
|
|
21
|
+
import { getMediaDecodingInfoPromise } from './utils/mediacapabilities-helper';
|
|
22
|
+
import { getMediaSource } from './utils/mediasource-helper';
|
|
23
|
+
import { getAudioTracksByGroup } from './utils/rendition-helper';
|
|
24
|
+
import { version } from './version';
|
|
25
|
+
import type { HlsConfig } from './config';
|
|
26
|
+
import type AbrController from './controller/abr-controller';
|
|
27
|
+
import type AudioStreamController from './controller/audio-stream-controller';
|
|
28
|
+
import type AudioTrackController from './controller/audio-track-controller';
|
|
29
|
+
import type BasePlaylistController from './controller/base-playlist-controller';
|
|
30
|
+
import type { InFlightData, State } from './controller/base-stream-controller';
|
|
31
|
+
import type BaseStreamController from './controller/base-stream-controller';
|
|
32
|
+
import type BufferController from './controller/buffer-controller';
|
|
33
|
+
import type CapLevelController from './controller/cap-level-controller';
|
|
34
|
+
import type CMCDController from './controller/cmcd-controller';
|
|
35
|
+
import type ContentSteeringController from './controller/content-steering-controller';
|
|
36
|
+
import type EMEController from './controller/eme-controller';
|
|
37
|
+
import type ErrorController from './controller/error-controller';
|
|
38
|
+
import type FPSController from './controller/fps-controller';
|
|
39
|
+
import type InterstitialsController from './controller/interstitials-controller';
|
|
40
|
+
import type { InterstitialsManager } from './controller/interstitials-controller';
|
|
41
|
+
import type { SubtitleStreamController } from './controller/subtitle-stream-controller';
|
|
42
|
+
import type SubtitleTrackController from './controller/subtitle-track-controller';
|
|
43
|
+
import type Decrypter from './crypt/decrypter';
|
|
44
|
+
import type TransmuxerInterface from './demux/transmuxer-interface';
|
|
45
|
+
import type { HlsEventEmitter, HlsListeners } from './events';
|
|
46
|
+
import type FragmentLoader from './loader/fragment-loader';
|
|
47
|
+
import type { LevelDetails } from './loader/level-details';
|
|
48
|
+
import type M3U8Parser from './loader/m3u8-parser';
|
|
49
|
+
import type TaskLoop from './task-loop';
|
|
50
|
+
import type { AlgoChunk, FrameItem } from './types/algo';
|
|
51
|
+
import type { AttachMediaSourceData } from './types/buffer';
|
|
52
|
+
import type {
|
|
53
|
+
AbrComponentAPI,
|
|
54
|
+
ComponentAPI,
|
|
55
|
+
NetworkComponentAPI,
|
|
56
|
+
} from './types/component-api';
|
|
57
|
+
import type { MediaAttachingData } from './types/events';
|
|
58
|
+
import type {
|
|
59
|
+
AudioSelectionOption,
|
|
60
|
+
MediaPlaylist,
|
|
61
|
+
SubtitleSelectionOption,
|
|
62
|
+
VideoSelectionOption,
|
|
63
|
+
} from './types/media-playlist';
|
|
64
|
+
import type { BufferInfo, BufferTimeRange } from './utils/buffer-helper';
|
|
65
|
+
import type Cues from './utils/cues';
|
|
66
|
+
import type EwmaBandWidthEstimator from './utils/ewma-bandwidth-estimator';
|
|
67
|
+
import type FetchLoader from './utils/fetch-loader';
|
|
68
|
+
import type { MediaDecodingInfo } from './utils/mediacapabilities-helper';
|
|
69
|
+
import type XhrLoader from './utils/xhr-loader';
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The `Hls` class is the core of the HLS.js library used to instantiate player instances.
|
|
73
|
+
* @public
|
|
74
|
+
*/
|
|
75
|
+
export default class Hls implements HlsEventEmitter {
|
|
76
|
+
private static defaultConfig: HlsConfig | undefined;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The runtime configuration used by the player. At instantiation this is combination of `hls.userConfig` merged over `Hls.DefaultConfig`.
|
|
80
|
+
*/
|
|
81
|
+
public readonly config: HlsConfig;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The configuration object provided on player instantiation.
|
|
85
|
+
*/
|
|
86
|
+
public readonly userConfig: Partial<HlsConfig>;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The logger functions used by this player instance, configured on player instantiation.
|
|
90
|
+
*/
|
|
91
|
+
public readonly logger: ILogger;
|
|
92
|
+
|
|
93
|
+
private coreComponents: ComponentAPI[];
|
|
94
|
+
private networkControllers: NetworkComponentAPI[];
|
|
95
|
+
private _emitter: HlsEventEmitter = new EventEmitter();
|
|
96
|
+
private _autoLevelCapping: number = -1;
|
|
97
|
+
private _maxHdcpLevel: HdcpLevel = null;
|
|
98
|
+
private abrController: AbrComponentAPI;
|
|
99
|
+
private bufferController: BufferController;
|
|
100
|
+
private capLevelController: CapLevelController;
|
|
101
|
+
private latencyController: LatencyController;
|
|
102
|
+
private levelController: LevelController;
|
|
103
|
+
private streamController: StreamController;
|
|
104
|
+
private algoDataController?: AlgoDataController;
|
|
105
|
+
private audioStreamController?: AudioStreamController;
|
|
106
|
+
private subtititleStreamController?: SubtitleStreamController;
|
|
107
|
+
private audioTrackController?: AudioTrackController;
|
|
108
|
+
private subtitleTrackController?: SubtitleTrackController;
|
|
109
|
+
private interstitialsController?: InterstitialsController;
|
|
110
|
+
private gapController: GapController;
|
|
111
|
+
private emeController?: EMEController;
|
|
112
|
+
private cmcdController?: CMCDController;
|
|
113
|
+
private _media: HTMLMediaElement | null = null;
|
|
114
|
+
private _url: string | null = null;
|
|
115
|
+
private _sessionId?: string;
|
|
116
|
+
private triggeringException?: boolean;
|
|
117
|
+
private started: boolean = false;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get the video-dev/hls.js package version.
|
|
121
|
+
*/
|
|
122
|
+
static get version(): string {
|
|
123
|
+
return version;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Check if the required MediaSource Extensions are available.
|
|
128
|
+
*/
|
|
129
|
+
static isMSESupported(): boolean {
|
|
130
|
+
return isMSESupported();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Check if MediaSource Extensions are available and isTypeSupported checks pass for any baseline codecs.
|
|
135
|
+
*/
|
|
136
|
+
static isSupported(): boolean {
|
|
137
|
+
return isSupported();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Get the MediaSource global used for MSE playback (ManagedMediaSource, MediaSource, or WebKitMediaSource).
|
|
142
|
+
*/
|
|
143
|
+
static getMediaSource(): typeof MediaSource | undefined {
|
|
144
|
+
return getMediaSource();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
static get Events(): typeof Events {
|
|
148
|
+
return Events;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static get MetadataSchema(): typeof MetadataSchema {
|
|
152
|
+
return MetadataSchema;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
static get ErrorTypes(): typeof ErrorTypes {
|
|
156
|
+
return ErrorTypes;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
static get ErrorDetails(): typeof ErrorDetails {
|
|
160
|
+
return ErrorDetails;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Get the default configuration applied to new instances.
|
|
165
|
+
*/
|
|
166
|
+
static get DefaultConfig(): HlsConfig {
|
|
167
|
+
if (!Hls.defaultConfig) {
|
|
168
|
+
return hlsDefaultConfig;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return Hls.defaultConfig;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Replace the default configuration applied to new instances.
|
|
176
|
+
*/
|
|
177
|
+
static set DefaultConfig(defaultConfig: HlsConfig) {
|
|
178
|
+
Hls.defaultConfig = defaultConfig;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Creates an instance of an HLS client that can attach to exactly one `HTMLMediaElement`.
|
|
183
|
+
* @param userConfig - Configuration options applied over `Hls.DefaultConfig`
|
|
184
|
+
*/
|
|
185
|
+
constructor(userConfig: Partial<HlsConfig> = {}) {
|
|
186
|
+
const logger = (this.logger = enableLogs(
|
|
187
|
+
userConfig.debug || false,
|
|
188
|
+
'Hls instance',
|
|
189
|
+
userConfig.assetPlayerId,
|
|
190
|
+
));
|
|
191
|
+
const config = (this.config = mergeConfig(
|
|
192
|
+
Hls.DefaultConfig,
|
|
193
|
+
userConfig,
|
|
194
|
+
logger,
|
|
195
|
+
));
|
|
196
|
+
this.userConfig = userConfig;
|
|
197
|
+
|
|
198
|
+
if (config.progressive) {
|
|
199
|
+
enableStreamingMode(config, logger);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// core controllers and network loaders
|
|
203
|
+
const {
|
|
204
|
+
abrController: _AbrController,
|
|
205
|
+
bufferController: _BufferController,
|
|
206
|
+
capLevelController: _CapLevelController,
|
|
207
|
+
errorController: _ErrorController,
|
|
208
|
+
fpsController: _FpsController,
|
|
209
|
+
} = config;
|
|
210
|
+
const errorController = new _ErrorController(this);
|
|
211
|
+
const abrController = (this.abrController = new _AbrController(this));
|
|
212
|
+
// FragmentTracker must be defined before StreamController because the order of event handling is important
|
|
213
|
+
const fragmentTracker = new FragmentTracker(this);
|
|
214
|
+
const _InterstitialsController = config.interstitialsController;
|
|
215
|
+
const interstitialsController = _InterstitialsController
|
|
216
|
+
? (this.interstitialsController = new _InterstitialsController(this, Hls))
|
|
217
|
+
: null;
|
|
218
|
+
const bufferController = (this.bufferController = new _BufferController(
|
|
219
|
+
this,
|
|
220
|
+
fragmentTracker,
|
|
221
|
+
));
|
|
222
|
+
const capLevelController = (this.capLevelController =
|
|
223
|
+
new _CapLevelController(this));
|
|
224
|
+
|
|
225
|
+
const fpsController = new _FpsController(this);
|
|
226
|
+
const playListLoader = new PlaylistLoader(this);
|
|
227
|
+
|
|
228
|
+
const _ContentSteeringController = config.contentSteeringController;
|
|
229
|
+
// Instantiate ConentSteeringController before LevelController to receive Multivariant Playlist events first
|
|
230
|
+
const contentSteering = _ContentSteeringController
|
|
231
|
+
? new _ContentSteeringController(this)
|
|
232
|
+
: null;
|
|
233
|
+
const levelController = (this.levelController = new LevelController(
|
|
234
|
+
this,
|
|
235
|
+
contentSteering,
|
|
236
|
+
));
|
|
237
|
+
|
|
238
|
+
const id3TrackController = new ID3TrackController(this);
|
|
239
|
+
const keyLoader = new KeyLoader(this.config, this.logger);
|
|
240
|
+
const streamController = (this.streamController = new StreamController(
|
|
241
|
+
this,
|
|
242
|
+
fragmentTracker,
|
|
243
|
+
keyLoader,
|
|
244
|
+
));
|
|
245
|
+
|
|
246
|
+
const algoDataController = config.algoDataEnabled
|
|
247
|
+
? (this.algoDataController = new AlgoDataController(this))
|
|
248
|
+
: null;
|
|
249
|
+
|
|
250
|
+
const gapController = (this.gapController = new GapController(
|
|
251
|
+
this,
|
|
252
|
+
fragmentTracker,
|
|
253
|
+
));
|
|
254
|
+
|
|
255
|
+
// Cap level controller uses streamController to flush the buffer
|
|
256
|
+
capLevelController.setStreamController(streamController);
|
|
257
|
+
// fpsController uses streamController to switch when frames are being dropped
|
|
258
|
+
fpsController.setStreamController(streamController);
|
|
259
|
+
|
|
260
|
+
const networkControllers: NetworkComponentAPI[] = [
|
|
261
|
+
playListLoader,
|
|
262
|
+
levelController,
|
|
263
|
+
streamController,
|
|
264
|
+
];
|
|
265
|
+
if (algoDataController) {
|
|
266
|
+
networkControllers.push(algoDataController);
|
|
267
|
+
}
|
|
268
|
+
if (interstitialsController) {
|
|
269
|
+
networkControllers.splice(1, 0, interstitialsController);
|
|
270
|
+
}
|
|
271
|
+
if (contentSteering) {
|
|
272
|
+
networkControllers.splice(1, 0, contentSteering);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
this.networkControllers = networkControllers;
|
|
276
|
+
const coreComponents: ComponentAPI[] = [
|
|
277
|
+
abrController,
|
|
278
|
+
bufferController,
|
|
279
|
+
gapController,
|
|
280
|
+
capLevelController,
|
|
281
|
+
fpsController,
|
|
282
|
+
id3TrackController,
|
|
283
|
+
fragmentTracker,
|
|
284
|
+
];
|
|
285
|
+
|
|
286
|
+
this.audioTrackController = this.createController(
|
|
287
|
+
config.audioTrackController,
|
|
288
|
+
networkControllers,
|
|
289
|
+
);
|
|
290
|
+
const AudioStreamControllerClass = config.audioStreamController;
|
|
291
|
+
if (AudioStreamControllerClass) {
|
|
292
|
+
networkControllers.push(
|
|
293
|
+
(this.audioStreamController = new AudioStreamControllerClass(
|
|
294
|
+
this,
|
|
295
|
+
fragmentTracker,
|
|
296
|
+
keyLoader,
|
|
297
|
+
)),
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
// Instantiate subtitleTrackController before SubtitleStreamController to receive level events first
|
|
301
|
+
this.subtitleTrackController = this.createController(
|
|
302
|
+
config.subtitleTrackController,
|
|
303
|
+
networkControllers,
|
|
304
|
+
);
|
|
305
|
+
const SubtitleStreamControllerClass = config.subtitleStreamController;
|
|
306
|
+
if (SubtitleStreamControllerClass) {
|
|
307
|
+
networkControllers.push(
|
|
308
|
+
(this.subtititleStreamController = new SubtitleStreamControllerClass(
|
|
309
|
+
this,
|
|
310
|
+
fragmentTracker,
|
|
311
|
+
keyLoader,
|
|
312
|
+
)),
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
this.createController(config.timelineController, coreComponents);
|
|
316
|
+
keyLoader.emeController = this.emeController = this.createController(
|
|
317
|
+
config.emeController,
|
|
318
|
+
coreComponents,
|
|
319
|
+
);
|
|
320
|
+
this.cmcdController = this.createController(
|
|
321
|
+
config.cmcdController,
|
|
322
|
+
coreComponents,
|
|
323
|
+
);
|
|
324
|
+
this.latencyController = this.createController(
|
|
325
|
+
LatencyController,
|
|
326
|
+
coreComponents,
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
this.coreComponents = coreComponents;
|
|
330
|
+
|
|
331
|
+
// Error controller handles errors before and after all other controllers
|
|
332
|
+
// This listener will be invoked after all other controllers error listeners
|
|
333
|
+
networkControllers.push(errorController);
|
|
334
|
+
const onErrorOut = errorController.onErrorOut;
|
|
335
|
+
if (typeof onErrorOut === 'function') {
|
|
336
|
+
this.on(Events.ERROR, onErrorOut, errorController);
|
|
337
|
+
}
|
|
338
|
+
// Autostart load handler
|
|
339
|
+
this.on(
|
|
340
|
+
Events.MANIFEST_LOADED,
|
|
341
|
+
playListLoader.onManifestLoaded,
|
|
342
|
+
playListLoader,
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
createController(ControllerClass, components) {
|
|
347
|
+
if (ControllerClass) {
|
|
348
|
+
const controllerInstance = new ControllerClass(this);
|
|
349
|
+
if (components) {
|
|
350
|
+
components.push(controllerInstance);
|
|
351
|
+
}
|
|
352
|
+
return controllerInstance;
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Delegate the EventEmitter through the public API of Hls.js
|
|
358
|
+
on<E extends keyof HlsListeners, Context = undefined>(
|
|
359
|
+
event: E,
|
|
360
|
+
listener: HlsListeners[E],
|
|
361
|
+
context: Context = this as any,
|
|
362
|
+
) {
|
|
363
|
+
this._emitter.on(event, listener, context);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
once<E extends keyof HlsListeners, Context = undefined>(
|
|
367
|
+
event: E,
|
|
368
|
+
listener: HlsListeners[E],
|
|
369
|
+
context: Context = this as any,
|
|
370
|
+
) {
|
|
371
|
+
this._emitter.once(event, listener, context);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
removeAllListeners<E extends keyof HlsListeners>(event?: E | undefined) {
|
|
375
|
+
this._emitter.removeAllListeners(event);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
off<E extends keyof HlsListeners, Context = undefined>(
|
|
379
|
+
event: E,
|
|
380
|
+
listener?: HlsListeners[E] | undefined,
|
|
381
|
+
context: Context = this as any,
|
|
382
|
+
once?: boolean | undefined,
|
|
383
|
+
) {
|
|
384
|
+
this._emitter.off(event, listener, context, once);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
listeners<E extends keyof HlsListeners>(event: E): HlsListeners[E][] {
|
|
388
|
+
return this._emitter.listeners(event);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
emit<E extends keyof HlsListeners>(
|
|
392
|
+
event: E,
|
|
393
|
+
name: E,
|
|
394
|
+
eventObject: Parameters<HlsListeners[E]>[1],
|
|
395
|
+
): boolean {
|
|
396
|
+
return this._emitter.emit(event, name, eventObject);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
trigger<E extends keyof HlsListeners>(
|
|
400
|
+
event: E,
|
|
401
|
+
eventObject: Parameters<HlsListeners[E]>[1],
|
|
402
|
+
): boolean {
|
|
403
|
+
if (this.config.debug) {
|
|
404
|
+
return this.emit(event, event, eventObject);
|
|
405
|
+
} else {
|
|
406
|
+
try {
|
|
407
|
+
return this.emit(event, event, eventObject);
|
|
408
|
+
} catch (error) {
|
|
409
|
+
this.logger.error(
|
|
410
|
+
'An internal error happened while handling event ' +
|
|
411
|
+
event +
|
|
412
|
+
'. Error message: "' +
|
|
413
|
+
error.message +
|
|
414
|
+
'". Here is a stacktrace:',
|
|
415
|
+
error,
|
|
416
|
+
);
|
|
417
|
+
// Prevent recursion in error event handlers that throw #5497
|
|
418
|
+
if (!this.triggeringException) {
|
|
419
|
+
this.triggeringException = true;
|
|
420
|
+
const fatal = event === Events.ERROR;
|
|
421
|
+
this.trigger(Events.ERROR, {
|
|
422
|
+
type: ErrorTypes.OTHER_ERROR,
|
|
423
|
+
details: ErrorDetails.INTERNAL_EXCEPTION,
|
|
424
|
+
fatal,
|
|
425
|
+
event,
|
|
426
|
+
error,
|
|
427
|
+
});
|
|
428
|
+
this.triggeringException = false;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
listenerCount<E extends keyof HlsListeners>(event: E): number {
|
|
436
|
+
return this._emitter.listenerCount(event);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Dispose of the instance
|
|
441
|
+
*/
|
|
442
|
+
destroy() {
|
|
443
|
+
this.logger.log('destroy');
|
|
444
|
+
this.trigger(Events.DESTROYING, undefined);
|
|
445
|
+
this.detachMedia();
|
|
446
|
+
this.removeAllListeners();
|
|
447
|
+
this._autoLevelCapping = -1;
|
|
448
|
+
this._url = null;
|
|
449
|
+
|
|
450
|
+
this.networkControllers.forEach((component) => component.destroy());
|
|
451
|
+
this.networkControllers.length = 0;
|
|
452
|
+
|
|
453
|
+
this.coreComponents.forEach((component) => component.destroy());
|
|
454
|
+
this.coreComponents.length = 0;
|
|
455
|
+
// Remove any references that could be held in config options or callbacks
|
|
456
|
+
const config = this.config;
|
|
457
|
+
config.xhrSetup = config.fetchSetup = undefined;
|
|
458
|
+
// @ts-ignore
|
|
459
|
+
this.userConfig = null;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Attaches Hls.js to a media element
|
|
464
|
+
*/
|
|
465
|
+
attachMedia(data: HTMLMediaElement | MediaAttachingData) {
|
|
466
|
+
if (!data || ('media' in data && !data.media)) {
|
|
467
|
+
const error = new Error(`attachMedia failed: invalid argument (${data})`);
|
|
468
|
+
this.trigger(Events.ERROR, {
|
|
469
|
+
type: ErrorTypes.OTHER_ERROR,
|
|
470
|
+
details: ErrorDetails.ATTACH_MEDIA_ERROR,
|
|
471
|
+
fatal: true,
|
|
472
|
+
error,
|
|
473
|
+
});
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
this.logger.log(`attachMedia`);
|
|
477
|
+
if (this._media) {
|
|
478
|
+
this.logger.warn(`media must be detached before attaching`);
|
|
479
|
+
this.detachMedia();
|
|
480
|
+
}
|
|
481
|
+
const attachMediaSource = 'media' in data;
|
|
482
|
+
const media = attachMediaSource ? data.media : data;
|
|
483
|
+
const attachingData = attachMediaSource ? data : { media };
|
|
484
|
+
this._media = media;
|
|
485
|
+
this.trigger(Events.MEDIA_ATTACHING, attachingData);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Detach Hls.js from the media
|
|
490
|
+
*/
|
|
491
|
+
detachMedia() {
|
|
492
|
+
this.logger.log('detachMedia');
|
|
493
|
+
const data = {};
|
|
494
|
+
this.trigger(Events.MEDIA_DETACHING, data);
|
|
495
|
+
this._media = null;
|
|
496
|
+
this.trigger(Events.MEDIA_DETACHED, data);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Detach HTMLMediaElement, MediaSource, and SourceBuffers without reset, for attaching to another instance
|
|
501
|
+
*/
|
|
502
|
+
transferMedia(): AttachMediaSourceData | null {
|
|
503
|
+
this._media = null;
|
|
504
|
+
const transferMedia = this.bufferController.transferMedia();
|
|
505
|
+
const data = { transferMedia };
|
|
506
|
+
this.trigger(Events.MEDIA_DETACHING, data);
|
|
507
|
+
this.trigger(Events.MEDIA_DETACHED, data);
|
|
508
|
+
return transferMedia;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Set the source URL. Can be relative or absolute.
|
|
513
|
+
*/
|
|
514
|
+
loadSource(url: string) {
|
|
515
|
+
this.stopLoad();
|
|
516
|
+
const media = this.media;
|
|
517
|
+
const loadedSource = this._url;
|
|
518
|
+
const loadingSource = (this._url = buildAbsoluteURL(
|
|
519
|
+
self.location.href,
|
|
520
|
+
url,
|
|
521
|
+
{
|
|
522
|
+
alwaysNormalize: true,
|
|
523
|
+
},
|
|
524
|
+
));
|
|
525
|
+
this._autoLevelCapping = -1;
|
|
526
|
+
this._maxHdcpLevel = null;
|
|
527
|
+
this.logger.log(`loadSource:${loadingSource}`);
|
|
528
|
+
if (
|
|
529
|
+
media &&
|
|
530
|
+
loadedSource &&
|
|
531
|
+
(loadedSource !== loadingSource || this.bufferController.hasSourceTypes())
|
|
532
|
+
) {
|
|
533
|
+
// Remove and re-create MediaSource
|
|
534
|
+
this.detachMedia();
|
|
535
|
+
this.attachMedia(media);
|
|
536
|
+
}
|
|
537
|
+
// when attaching to a source URL, trigger a playlist load
|
|
538
|
+
this.trigger(Events.MANIFEST_LOADING, { url: url });
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Gets the currently loaded URL
|
|
543
|
+
*/
|
|
544
|
+
public get url(): string | null {
|
|
545
|
+
return this._url;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Whether or not enough has been buffered to seek to start position or use `media.currentTime` to determine next load position
|
|
550
|
+
*/
|
|
551
|
+
get hasEnoughToStart(): boolean {
|
|
552
|
+
return this.streamController.hasEnoughToStart;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Get the startPosition set on startLoad(position) or on autostart with config.startPosition
|
|
557
|
+
*/
|
|
558
|
+
get startPosition(): number {
|
|
559
|
+
return this.streamController.startPositionValue;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Start loading data from the stream source.
|
|
564
|
+
* Depending on default config, client starts loading automatically when a source is set.
|
|
565
|
+
*
|
|
566
|
+
* @param startPosition - Set the start position to stream from.
|
|
567
|
+
* Defaults to -1 (None: starts from earliest point)
|
|
568
|
+
*/
|
|
569
|
+
startLoad(startPosition: number = -1, skipSeekToStartPosition?: boolean) {
|
|
570
|
+
this.logger.log(
|
|
571
|
+
`startLoad(${
|
|
572
|
+
startPosition +
|
|
573
|
+
(skipSeekToStartPosition ? ', <skip seek to start>' : '')
|
|
574
|
+
})`,
|
|
575
|
+
);
|
|
576
|
+
this.started = true;
|
|
577
|
+
this.resumeBuffering();
|
|
578
|
+
for (let i = 0; i < this.networkControllers.length; i++) {
|
|
579
|
+
this.networkControllers[i].startLoad(
|
|
580
|
+
startPosition,
|
|
581
|
+
skipSeekToStartPosition,
|
|
582
|
+
);
|
|
583
|
+
if (!this.started || !this.networkControllers) {
|
|
584
|
+
break;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Stop loading of any stream data.
|
|
591
|
+
*/
|
|
592
|
+
stopLoad() {
|
|
593
|
+
this.logger.log('stopLoad');
|
|
594
|
+
this.started = false;
|
|
595
|
+
for (let i = 0; i < this.networkControllers.length; i++) {
|
|
596
|
+
this.networkControllers[i].stopLoad();
|
|
597
|
+
if (this.started || !this.networkControllers) {
|
|
598
|
+
break;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Returns whether loading, toggled with `startLoad()` and `stopLoad()`, is active or not`.
|
|
605
|
+
*/
|
|
606
|
+
get loadingEnabled(): boolean {
|
|
607
|
+
return this.started;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* 根据时间获取算法帧数据
|
|
612
|
+
*/
|
|
613
|
+
getAlgoFrameByTime(time: number): FrameItem | null {
|
|
614
|
+
return this.algoDataController?.getFrameByTime(time) || null;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* 根据帧索引获取算法帧数据(1-based)
|
|
619
|
+
*/
|
|
620
|
+
getAlgoFrameByIndex(frameIdx: number): FrameItem | null {
|
|
621
|
+
return this.algoDataController?.getFrameByIndex(frameIdx) || null;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* 判断时间点的算法数据是否已就绪
|
|
626
|
+
*/
|
|
627
|
+
isAlgoDataReady(time: number): boolean {
|
|
628
|
+
return this.algoDataController?.isDataReady(time) || false;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* 判断帧索引的算法数据是否已就绪(1-based)
|
|
633
|
+
*/
|
|
634
|
+
isAlgoDataReadyByIndex(frameIdx: number): boolean {
|
|
635
|
+
return this.algoDataController?.isDataReadyByIndex(frameIdx) || false;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
getAllCachedAlgoChunks(): AlgoChunk[] {
|
|
639
|
+
return this.algoDataController?.getAllCachedChunks() ?? [];
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Returns state of fragment loading toggled by calling `pauseBuffering()` and `resumeBuffering()`.
|
|
644
|
+
*/
|
|
645
|
+
get bufferingEnabled(): boolean {
|
|
646
|
+
return this.streamController.bufferingEnabled;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Resumes stream controller segment loading after `pauseBuffering` has been called.
|
|
651
|
+
*/
|
|
652
|
+
resumeBuffering() {
|
|
653
|
+
if (!this.bufferingEnabled) {
|
|
654
|
+
this.logger.log(`resume buffering`);
|
|
655
|
+
this.networkControllers.forEach((controller) => {
|
|
656
|
+
if (controller.resumeBuffering) {
|
|
657
|
+
controller.resumeBuffering();
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Prevents stream controller from loading new segments until `resumeBuffering` is called.
|
|
665
|
+
* This allows for media buffering to be paused without interupting playlist loading.
|
|
666
|
+
*/
|
|
667
|
+
pauseBuffering() {
|
|
668
|
+
if (this.bufferingEnabled) {
|
|
669
|
+
this.logger.log(`pause buffering`);
|
|
670
|
+
this.networkControllers.forEach((controller) => {
|
|
671
|
+
if (controller.pauseBuffering) {
|
|
672
|
+
controller.pauseBuffering();
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
get inFlightFragments(): InFlightFragments {
|
|
679
|
+
const inFlightData = {
|
|
680
|
+
[PlaylistLevelType.MAIN]: this.streamController.inFlightFrag,
|
|
681
|
+
};
|
|
682
|
+
if (this.audioStreamController) {
|
|
683
|
+
inFlightData[PlaylistLevelType.AUDIO] =
|
|
684
|
+
this.audioStreamController.inFlightFrag;
|
|
685
|
+
}
|
|
686
|
+
if (this.subtititleStreamController) {
|
|
687
|
+
inFlightData[PlaylistLevelType.SUBTITLE] =
|
|
688
|
+
this.subtititleStreamController.inFlightFrag;
|
|
689
|
+
}
|
|
690
|
+
return inFlightData;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
|
|
695
|
+
*/
|
|
696
|
+
swapAudioCodec() {
|
|
697
|
+
this.logger.log('swapAudioCodec');
|
|
698
|
+
this.streamController.swapAudioCodec();
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* When the media-element fails, this allows to detach and then re-attach it
|
|
703
|
+
* as one call (convenience method).
|
|
704
|
+
*
|
|
705
|
+
* Automatic recovery of media-errors by this process is configurable.
|
|
706
|
+
*/
|
|
707
|
+
recoverMediaError() {
|
|
708
|
+
this.logger.log('recoverMediaError');
|
|
709
|
+
const media = this._media;
|
|
710
|
+
const started = this.started;
|
|
711
|
+
const time = media?.currentTime;
|
|
712
|
+
this.detachMedia();
|
|
713
|
+
if (media) {
|
|
714
|
+
this.attachMedia(media);
|
|
715
|
+
if (started) {
|
|
716
|
+
if (time) {
|
|
717
|
+
this.startLoad(time);
|
|
718
|
+
} else if (!this.config.autoStartLoad) {
|
|
719
|
+
this.startLoad();
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
removeLevel(levelIndex: number) {
|
|
726
|
+
this.levelController.removeLevel(levelIndex);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* @returns a UUID for this player instance
|
|
731
|
+
*/
|
|
732
|
+
get sessionId(): string {
|
|
733
|
+
let _sessionId = this._sessionId;
|
|
734
|
+
if (!_sessionId) {
|
|
735
|
+
_sessionId = this._sessionId = uuid();
|
|
736
|
+
}
|
|
737
|
+
return _sessionId;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* @returns an array of levels (variants) sorted by HDCP-LEVEL, RESOLUTION (height), FRAME-RATE, CODECS, VIDEO-RANGE, and BANDWIDTH
|
|
742
|
+
*/
|
|
743
|
+
get levels(): Level[] {
|
|
744
|
+
const levels = this.levelController.levels;
|
|
745
|
+
return levels ? levels : [];
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* @returns LevelDetails of last loaded level (variant) or `null` prior to loading a media playlist.
|
|
750
|
+
*/
|
|
751
|
+
get latestLevelDetails(): LevelDetails | null {
|
|
752
|
+
return this.streamController.getLevelDetails() || null;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* @returns Level object of selected level (variant) or `null` prior to selecting a level or once the level is removed.
|
|
757
|
+
*/
|
|
758
|
+
get loadLevelObj(): Level | null {
|
|
759
|
+
return this.levelController.loadLevelObj;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Index of quality level (variant) currently played
|
|
764
|
+
*/
|
|
765
|
+
get currentLevel(): number {
|
|
766
|
+
return this.streamController.currentLevel;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* Set quality level index immediately. This will flush the current buffer to replace the quality asap. That means playback will interrupt at least shortly to re-buffer and re-sync eventually. Set to -1 for automatic level selection.
|
|
771
|
+
*/
|
|
772
|
+
set currentLevel(newLevel: number) {
|
|
773
|
+
this.logger.log(`set currentLevel:${newLevel}`);
|
|
774
|
+
this.levelController.manualLevel = newLevel;
|
|
775
|
+
this.streamController.immediateLevelSwitch();
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Index of next quality level loaded as scheduled by stream controller.
|
|
780
|
+
*/
|
|
781
|
+
get nextLevel(): number {
|
|
782
|
+
return this.streamController.nextLevel;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* Set quality level index for next loaded data.
|
|
787
|
+
* This will switch the video quality asap, without interrupting playback.
|
|
788
|
+
* May abort current loading of data, and flush parts of buffer (outside currently played fragment region).
|
|
789
|
+
* @param newLevel - Pass -1 for automatic level selection
|
|
790
|
+
*/
|
|
791
|
+
set nextLevel(newLevel: number) {
|
|
792
|
+
this.logger.log(`set nextLevel:${newLevel}`);
|
|
793
|
+
this.levelController.manualLevel = newLevel;
|
|
794
|
+
this.streamController.nextLevelSwitch();
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Return the quality level of the currently or last (of none is loaded currently) segment
|
|
799
|
+
*/
|
|
800
|
+
get loadLevel(): number {
|
|
801
|
+
return this.levelController.level;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Set quality level index for next loaded data in a conservative way.
|
|
806
|
+
* This will switch the quality without flushing, but interrupt current loading.
|
|
807
|
+
* Thus the moment when the quality switch will appear in effect will only be after the already existing buffer.
|
|
808
|
+
* @param newLevel - Pass -1 for automatic level selection
|
|
809
|
+
*/
|
|
810
|
+
set loadLevel(newLevel: number) {
|
|
811
|
+
this.logger.log(`set loadLevel:${newLevel}`);
|
|
812
|
+
this.levelController.manualLevel = newLevel;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* get next quality level loaded
|
|
817
|
+
*/
|
|
818
|
+
get nextLoadLevel(): number {
|
|
819
|
+
return this.levelController.nextLoadLevel;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/**
|
|
823
|
+
* Set quality level of next loaded segment in a fully "non-destructive" way.
|
|
824
|
+
* Same as `loadLevel` but will wait for next switch (until current loading is done).
|
|
825
|
+
*/
|
|
826
|
+
set nextLoadLevel(level: number) {
|
|
827
|
+
this.levelController.nextLoadLevel = level;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
/**
|
|
831
|
+
* Return "first level": like a default level, if not set,
|
|
832
|
+
* falls back to index of first level referenced in manifest
|
|
833
|
+
*/
|
|
834
|
+
get firstLevel(): number {
|
|
835
|
+
return Math.max(this.levelController.firstLevel, this.minAutoLevel);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* Sets "first-level", see getter.
|
|
840
|
+
*/
|
|
841
|
+
set firstLevel(newLevel: number) {
|
|
842
|
+
this.logger.log(`set firstLevel:${newLevel}`);
|
|
843
|
+
this.levelController.firstLevel = newLevel;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* Return the desired start level for the first fragment that will be loaded.
|
|
848
|
+
* The default value of -1 indicates automatic start level selection.
|
|
849
|
+
* Setting hls.nextAutoLevel without setting a startLevel will result in
|
|
850
|
+
* the nextAutoLevel value being used for one fragment load.
|
|
851
|
+
*/
|
|
852
|
+
get startLevel(): number {
|
|
853
|
+
const startLevel = this.levelController.startLevel;
|
|
854
|
+
if (startLevel === -1 && this.abrController.forcedAutoLevel > -1) {
|
|
855
|
+
return this.abrController.forcedAutoLevel;
|
|
856
|
+
}
|
|
857
|
+
return startLevel;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
/**
|
|
861
|
+
* set start level (level of first fragment that will be played back)
|
|
862
|
+
* if not overrided by user, first level appearing in manifest will be used as start level
|
|
863
|
+
* if -1 : automatic start level selection, playback will start from level matching download bandwidth
|
|
864
|
+
* (determined from download of first segment)
|
|
865
|
+
*/
|
|
866
|
+
set startLevel(newLevel: number) {
|
|
867
|
+
this.logger.log(`set startLevel:${newLevel}`);
|
|
868
|
+
// if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
|
|
869
|
+
if (newLevel !== -1) {
|
|
870
|
+
newLevel = Math.max(newLevel, this.minAutoLevel);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
this.levelController.startLevel = newLevel;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* Whether level capping is enabled.
|
|
878
|
+
* Default value is set via `config.capLevelToPlayerSize`.
|
|
879
|
+
*/
|
|
880
|
+
get capLevelToPlayerSize(): boolean {
|
|
881
|
+
return this.config.capLevelToPlayerSize;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
* Enables or disables level capping. If disabled after previously enabled, `nextLevelSwitch` will be immediately called.
|
|
886
|
+
*/
|
|
887
|
+
set capLevelToPlayerSize(shouldStartCapping: boolean) {
|
|
888
|
+
const newCapLevelToPlayerSize = !!shouldStartCapping;
|
|
889
|
+
|
|
890
|
+
if (newCapLevelToPlayerSize !== this.config.capLevelToPlayerSize) {
|
|
891
|
+
if (newCapLevelToPlayerSize) {
|
|
892
|
+
this.capLevelController.startCapping(); // If capping occurs, nextLevelSwitch will happen based on size.
|
|
893
|
+
} else {
|
|
894
|
+
this.capLevelController.stopCapping();
|
|
895
|
+
this.autoLevelCapping = -1;
|
|
896
|
+
this.streamController.nextLevelSwitch(); // Now we're uncapped, get the next level asap.
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
this.config.capLevelToPlayerSize = newCapLevelToPlayerSize;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Capping/max level value that should be used by automatic level selection algorithm (`ABRController`)
|
|
905
|
+
*/
|
|
906
|
+
get autoLevelCapping(): number {
|
|
907
|
+
return this._autoLevelCapping;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
/**
|
|
911
|
+
* Returns the current bandwidth estimate in bits per second, when available. Otherwise, `NaN` is returned.
|
|
912
|
+
*/
|
|
913
|
+
get bandwidthEstimate(): number {
|
|
914
|
+
const { bwEstimator } = this.abrController;
|
|
915
|
+
if (!bwEstimator) {
|
|
916
|
+
return NaN;
|
|
917
|
+
}
|
|
918
|
+
return bwEstimator.getEstimate();
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
set bandwidthEstimate(abrEwmaDefaultEstimate: number) {
|
|
922
|
+
this.abrController.resetEstimator(abrEwmaDefaultEstimate);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
get abrEwmaDefaultEstimate(): number {
|
|
926
|
+
const { bwEstimator } = this.abrController;
|
|
927
|
+
if (!bwEstimator) {
|
|
928
|
+
return NaN;
|
|
929
|
+
}
|
|
930
|
+
return bwEstimator.defaultEstimate;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* get time to first byte estimate
|
|
935
|
+
* @type {number}
|
|
936
|
+
*/
|
|
937
|
+
get ttfbEstimate(): number {
|
|
938
|
+
const { bwEstimator } = this.abrController;
|
|
939
|
+
if (!bwEstimator) {
|
|
940
|
+
return NaN;
|
|
941
|
+
}
|
|
942
|
+
return bwEstimator.getEstimateTTFB();
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* Capping/max level value that should be used by automatic level selection algorithm (`ABRController`)
|
|
947
|
+
*/
|
|
948
|
+
set autoLevelCapping(newLevel: number) {
|
|
949
|
+
if (this._autoLevelCapping !== newLevel) {
|
|
950
|
+
this.logger.log(`set autoLevelCapping:${newLevel}`);
|
|
951
|
+
this._autoLevelCapping = newLevel;
|
|
952
|
+
this.levelController.checkMaxAutoUpdated();
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
get maxHdcpLevel(): HdcpLevel {
|
|
957
|
+
return this._maxHdcpLevel;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
set maxHdcpLevel(value: HdcpLevel) {
|
|
961
|
+
if (isHdcpLevel(value) && this._maxHdcpLevel !== value) {
|
|
962
|
+
this._maxHdcpLevel = value;
|
|
963
|
+
this.levelController.checkMaxAutoUpdated();
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* True when automatic level selection enabled
|
|
969
|
+
*/
|
|
970
|
+
get autoLevelEnabled(): boolean {
|
|
971
|
+
return this.levelController.manualLevel === -1;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Level set manually (if any)
|
|
976
|
+
*/
|
|
977
|
+
get manualLevel(): number {
|
|
978
|
+
return this.levelController.manualLevel;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
/**
|
|
982
|
+
* min level selectable in auto mode according to config.minAutoBitrate
|
|
983
|
+
*/
|
|
984
|
+
get minAutoLevel(): number {
|
|
985
|
+
const {
|
|
986
|
+
levels,
|
|
987
|
+
config: { minAutoBitrate },
|
|
988
|
+
} = this;
|
|
989
|
+
if (!levels) return 0;
|
|
990
|
+
|
|
991
|
+
const len = levels.length;
|
|
992
|
+
for (let i = 0; i < len; i++) {
|
|
993
|
+
if (levels[i].maxBitrate >= minAutoBitrate) {
|
|
994
|
+
return i;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
return 0;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* max level selectable in auto mode according to autoLevelCapping
|
|
1003
|
+
*/
|
|
1004
|
+
get maxAutoLevel(): number {
|
|
1005
|
+
const { levels, autoLevelCapping, maxHdcpLevel } = this;
|
|
1006
|
+
|
|
1007
|
+
let maxAutoLevel;
|
|
1008
|
+
if (autoLevelCapping === -1 && levels?.length) {
|
|
1009
|
+
maxAutoLevel = levels.length - 1;
|
|
1010
|
+
} else {
|
|
1011
|
+
maxAutoLevel = autoLevelCapping;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
if (maxHdcpLevel) {
|
|
1015
|
+
for (let i = maxAutoLevel; i--; ) {
|
|
1016
|
+
const hdcpLevel = levels[i].attrs['HDCP-LEVEL'];
|
|
1017
|
+
if (hdcpLevel && hdcpLevel <= maxHdcpLevel) {
|
|
1018
|
+
return i;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
return maxAutoLevel;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
get firstAutoLevel(): number {
|
|
1027
|
+
return this.abrController.firstAutoLevel;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
/**
|
|
1031
|
+
* next automatically selected quality level
|
|
1032
|
+
*/
|
|
1033
|
+
get nextAutoLevel(): number {
|
|
1034
|
+
return this.abrController.nextAutoLevel;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
/**
|
|
1038
|
+
* this setter is used to force next auto level.
|
|
1039
|
+
* this is useful to force a switch down in auto mode:
|
|
1040
|
+
* in case of load error on level N, hls.js can set nextAutoLevel to N-1 for example)
|
|
1041
|
+
* forced value is valid for one fragment. upon successful frag loading at forced level,
|
|
1042
|
+
* this value will be resetted to -1 by ABR controller.
|
|
1043
|
+
*/
|
|
1044
|
+
set nextAutoLevel(nextLevel: number) {
|
|
1045
|
+
this.abrController.nextAutoLevel = nextLevel;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* get the datetime value relative to media.currentTime for the active level Program Date Time if present
|
|
1050
|
+
*/
|
|
1051
|
+
public get playingDate(): Date | null {
|
|
1052
|
+
return this.streamController.currentProgramDateTime;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
public get mainForwardBufferInfo(): BufferInfo | null {
|
|
1056
|
+
return this.streamController.getMainFwdBufferInfo();
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
public get maxBufferLength(): number {
|
|
1060
|
+
return this.streamController.maxBufferLength;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
/**
|
|
1064
|
+
* Find and select the best matching audio track, making a level switch when a Group change is necessary.
|
|
1065
|
+
* Updates `hls.config.audioPreference`. Returns the selected track, or null when no matching track is found.
|
|
1066
|
+
*/
|
|
1067
|
+
public setAudioOption(
|
|
1068
|
+
audioOption: MediaPlaylist | AudioSelectionOption | undefined,
|
|
1069
|
+
): MediaPlaylist | null {
|
|
1070
|
+
return this.audioTrackController?.setAudioOption(audioOption) || null;
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Find and select the best matching subtitle track, making a level switch when a Group change is necessary.
|
|
1074
|
+
* Updates `hls.config.subtitlePreference`. Returns the selected track, or null when no matching track is found.
|
|
1075
|
+
*/
|
|
1076
|
+
public setSubtitleOption(
|
|
1077
|
+
subtitleOption: MediaPlaylist | SubtitleSelectionOption | undefined,
|
|
1078
|
+
): MediaPlaylist | null {
|
|
1079
|
+
return (
|
|
1080
|
+
this.subtitleTrackController?.setSubtitleOption(subtitleOption) || null
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
/**
|
|
1085
|
+
* Get the complete list of audio tracks across all media groups
|
|
1086
|
+
*/
|
|
1087
|
+
get allAudioTracks(): MediaPlaylist[] {
|
|
1088
|
+
const audioTrackController = this.audioTrackController;
|
|
1089
|
+
return audioTrackController ? audioTrackController.allAudioTracks : [];
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* Get the list of selectable audio tracks
|
|
1094
|
+
*/
|
|
1095
|
+
get audioTracks(): MediaPlaylist[] {
|
|
1096
|
+
const audioTrackController = this.audioTrackController;
|
|
1097
|
+
return audioTrackController ? audioTrackController.audioTracks : [];
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
/**
|
|
1101
|
+
* index of the selected audio track (index in audio track lists)
|
|
1102
|
+
*/
|
|
1103
|
+
get audioTrack(): number {
|
|
1104
|
+
const audioTrackController = this.audioTrackController;
|
|
1105
|
+
return audioTrackController ? audioTrackController.audioTrack : -1;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
/**
|
|
1109
|
+
* selects an audio track, based on its index in audio track lists
|
|
1110
|
+
*/
|
|
1111
|
+
set audioTrack(audioTrackId: number) {
|
|
1112
|
+
const audioTrackController = this.audioTrackController;
|
|
1113
|
+
if (audioTrackController) {
|
|
1114
|
+
audioTrackController.audioTrack = audioTrackId;
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
/**
|
|
1119
|
+
* Index of next audio track as scheduled by audio stream controller.
|
|
1120
|
+
*/
|
|
1121
|
+
get nextAudioTrack(): number {
|
|
1122
|
+
return this.audioStreamController?.nextAudioTrack ?? -1;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
/**
|
|
1126
|
+
* Set audio track index for next loaded data.
|
|
1127
|
+
* This will switch the audio track asap, without interrupting playback.
|
|
1128
|
+
* May abort current loading of data, and flush parts of buffer(outside
|
|
1129
|
+
* currently played fragment region). Audio Track Switched event will be
|
|
1130
|
+
* delayed until the currently playing fragment is of the next audio track.
|
|
1131
|
+
* @param audioTrackId - Pass -1 for automatic level selection
|
|
1132
|
+
*/
|
|
1133
|
+
set nextAudioTrack(audioTrackId: number) {
|
|
1134
|
+
const { audioTrackController } = this;
|
|
1135
|
+
if (audioTrackController) {
|
|
1136
|
+
audioTrackController.nextAudioTrack = audioTrackId;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
/**
|
|
1141
|
+
* get the complete list of subtitle tracks across all media groups
|
|
1142
|
+
*/
|
|
1143
|
+
get allSubtitleTracks(): MediaPlaylist[] {
|
|
1144
|
+
const subtitleTrackController = this.subtitleTrackController;
|
|
1145
|
+
return subtitleTrackController
|
|
1146
|
+
? subtitleTrackController.allSubtitleTracks
|
|
1147
|
+
: [];
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
/**
|
|
1151
|
+
* get alternate subtitle tracks list from playlist
|
|
1152
|
+
*/
|
|
1153
|
+
get subtitleTracks(): MediaPlaylist[] {
|
|
1154
|
+
const subtitleTrackController = this.subtitleTrackController;
|
|
1155
|
+
return subtitleTrackController
|
|
1156
|
+
? subtitleTrackController.subtitleTracks
|
|
1157
|
+
: [];
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
/**
|
|
1161
|
+
* index of the selected subtitle track (index in subtitle track lists)
|
|
1162
|
+
*/
|
|
1163
|
+
get subtitleTrack(): number {
|
|
1164
|
+
const subtitleTrackController = this.subtitleTrackController;
|
|
1165
|
+
return subtitleTrackController ? subtitleTrackController.subtitleTrack : -1;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
get media() {
|
|
1169
|
+
return this._media;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
/**
|
|
1173
|
+
* select an subtitle track, based on its index in subtitle track lists
|
|
1174
|
+
*/
|
|
1175
|
+
set subtitleTrack(subtitleTrackId: number) {
|
|
1176
|
+
const subtitleTrackController = this.subtitleTrackController;
|
|
1177
|
+
if (subtitleTrackController) {
|
|
1178
|
+
subtitleTrackController.subtitleTrack = subtitleTrackId;
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
/**
|
|
1183
|
+
* Whether subtitle display is enabled or not
|
|
1184
|
+
*/
|
|
1185
|
+
get subtitleDisplay(): boolean {
|
|
1186
|
+
const subtitleTrackController = this.subtitleTrackController;
|
|
1187
|
+
return subtitleTrackController
|
|
1188
|
+
? subtitleTrackController.subtitleDisplay
|
|
1189
|
+
: false;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
/**
|
|
1193
|
+
* Enable/disable subtitle display rendering
|
|
1194
|
+
*/
|
|
1195
|
+
set subtitleDisplay(value: boolean) {
|
|
1196
|
+
const subtitleTrackController = this.subtitleTrackController;
|
|
1197
|
+
if (subtitleTrackController) {
|
|
1198
|
+
subtitleTrackController.subtitleDisplay = value;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
/**
|
|
1203
|
+
* get mode for Low-Latency HLS loading
|
|
1204
|
+
*/
|
|
1205
|
+
get lowLatencyMode(): boolean {
|
|
1206
|
+
return this.config.lowLatencyMode;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
/**
|
|
1210
|
+
* Enable/disable Low-Latency HLS part playlist and segment loading, and start live streams at playlist PART-HOLD-BACK rather than HOLD-BACK.
|
|
1211
|
+
*/
|
|
1212
|
+
set lowLatencyMode(mode: boolean) {
|
|
1213
|
+
this.config.lowLatencyMode = mode;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
/**
|
|
1217
|
+
* Position (in seconds) of live sync point (ie edge of live position minus safety delay defined by ```hls.config.liveSyncDuration```)
|
|
1218
|
+
* @returns null prior to loading live Playlist
|
|
1219
|
+
*/
|
|
1220
|
+
get liveSyncPosition(): number | null {
|
|
1221
|
+
return this.latencyController.liveSyncPosition;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
/**
|
|
1225
|
+
* Estimated position (in seconds) of live edge (ie edge of live playlist plus time sync playlist advanced)
|
|
1226
|
+
* @returns 0 before first playlist is loaded
|
|
1227
|
+
*/
|
|
1228
|
+
get latency(): number {
|
|
1229
|
+
return this.latencyController.latency;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
/**
|
|
1233
|
+
* maximum distance from the edge before the player seeks forward to ```hls.liveSyncPosition```
|
|
1234
|
+
* configured using ```liveMaxLatencyDurationCount``` (multiple of target duration) or ```liveMaxLatencyDuration```
|
|
1235
|
+
* @returns 0 before first playlist is loaded
|
|
1236
|
+
*/
|
|
1237
|
+
get maxLatency(): number {
|
|
1238
|
+
return this.latencyController.maxLatency;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
/**
|
|
1242
|
+
* target distance from the edge as calculated by the latency controller
|
|
1243
|
+
*/
|
|
1244
|
+
get targetLatency(): number | null {
|
|
1245
|
+
return this.latencyController.targetLatency;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
set targetLatency(latency: number) {
|
|
1249
|
+
this.latencyController.targetLatency = latency;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
/**
|
|
1253
|
+
* the rate at which the edge of the current live playlist is advancing or 1 if there is none
|
|
1254
|
+
*/
|
|
1255
|
+
get drift(): number | null {
|
|
1256
|
+
return this.latencyController.drift;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
/**
|
|
1260
|
+
* set to true when startLoad is called before MANIFEST_PARSED event
|
|
1261
|
+
*/
|
|
1262
|
+
get forceStartLoad(): boolean {
|
|
1263
|
+
return this.streamController.forceStartLoad;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
/**
|
|
1267
|
+
* ContentSteering pathways getter
|
|
1268
|
+
*/
|
|
1269
|
+
get pathways(): string[] {
|
|
1270
|
+
return this.levelController.pathways;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
/**
|
|
1274
|
+
* ContentSteering pathwayPriority getter/setter
|
|
1275
|
+
*/
|
|
1276
|
+
get pathwayPriority(): string[] | null {
|
|
1277
|
+
return this.levelController.pathwayPriority;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
set pathwayPriority(pathwayPriority: string[]) {
|
|
1281
|
+
this.levelController.pathwayPriority = pathwayPriority;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
/**
|
|
1285
|
+
* returns true when all SourceBuffers are buffered to the end
|
|
1286
|
+
*/
|
|
1287
|
+
get bufferedToEnd(): boolean {
|
|
1288
|
+
return !!this.bufferController?.bufferedToEnd;
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
/**
|
|
1292
|
+
* returns Interstitials Program Manager
|
|
1293
|
+
*/
|
|
1294
|
+
get interstitialsManager(): InterstitialsManager | null {
|
|
1295
|
+
return this.interstitialsController?.interstitialsManager || null;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
/**
|
|
1299
|
+
* returns mediaCapabilities.decodingInfo for a variant/rendition
|
|
1300
|
+
*/
|
|
1301
|
+
getMediaDecodingInfo(
|
|
1302
|
+
level: Level,
|
|
1303
|
+
audioTracks: MediaPlaylist[] = this.allAudioTracks,
|
|
1304
|
+
): Promise<MediaDecodingInfo> {
|
|
1305
|
+
const audioTracksByGroup = getAudioTracksByGroup(audioTracks);
|
|
1306
|
+
return getMediaDecodingInfoPromise(
|
|
1307
|
+
level,
|
|
1308
|
+
audioTracksByGroup,
|
|
1309
|
+
navigator.mediaCapabilities,
|
|
1310
|
+
);
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
export type InFlightFragments = {
|
|
1315
|
+
[PlaylistLevelType.MAIN]: InFlightData;
|
|
1316
|
+
[PlaylistLevelType.AUDIO]?: InFlightData;
|
|
1317
|
+
[PlaylistLevelType.SUBTITLE]?: InFlightData;
|
|
1318
|
+
};
|
|
1319
|
+
export type {
|
|
1320
|
+
AudioSelectionOption,
|
|
1321
|
+
SubtitleSelectionOption,
|
|
1322
|
+
VideoSelectionOption,
|
|
1323
|
+
MediaPlaylist,
|
|
1324
|
+
ErrorDetails,
|
|
1325
|
+
ErrorTypes,
|
|
1326
|
+
Events,
|
|
1327
|
+
Level,
|
|
1328
|
+
LevelDetails,
|
|
1329
|
+
HlsListeners,
|
|
1330
|
+
HlsEventEmitter,
|
|
1331
|
+
HlsConfig,
|
|
1332
|
+
BufferInfo,
|
|
1333
|
+
BufferTimeRange,
|
|
1334
|
+
HdcpLevel,
|
|
1335
|
+
AbrController,
|
|
1336
|
+
AudioStreamController,
|
|
1337
|
+
AudioTrackController,
|
|
1338
|
+
BasePlaylistController,
|
|
1339
|
+
BaseStreamController,
|
|
1340
|
+
BufferController,
|
|
1341
|
+
CapLevelController,
|
|
1342
|
+
CMCDController,
|
|
1343
|
+
ContentSteeringController,
|
|
1344
|
+
EMEController,
|
|
1345
|
+
ErrorController,
|
|
1346
|
+
FPSController,
|
|
1347
|
+
InterstitialsController,
|
|
1348
|
+
StreamController,
|
|
1349
|
+
SubtitleStreamController,
|
|
1350
|
+
SubtitleTrackController,
|
|
1351
|
+
EwmaBandWidthEstimator,
|
|
1352
|
+
InterstitialsManager,
|
|
1353
|
+
Decrypter,
|
|
1354
|
+
FragmentLoader,
|
|
1355
|
+
KeyLoader,
|
|
1356
|
+
TaskLoop,
|
|
1357
|
+
TransmuxerInterface,
|
|
1358
|
+
InFlightData,
|
|
1359
|
+
State,
|
|
1360
|
+
XhrLoader,
|
|
1361
|
+
FetchLoader,
|
|
1362
|
+
Cues,
|
|
1363
|
+
M3U8Parser,
|
|
1364
|
+
};
|
|
1365
|
+
export type {
|
|
1366
|
+
ABRControllerConfig,
|
|
1367
|
+
PlaylistControllerConfig,
|
|
1368
|
+
BufferControllerConfig,
|
|
1369
|
+
CapLevelControllerConfig,
|
|
1370
|
+
CMCDControllerConfig,
|
|
1371
|
+
EMEControllerConfig,
|
|
1372
|
+
DRMSystemConfiguration,
|
|
1373
|
+
DRMSystemsConfiguration,
|
|
1374
|
+
DRMSystemOptions,
|
|
1375
|
+
FPSControllerConfig,
|
|
1376
|
+
FragmentLoaderConfig,
|
|
1377
|
+
FragmentLoaderConstructor,
|
|
1378
|
+
GapControllerConfig,
|
|
1379
|
+
HlsLoadPolicies,
|
|
1380
|
+
LevelControllerConfig,
|
|
1381
|
+
LoaderConfig,
|
|
1382
|
+
LoadPolicy,
|
|
1383
|
+
MP4RemuxerConfig,
|
|
1384
|
+
PlaylistLoaderConfig,
|
|
1385
|
+
PlaylistLoaderConstructor,
|
|
1386
|
+
RetryConfig,
|
|
1387
|
+
SelectionPreferences,
|
|
1388
|
+
StreamControllerConfig,
|
|
1389
|
+
LatencyControllerConfig,
|
|
1390
|
+
MetadataControllerConfig,
|
|
1391
|
+
TimelineControllerConfig,
|
|
1392
|
+
TSDemuxerConfig,
|
|
1393
|
+
} from './config';
|
|
1394
|
+
export type { MediaKeySessionContext } from './controller/eme-controller';
|
|
1395
|
+
export type {
|
|
1396
|
+
FragmentState,
|
|
1397
|
+
FragmentTracker,
|
|
1398
|
+
} from './controller/fragment-tracker';
|
|
1399
|
+
export type {
|
|
1400
|
+
PathwayClone,
|
|
1401
|
+
SteeringManifest,
|
|
1402
|
+
UriReplacement,
|
|
1403
|
+
} from './controller/content-steering-controller';
|
|
1404
|
+
export type {
|
|
1405
|
+
NetworkErrorAction,
|
|
1406
|
+
ErrorActionFlags,
|
|
1407
|
+
IErrorAction,
|
|
1408
|
+
} from './controller/error-controller';
|
|
1409
|
+
export type {
|
|
1410
|
+
HlsAssetPlayer,
|
|
1411
|
+
HlsAssetPlayerConfig,
|
|
1412
|
+
InterstitialPlayer,
|
|
1413
|
+
} from './controller/interstitial-player';
|
|
1414
|
+
export type { PlayheadTimes } from './controller/interstitials-controller';
|
|
1415
|
+
export type {
|
|
1416
|
+
InterstitialScheduleDurations,
|
|
1417
|
+
InterstitialScheduleEventItem,
|
|
1418
|
+
InterstitialScheduleItem,
|
|
1419
|
+
InterstitialSchedulePrimaryItem,
|
|
1420
|
+
} from './controller/interstitials-schedule';
|
|
1421
|
+
export type { TimelineController } from './controller/timeline-controller';
|
|
1422
|
+
export type { DecrypterAesMode } from './crypt/decrypter-aes-mode';
|
|
1423
|
+
export type { DateRange, DateRangeCue } from './loader/date-range';
|
|
1424
|
+
export type { LoadStats } from './loader/load-stats';
|
|
1425
|
+
export type { LevelKey } from './loader/level-key';
|
|
1426
|
+
export type {
|
|
1427
|
+
BaseSegment,
|
|
1428
|
+
Fragment,
|
|
1429
|
+
MediaFragment,
|
|
1430
|
+
Part,
|
|
1431
|
+
ElementaryStreams,
|
|
1432
|
+
ElementaryStreamTypes,
|
|
1433
|
+
ElementaryStreamInfo,
|
|
1434
|
+
} from './loader/fragment';
|
|
1435
|
+
export type {
|
|
1436
|
+
FragLoadFailResult,
|
|
1437
|
+
FragmentLoadProgressCallback,
|
|
1438
|
+
LoadError,
|
|
1439
|
+
} from './loader/fragment-loader';
|
|
1440
|
+
export type { KeyLoaderInfo } from './loader/key-loader';
|
|
1441
|
+
export type { DecryptData } from './loader/level-key';
|
|
1442
|
+
export type {
|
|
1443
|
+
AssetListJSON,
|
|
1444
|
+
BaseData,
|
|
1445
|
+
InterstitialAssetId,
|
|
1446
|
+
InterstitialAssetItem,
|
|
1447
|
+
InterstitialEvent,
|
|
1448
|
+
InterstitialEventWithAssetList,
|
|
1449
|
+
InterstitialId,
|
|
1450
|
+
PlaybackRestrictions,
|
|
1451
|
+
SnapOptions,
|
|
1452
|
+
TimelineOccupancy,
|
|
1453
|
+
} from './loader/interstitial-event';
|
|
1454
|
+
export type { ParsedMultivariantPlaylist } from './loader/m3u8-parser';
|
|
1455
|
+
export type {
|
|
1456
|
+
AttachMediaSourceData,
|
|
1457
|
+
BaseTrack,
|
|
1458
|
+
BaseTrackSet,
|
|
1459
|
+
BufferCreatedTrack,
|
|
1460
|
+
BufferCreatedTrackSet,
|
|
1461
|
+
ExtendedSourceBuffer,
|
|
1462
|
+
MediaOverrides,
|
|
1463
|
+
ParsedTrack,
|
|
1464
|
+
SourceBufferName,
|
|
1465
|
+
SourceBufferListener,
|
|
1466
|
+
SourceBufferTrack,
|
|
1467
|
+
SourceBufferTrackSet,
|
|
1468
|
+
} from './types/buffer';
|
|
1469
|
+
export type {
|
|
1470
|
+
ComponentAPI,
|
|
1471
|
+
AbrComponentAPI,
|
|
1472
|
+
NetworkComponentAPI,
|
|
1473
|
+
} from './types/component-api';
|
|
1474
|
+
export type {
|
|
1475
|
+
TrackLoadingData,
|
|
1476
|
+
TrackLoadedData,
|
|
1477
|
+
AssetListLoadedData,
|
|
1478
|
+
AssetListLoadingData,
|
|
1479
|
+
AudioTrackLoadedData,
|
|
1480
|
+
AudioTrackUpdatedData,
|
|
1481
|
+
AudioTracksUpdatedData,
|
|
1482
|
+
AudioTrackSwitchedData,
|
|
1483
|
+
AudioTrackSwitchingData,
|
|
1484
|
+
BackBufferData,
|
|
1485
|
+
BufferAppendedData,
|
|
1486
|
+
BufferAppendingData,
|
|
1487
|
+
BufferCodecsData,
|
|
1488
|
+
BufferCreatedData,
|
|
1489
|
+
BufferEOSData,
|
|
1490
|
+
BufferFlushedData,
|
|
1491
|
+
BufferFlushingData,
|
|
1492
|
+
CuesParsedData,
|
|
1493
|
+
ErrorData,
|
|
1494
|
+
FPSDropData,
|
|
1495
|
+
FPSDropLevelCappingData,
|
|
1496
|
+
FragBufferedData,
|
|
1497
|
+
FragChangedData,
|
|
1498
|
+
FragDecryptedData,
|
|
1499
|
+
FragLoadedData,
|
|
1500
|
+
FragLoadEmergencyAbortedData,
|
|
1501
|
+
FragLoadingData,
|
|
1502
|
+
FragParsedData,
|
|
1503
|
+
FragParsingInitSegmentData,
|
|
1504
|
+
FragParsingMetadataData,
|
|
1505
|
+
FragParsingUserdataData,
|
|
1506
|
+
InitPTSFoundData,
|
|
1507
|
+
KeyLoadedData,
|
|
1508
|
+
KeyLoadingData,
|
|
1509
|
+
LevelLoadedData,
|
|
1510
|
+
LevelLoadingData,
|
|
1511
|
+
LevelPTSUpdatedData,
|
|
1512
|
+
LevelsUpdatedData,
|
|
1513
|
+
LevelSwitchedData,
|
|
1514
|
+
LevelSwitchingData,
|
|
1515
|
+
LevelUpdatedData,
|
|
1516
|
+
LiveBackBufferData,
|
|
1517
|
+
ContentSteeringOptions,
|
|
1518
|
+
ManifestLoadedData,
|
|
1519
|
+
ManifestLoadingData,
|
|
1520
|
+
ManifestParsedData,
|
|
1521
|
+
MaxAutoLevelUpdatedData,
|
|
1522
|
+
MediaAttachedData,
|
|
1523
|
+
MediaAttachingData,
|
|
1524
|
+
MediaDetachedData,
|
|
1525
|
+
MediaDetachingData,
|
|
1526
|
+
MediaEndedData,
|
|
1527
|
+
NonNativeTextTrack,
|
|
1528
|
+
NonNativeTextTracksData,
|
|
1529
|
+
PartsLoadedData,
|
|
1530
|
+
SteeringManifestLoadedData,
|
|
1531
|
+
SubtitleFragProcessedData,
|
|
1532
|
+
SubtitleTrackLoadedData,
|
|
1533
|
+
SubtitleTrackUpdatedData,
|
|
1534
|
+
SubtitleTracksUpdatedData,
|
|
1535
|
+
SubtitleTrackSwitchData,
|
|
1536
|
+
InterstitialsUpdatedData,
|
|
1537
|
+
InterstitialsBufferedToBoundaryData,
|
|
1538
|
+
InterstitialAssetPlayerCreatedData,
|
|
1539
|
+
InterstitialStartedData,
|
|
1540
|
+
InterstitialEndedData,
|
|
1541
|
+
InterstitialAssetStartedData,
|
|
1542
|
+
InterstitialAssetEndedData,
|
|
1543
|
+
InterstitialAssetErrorData,
|
|
1544
|
+
InterstitialsPrimaryResumed,
|
|
1545
|
+
} from './types/events';
|
|
1546
|
+
export type {
|
|
1547
|
+
MetadataSample,
|
|
1548
|
+
MetadataSchema,
|
|
1549
|
+
UserdataSample,
|
|
1550
|
+
} from './types/demuxer';
|
|
1551
|
+
export type {
|
|
1552
|
+
InitSegmentData,
|
|
1553
|
+
RemuxedMetadata,
|
|
1554
|
+
RemuxedTrack,
|
|
1555
|
+
RemuxedUserdata,
|
|
1556
|
+
RemuxerResult,
|
|
1557
|
+
} from './types/remuxer';
|
|
1558
|
+
export type { AttrList } from './utils/attr-list';
|
|
1559
|
+
export type { Bufferable } from './utils/buffer-helper';
|
|
1560
|
+
export type { CaptionScreen } from './utils/cea-608-parser';
|
|
1561
|
+
export type { CuesInterface } from './utils/cues';
|
|
1562
|
+
export type {
|
|
1563
|
+
CodecsParsed,
|
|
1564
|
+
HdcpLevels,
|
|
1565
|
+
HlsSkip,
|
|
1566
|
+
HlsUrlParameters,
|
|
1567
|
+
LevelAttributes,
|
|
1568
|
+
LevelParsed,
|
|
1569
|
+
VariableMap,
|
|
1570
|
+
VideoRange,
|
|
1571
|
+
VideoRangeValues,
|
|
1572
|
+
} from './types/level';
|
|
1573
|
+
export type {
|
|
1574
|
+
PlaylistLevelType,
|
|
1575
|
+
HlsChunkPerformanceTiming,
|
|
1576
|
+
HlsPerformanceTiming,
|
|
1577
|
+
HlsProgressivePerformanceTiming,
|
|
1578
|
+
PlaylistContextType,
|
|
1579
|
+
PlaylistLoaderContext,
|
|
1580
|
+
FragmentLoaderContext,
|
|
1581
|
+
KeyLoaderContext,
|
|
1582
|
+
Loader,
|
|
1583
|
+
LoaderStats,
|
|
1584
|
+
LoaderContext,
|
|
1585
|
+
LoaderResponse,
|
|
1586
|
+
LoaderConfiguration,
|
|
1587
|
+
LoaderCallbacks,
|
|
1588
|
+
LoaderOnProgress,
|
|
1589
|
+
LoaderOnAbort,
|
|
1590
|
+
LoaderOnError,
|
|
1591
|
+
LoaderOnSuccess,
|
|
1592
|
+
LoaderOnTimeout,
|
|
1593
|
+
} from './types/loader';
|
|
1594
|
+
export type { ILogFunction, ILogger, Logger } from './utils/logger';
|
|
1595
|
+
export type {
|
|
1596
|
+
MediaAttributes,
|
|
1597
|
+
MediaPlaylistType,
|
|
1598
|
+
MainPlaylistType,
|
|
1599
|
+
AudioPlaylistType,
|
|
1600
|
+
SubtitlePlaylistType,
|
|
1601
|
+
} from './types/media-playlist';
|
|
1602
|
+
export type { Track, TrackSet } from './types/track';
|
|
1603
|
+
export type { ChunkMetadata, TransmuxerResult } from './types/transmuxer';
|
|
1604
|
+
export type { MediaDecodingInfo } from './utils/mediacapabilities-helper';
|
|
1605
|
+
export type {
|
|
1606
|
+
MediaKeyFunc,
|
|
1607
|
+
KeySystems,
|
|
1608
|
+
KeySystemFormats,
|
|
1609
|
+
} from './utils/mediakeys-helper';
|
|
1610
|
+
export type {
|
|
1611
|
+
RationalTimestamp,
|
|
1612
|
+
TimestampOffset,
|
|
1613
|
+
} from './utils/timescale-conversion';
|