@gcorevideo/player 2.28.26 → 2.28.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.js CHANGED
@@ -118,6 +118,73 @@ class LogTracer {
118
118
  }
119
119
  }
120
120
 
121
+ const DEFAULT_DELAY = 1000;
122
+ const MIN_DELAY = 1000;
123
+ /**
124
+ * A tracer the pushes the records to a remote server.
125
+ * Used with fullstack Node.js applications (Nuxt.js, Next.js, etc.)
126
+ * @beta
127
+ */
128
+ class RemoteTracer {
129
+ baseTracer;
130
+ tags;
131
+ buffer = [];
132
+ timerId = null;
133
+ delay;
134
+ /**
135
+ *
136
+ * @param baseTracer An additional tracer to be called next to this one. Deprecated. Use {@link ChainedTracer} instead.
137
+ * @param tags
138
+ * @param options
139
+ */
140
+ constructor(baseTracer, tags = {}, options = {}) {
141
+ this.baseTracer = baseTracer;
142
+ this.tags = tags;
143
+ this.delay = Math.max(options.delay ?? DEFAULT_DELAY, MIN_DELAY);
144
+ }
145
+ reportError(e) {
146
+ if (this.baseTracer) {
147
+ this.baseTracer.reportError(e);
148
+ }
149
+ const message = String(e);
150
+ const detail = e instanceof Error && 'detail' in e
151
+ ? e.detail
152
+ : undefined;
153
+ this.push(message, detail);
154
+ }
155
+ trace(message, detail) {
156
+ if (this.baseTracer) {
157
+ this.baseTracer.trace(message, detail);
158
+ }
159
+ this.push(message, detail);
160
+ }
161
+ setTag(key, value) {
162
+ this.tags[key] = value;
163
+ }
164
+ push(message, detail) {
165
+ const time = new Date().getTime();
166
+ this.buffer.push({ message, detail, time });
167
+ if (!this.timerId) {
168
+ this.timerId = setTimeout(() => {
169
+ this.timerId = null;
170
+ this.send(this.buffer.splice(0, this.buffer.length));
171
+ }, this.delay);
172
+ }
173
+ }
174
+ send(records) {
175
+ fetch('/api/traceb', {
176
+ method: 'POST',
177
+ body: JSON.stringify({
178
+ records,
179
+ tags: this.tags,
180
+ }),
181
+ headers: {
182
+ 'Content-Type': 'application/json',
183
+ },
184
+ }).catch((e) => console.error(e));
185
+ }
186
+ }
187
+
121
188
  /**
122
189
  * @beta
123
190
  */
@@ -13805,7 +13872,7 @@ function enableLogs(debugConfig, context, id) {
13805
13872
  // Some browsers don't allow to use bind on console object anyway
13806
13873
  // fallback to default if needed
13807
13874
  try {
13808
- newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.14"}`);
13875
+ newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.6.15"}`);
13809
13876
  } catch (e) {
13810
13877
  /* log fn threw an exception. All logger methods are no-ops. */
13811
13878
  return createLogger();
@@ -18251,11 +18318,7 @@ class FragmentTracker {
18251
18318
  });
18252
18319
  fragmentEntity.loaded = null;
18253
18320
  if (Object.keys(fragmentEntity.range).length) {
18254
- fragmentEntity.buffered = true;
18255
- const endList = fragmentEntity.body.endList = frag.endList || fragmentEntity.body.endList;
18256
- if (endList) {
18257
- this.endListFragments[fragmentEntity.body.type] = fragmentEntity;
18258
- }
18321
+ this.bufferedEnd(fragmentEntity, frag);
18259
18322
  if (!isPartial(fragmentEntity)) {
18260
18323
  // Remove older fragment parts from lookup after frag is tracked as buffered
18261
18324
  this.removeParts(frag.sn - 1, frag.type);
@@ -18265,6 +18328,13 @@ class FragmentTracker {
18265
18328
  this.removeFragment(fragmentEntity.body);
18266
18329
  }
18267
18330
  }
18331
+ bufferedEnd(fragmentEntity, frag) {
18332
+ fragmentEntity.buffered = true;
18333
+ const endList = fragmentEntity.body.endList = frag.endList || fragmentEntity.body.endList;
18334
+ if (endList) {
18335
+ this.endListFragments[fragmentEntity.body.type] = fragmentEntity;
18336
+ }
18337
+ }
18268
18338
  removeParts(snToKeep, levelType) {
18269
18339
  const activeParts = this.activePartLists[levelType];
18270
18340
  if (!activeParts) {
@@ -18289,7 +18359,7 @@ class FragmentTracker {
18289
18359
  }
18290
18360
  if (fragmentEntity) {
18291
18361
  fragmentEntity.loaded = null;
18292
- fragmentEntity.buffered = true;
18362
+ this.bufferedEnd(fragmentEntity, frag);
18293
18363
  }
18294
18364
  }
18295
18365
  getBufferedTimes(fragment, part, partial, timeRange) {
@@ -20338,6 +20408,14 @@ class LevelKey {
20338
20408
  static setKeyIdForUri(uri, keyId) {
20339
20409
  keyUriToKeyIdMap[uri] = keyId;
20340
20410
  }
20411
+ static addKeyIdForUri(uri) {
20412
+ const val = Object.keys(keyUriToKeyIdMap).length % Number.MAX_SAFE_INTEGER;
20413
+ const keyId = new Uint8Array(16);
20414
+ const dv = new DataView(keyId.buffer, 12, 4); // Just set the last 4 bytes
20415
+ dv.setUint32(0, val);
20416
+ keyUriToKeyIdMap[uri] = keyId;
20417
+ return keyId;
20418
+ }
20341
20419
  constructor(method, uri, format, formatversions = [1], iv = null, keyId) {
20342
20420
  this.uri = void 0;
20343
20421
  this.method = void 0;
@@ -22502,7 +22580,7 @@ class BaseStreamController extends TaskLoop {
22502
22580
  this.state = State.FRAG_LOADING;
22503
22581
 
22504
22582
  // Load key before streaming fragment data
22505
- const dataOnProgress = this.config.progressive;
22583
+ const dataOnProgress = this.config.progressive && frag.type !== PlaylistLevelType.SUBTITLE;
22506
22584
  let result;
22507
22585
  if (dataOnProgress && keyLoadingPromise) {
22508
22586
  result = keyLoadingPromise.then(keyLoadedData => {
@@ -23350,11 +23428,12 @@ class BaseStreamController extends TaskLoop {
23350
23428
  }, false);
23351
23429
  if (!parsed) {
23352
23430
  var _this$transmuxer;
23353
- if (level.fragmentError === 0) {
23354
- // Mark and track the odd empty segment as a gap to avoid reloading
23431
+ const mediaNotFound = ((_this$transmuxer = this.transmuxer) == null ? void 0 : _this$transmuxer.error) === null;
23432
+ if (level.fragmentError === 0 || mediaNotFound && (level.fragmentError < 2 || frag.endList)) {
23433
+ // Mark and track the odd (or last) empty segment as a gap to avoid reloading
23355
23434
  this.treatAsGap(frag, level);
23356
23435
  }
23357
- if (((_this$transmuxer = this.transmuxer) == null ? void 0 : _this$transmuxer.error) === null) {
23436
+ if (mediaNotFound) {
23358
23437
  const error = new Error(`Found no media in fragment ${frag.sn} of ${this.playlistLabel()} ${frag.level} resetting transmuxer to fallback to playlist timing`);
23359
23438
  this.warn(error.message);
23360
23439
  this.hls.trigger(Events.ERROR, {
@@ -23815,7 +23894,7 @@ function requireEventemitter3 () {
23815
23894
  var eventemitter3Exports = requireEventemitter3();
23816
23895
  var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
23817
23896
 
23818
- const version$2 = "1.6.14";
23897
+ const version$2 = "1.6.15";
23819
23898
 
23820
23899
  // ensure the worker ends up in the bundle
23821
23900
  // If the worker should not be included this gets aliased to empty.js
@@ -28993,7 +29072,7 @@ class MP4Remuxer extends Logger {
28993
29072
  // Clear the track samples. This also clears the samples array in the demuxer, since the reference is shared
28994
29073
  track.samples = [];
28995
29074
  const start = (firstPTS - initTime) / inputTimeScale;
28996
- const end = nextAudioTs / inputTimeScale;
29075
+ const end = this.nextAudioTs / inputTimeScale;
28997
29076
  const type = 'audio';
28998
29077
  const audioData = {
28999
29078
  data1: moof,
@@ -36157,6 +36236,11 @@ class EMEController extends Logger {
36157
36236
  }
36158
36237
  const keyIdArray = 'buffer' in keyId ? new Uint8Array(keyId.buffer, keyId.byteOffset, keyId.byteLength) : new Uint8Array(keyId);
36159
36238
  if (mediaKeySessionContext.keySystem === KeySystems.PLAYREADY && keyIdArray.length === 16) {
36239
+ // On some devices, the key ID has already been converted for endianness.
36240
+ // In such cases, this key ID is the one we need to cache.
36241
+ const originKeyIdWithStatusChange = arrayToHex(keyIdArray);
36242
+ // Cache the original key IDs to ensure compatibility across all cases.
36243
+ keyStatuses[originKeyIdWithStatusChange] = status;
36160
36244
  changeEndianness(keyIdArray);
36161
36245
  }
36162
36246
  const keyIdWithStatusChange = arrayToHex(keyIdArray);
@@ -38498,7 +38582,8 @@ class InterstitialsController extends Logger {
38498
38582
  if (backwardSeek && currentTime < start || currentTime >= start + duration) {
38499
38583
  var _playingItem$event;
38500
38584
  if ((_playingItem$event = playingItem.event) != null && _playingItem$event.appendInPlace) {
38501
- this.clearInterstitial(playingItem.event, playingItem);
38585
+ // Return SourceBuffer(s) to primary player and flush
38586
+ this.clearAssetPlayers(playingItem.event, playingItem);
38502
38587
  this.flushFrontBuffer(currentTime);
38503
38588
  }
38504
38589
  this.setScheduleToAssetAtTime(currentTime, playingAsset);
@@ -40208,11 +40293,14 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))} pos: ${this.timeline
40208
40293
  return player;
40209
40294
  }
40210
40295
  clearInterstitial(interstitial, toSegment) {
40296
+ this.clearAssetPlayers(interstitial, toSegment);
40297
+ // Remove asset list and resolved duration
40298
+ interstitial.reset();
40299
+ }
40300
+ clearAssetPlayers(interstitial, toSegment) {
40211
40301
  interstitial.assetList.forEach(asset => {
40212
40302
  this.clearAssetPlayer(asset.identifier, toSegment);
40213
40303
  });
40214
- // Remove asset list and resolved duration
40215
- interstitial.reset();
40216
40304
  }
40217
40305
  resetAssetPlayer(assetId) {
40218
40306
  // Reset asset player so that it's timeline can be adjusted without reloading the MVP
@@ -40404,10 +40492,10 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))} pos: ${this.timeline
40404
40492
  // Fallback to Primary by on current or future events by updating schedule to skip errored interstitials/assets
40405
40493
  const flushStart = interstitial.timelineStart;
40406
40494
  const playingItem = this.effectivePlayingItem;
40495
+ let timelinePos = this.timelinePos;
40407
40496
  // Update schedule now that interstitial/assets are flagged with `error` for fallback
40408
40497
  if (playingItem) {
40409
- this.log(`Fallback to primary from event "${interstitial.identifier}" start: ${flushStart} pos: ${this.timelinePos} playing: ${segmentToString(playingItem)} error: ${interstitial.error}`);
40410
- let timelinePos = this.timelinePos;
40498
+ this.log(`Fallback to primary from event "${interstitial.identifier}" start: ${flushStart} pos: ${timelinePos} playing: ${segmentToString(playingItem)} error: ${interstitial.error}`);
40411
40499
  if (timelinePos === -1) {
40412
40500
  timelinePos = this.hls.startPosition;
40413
40501
  }
@@ -40419,14 +40507,15 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))} pos: ${this.timeline
40419
40507
  this.attachPrimary(flushStart, null);
40420
40508
  this.flushFrontBuffer(flushStart);
40421
40509
  }
40422
- if (!this.schedule) {
40423
- return;
40424
- }
40425
- const scheduleIndex = this.schedule.findItemIndexAtTime(timelinePos);
40426
- this.setSchedulePosition(scheduleIndex);
40427
- } else {
40510
+ } else if (timelinePos === -1) {
40428
40511
  this.checkStart();
40512
+ return;
40513
+ }
40514
+ if (!this.schedule) {
40515
+ return;
40429
40516
  }
40517
+ const scheduleIndex = this.schedule.findItemIndexAtTime(timelinePos);
40518
+ this.setSchedulePosition(scheduleIndex);
40430
40519
  }
40431
40520
 
40432
40521
  // Asset List loading
@@ -40467,7 +40556,8 @@ Schedule: ${scheduleItems.map(seg => segmentToString(seg))} pos: ${this.timeline
40467
40556
  // Abandon if new duration is reduced enough to land playback in primary start
40468
40557
  const index = this.schedule.findItemIndexAtTime(this.timelinePos);
40469
40558
  if (index !== scheduleIndex) {
40470
- interstitial.error = new Error(`Interstitial no longer within playback range ${this.timelinePos} ${interstitial}`);
40559
+ interstitial.error = new Error(`Interstitial ${assets.length ? 'no longer within playback range' : 'asset-list is empty'} ${this.timelinePos} ${interstitial}`);
40560
+ this.log(interstitial.error.message);
40471
40561
  this.updateSchedule(true);
40472
40562
  this.primaryFallback(interstitial);
40473
40563
  return;
@@ -47275,7 +47365,7 @@ class StreamController extends BaseStreamController {
47275
47365
  onAudioTrackSwitching(event, data) {
47276
47366
  const hls = this.hls;
47277
47367
  // if any URL found on new audio track, it is an alternate audio track
47278
- const fromAltAudio = this.altAudio === 2;
47368
+ const fromAltAudio = this.altAudio !== 0;
47279
47369
  const altAudio = useAlternateAudio(data.url, hls);
47280
47370
  // if we switch on main audio, ensure that main fragment scheduling is synced with media.buffered
47281
47371
  // don't do anything if we switch to alt audio: audio stream controller is handling it.
@@ -47301,6 +47391,7 @@ class StreamController extends BaseStreamController {
47301
47391
  }
47302
47392
  // If switching from alt to main audio, flush all audio and trigger track switched
47303
47393
  if (fromAltAudio) {
47394
+ this.altAudio = 0;
47304
47395
  this.fragmentTracker.removeAllFragments();
47305
47396
  hls.once(Events.BUFFER_FLUSHED, () => {
47306
47397
  if (!this.hls) {
@@ -48138,14 +48229,22 @@ class KeyLoader extends Logger {
48138
48229
  if (!keyInfo.decryptdata.keyId && (_frag$initSegment = frag.initSegment) != null && _frag$initSegment.data) {
48139
48230
  const keyIds = parseKeyIdsFromTenc(frag.initSegment.data);
48140
48231
  if (keyIds.length) {
48141
- const keyId = keyIds[0];
48232
+ let keyId = keyIds[0];
48142
48233
  if (keyId.some(b => b !== 0)) {
48143
48234
  this.log(`Using keyId found in init segment ${arrayToHex(keyId)}`);
48144
- keyInfo.decryptdata.keyId = keyId;
48145
48235
  LevelKey.setKeyIdForUri(keyInfo.decryptdata.uri, keyId);
48236
+ } else {
48237
+ keyId = LevelKey.addKeyIdForUri(keyInfo.decryptdata.uri);
48238
+ this.log(`Generating keyId to patch media ${arrayToHex(keyId)}`);
48146
48239
  }
48240
+ keyInfo.decryptdata.keyId = keyId;
48147
48241
  }
48148
48242
  }
48243
+ if (!keyInfo.decryptdata.keyId && !isMediaFragment(frag)) {
48244
+ // Resolve so that unencrypted init segment is loaded
48245
+ // key id is extracted from tenc box when processing key for next segment above
48246
+ return Promise.resolve(keyLoadedData);
48247
+ }
48149
48248
  const keySessionContextPromise = this.emeController.loadKey(keyLoadedData);
48150
48249
  return (keyInfo.keyLoadPromise = keySessionContextPromise.then(keySessionContext => {
48151
48250
  keyInfo.mediaKeySessionContext = keySessionContext;
@@ -51332,7 +51431,7 @@ class Player {
51332
51431
  }
51333
51432
  }
51334
51433
 
51335
- var version$1 = "2.28.26";
51434
+ var version$1 = "2.28.27";
51336
51435
 
51337
51436
  var packages = {
51338
51437
  "node_modules/@clappr/core": {
@@ -51340,7 +51439,7 @@ var packages = {
51340
51439
  "node_modules/dashjs": {
51341
51440
  version: "4.7.4"},
51342
51441
  "node_modules/hls.js": {
51343
- version: "1.6.14"}};
51442
+ version: "1.6.15"}};
51344
51443
 
51345
51444
  /**
51346
51445
  * Version information about the gplayer and its main dependencies
@@ -51356,4 +51455,4 @@ function version() {
51356
51455
  };
51357
51456
  }
51358
51457
 
51359
- export { ChainedTracer, LogTracer, Logger$1 as Logger, PlaybackErrorCode, Player, PlayerEvent, SentryTracer, reportError, setTracer, trace, version };
51458
+ export { ChainedTracer, LogTracer, Logger$1 as Logger, PlaybackErrorCode, Player, PlayerEvent, RemoteTracer, SentryTracer, reportError, setTracer, trace, version };