@amazon/vinyl 3.1.0 → 3.2.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.
Files changed (51) hide show
  1. package/dist/index.cjs +207 -164
  2. package/dist/index.cjs.map +4 -4
  3. package/dist/index.js +195 -151
  4. package/dist/index.js.map +4 -4
  5. package/dist/test/integ.es5.js +201 -199
  6. package/dist/test/integ.js +417 -222
  7. package/dist/test/integ.js.map +4 -4
  8. package/dist/types/current/drm/DrmControllerImpl.d.ts +17 -1
  9. package/dist/types/current/drm/DrmControllerImpl.d.ts.map +1 -1
  10. package/dist/types/current/drm/DrmControllerImpl.js +45 -10
  11. package/dist/types/current/streaming/LoadMetric.d.ts +15 -1
  12. package/dist/types/current/streaming/LoadMetric.d.ts.map +1 -1
  13. package/dist/types/current/streaming/mediaTimelineFilter.d.ts +4 -2
  14. package/dist/types/current/streaming/mediaTimelineFilter.d.ts.map +1 -1
  15. package/dist/types/current/streaming/mediaTimelineFilter.js +23 -8
  16. package/dist/types/current/track/filters/sampleRateFilter.d.ts +8 -4
  17. package/dist/types/current/track/filters/sampleRateFilter.d.ts.map +1 -1
  18. package/dist/types/current/track/filters/sampleRateFilter.js +31 -21
  19. package/dist/types/current/track/mse/MseTrack.d.ts +0 -9
  20. package/dist/types/current/track/mse/MseTrack.d.ts.map +1 -1
  21. package/dist/types/current/track/mse/MseTrack.js +2 -29
  22. package/dist/types/current/tsconfig.tsbuildinfo +1 -1
  23. package/dist/types/current/vinyl/VinylPlayer.d.ts +5 -0
  24. package/dist/types/current/vinyl/VinylPlayer.d.ts.map +1 -1
  25. package/dist/types/current/vinyl/VinylPlayer.js +23 -1
  26. package/dist/types/ts3.7/drm/DrmControllerImpl.d.ts +17 -1
  27. package/dist/types/ts3.7/streaming/LoadMetric.d.ts +15 -1
  28. package/dist/types/ts3.7/streaming/mediaTimelineFilter.d.ts +4 -2
  29. package/dist/types/ts3.7/track/filters/sampleRateFilter.d.ts +8 -4
  30. package/dist/types/ts3.7/track/mse/MseTrack.d.ts +0 -9
  31. package/dist/types/ts3.7/vinyl/VinylPlayer.d.ts +5 -0
  32. package/dist/types/ts4.1/drm/DrmControllerImpl.d.ts +17 -1
  33. package/dist/types/ts4.1/streaming/LoadMetric.d.ts +15 -1
  34. package/dist/types/ts4.1/streaming/mediaTimelineFilter.d.ts +4 -2
  35. package/dist/types/ts4.1/track/filters/sampleRateFilter.d.ts +8 -4
  36. package/dist/types/ts4.1/track/mse/MseTrack.d.ts +0 -9
  37. package/dist/types/ts4.1/vinyl/VinylPlayer.d.ts +5 -0
  38. package/dist/types/ts4.7/drm/DrmControllerImpl.d.ts +17 -1
  39. package/dist/types/ts4.7/streaming/LoadMetric.d.ts +15 -1
  40. package/dist/types/ts4.7/streaming/mediaTimelineFilter.d.ts +4 -2
  41. package/dist/types/ts4.7/track/filters/sampleRateFilter.d.ts +8 -4
  42. package/dist/types/ts4.7/track/mse/MseTrack.d.ts +0 -9
  43. package/dist/types/ts4.7/vinyl/VinylPlayer.d.ts +5 -0
  44. package/dist/unit/types/current/drm/DrmControllerImpl.test.js +53 -9
  45. package/dist/unit/types/current/streaming/MseTrack.test.js +11 -8
  46. package/dist/unit/types/current/streaming/mediaTimelineFilter.test.js +60 -54
  47. package/dist/unit/types/current/track/filters/sampleRateFilter.test.js +75 -0
  48. package/dist/unit/types/current/tsconfig.tsbuildinfo +1 -1
  49. package/dist/unit/types/current/vinyl/VinylPlayer.test.js +33 -2
  50. package/dist/vinylTestUtil/types/current/tsconfig.tsbuildinfo +1 -1
  51. package/package.json +10 -10
package/dist/index.cjs CHANGED
@@ -2104,6 +2104,10 @@ var DrmControllerImpl = class extends import_vinyl_util24.EventHostImpl {
2104
2104
  __publicField(this, "bufferingTrackUri", null);
2105
2105
  __publicField(this, "sessionAbort", null);
2106
2106
  __publicField(this, "pendingMessageProps", null);
2107
+ // Armed per track load; latches on the first session so only the
2108
+ // critical-path session's EME/CDM setup is measured.
2109
+ __publicField(this, "keySetupSpanArmed", true);
2110
+ __publicField(this, "keySetupSpanStart", null);
2107
2111
  __publicField(this, "disposer", /* @__PURE__ */ (0, import_vinyl_util24.createDisposer)());
2108
2112
  __publicField(this, "checkIsSupportedCached", /* @__PURE__ */ (0, import_vinyl_util24.memoize)(
2109
2113
  async (params) => {
@@ -2269,6 +2273,7 @@ var DrmControllerImpl = class extends import_vinyl_util24.EventHostImpl {
2269
2273
  if (!hasMimeType(drmInfo)) {
2270
2274
  throw new DrmError("Encrypted content must have a mimeType.");
2271
2275
  }
2276
+ this.markKeySetupStart();
2272
2277
  const mediaKeys = await this.attachMediaKeys(drmInfo);
2273
2278
  this.abortIfDisposed();
2274
2279
  const keySystemOptions = (_a = this.options.keySystems[mediaKeys.keySystem]) != null ? _a : this.options.keySystems["*"];
@@ -2313,6 +2318,28 @@ var DrmControllerImpl = class extends import_vinyl_util24.EventHostImpl {
2313
2318
  });
2314
2319
  return newSession;
2315
2320
  }
2321
+ /**
2322
+ * Captures the key-setup span start at the top of the session-creation path
2323
+ * (before media keys are attached), latching so only the first session of
2324
+ * the current track load is measured.
2325
+ */
2326
+ markKeySetupStart() {
2327
+ if (!this.keySetupSpanArmed) return;
2328
+ this.keySetupSpanArmed = false;
2329
+ this.keySetupSpanStart = Date.now();
2330
+ }
2331
+ dispatchLoadSpan(kind, startTime, endTime, messageProps) {
2332
+ this.dispatch("loadSpanMeasured", __spreadValues(__spreadValues({
2333
+ kind,
2334
+ startTime,
2335
+ endTime,
2336
+ mimeType: messageProps.mimeType
2337
+ }, messageProps.trackUri != null && {
2338
+ trackUri: messageProps.trackUri
2339
+ }), messageProps.contentType != null && {
2340
+ contentType: messageProps.contentType
2341
+ }));
2342
+ }
2316
2343
  initializeForPlayback(drmInfo, options) {
2317
2344
  var _a;
2318
2345
  (0, import_vinyl_util24.logDebug)(this, "initializeForPlayback", drmInfo);
@@ -2336,6 +2363,8 @@ var DrmControllerImpl = class extends import_vinyl_util24.EventHostImpl {
2336
2363
  this.drmInfo = drmInfo;
2337
2364
  this.bufferingTrackUri = (_a = options == null ? void 0 : options.trackUri) != null ? _a : null;
2338
2365
  this.sessionAbort = (_b = options == null ? void 0 : options.abort) != null ? _b : null;
2366
+ this.keySetupSpanArmed = true;
2367
+ this.keySetupSpanStart = null;
2339
2368
  }
2340
2369
  /**
2341
2370
  * If the drm metadata contains initialization data for the current key system, create a new session.
@@ -2347,6 +2376,7 @@ var DrmControllerImpl = class extends import_vinyl_util24.EventHostImpl {
2347
2376
  this.handleError(new DrmError("DRM not supported."));
2348
2377
  return;
2349
2378
  }
2379
+ this.markKeySetupStart();
2350
2380
  const mediaKeys = await this.attachMediaKeys(drmInfo);
2351
2381
  const drmProtection = (_a = drmInfo.contentProtections.find((cP) => {
2352
2382
  return cP.keySystem === mediaKeys.keySystem;
@@ -2485,7 +2515,9 @@ var DrmControllerImpl = class extends import_vinyl_util24.EventHostImpl {
2485
2515
  event,
2486
2516
  // Captured per session, so a concurrent preloaded track's
2487
2517
  // license exchange keeps its own attribution.
2488
- trackUri
2518
+ trackUri,
2519
+ mimeType: drmInfo.mimeType,
2520
+ contentType: drmInfo.contentType
2489
2521
  }),
2490
2522
  LICENSE_TIMEOUT,
2491
2523
  { message: LICENSE_TIMEOUT_MESSAGE }
@@ -2507,6 +2539,15 @@ var DrmControllerImpl = class extends import_vinyl_util24.EventHostImpl {
2507
2539
  this.pendingMessageProps = messageProps;
2508
2540
  const keySystem = mediaKeys.keySystem;
2509
2541
  (0, import_vinyl_util24.logDebug)(this, "message", keySystem, event.message.byteLength);
2542
+ if (this.keySetupSpanStart != null) {
2543
+ this.dispatchLoadSpan(
2544
+ "keySetup",
2545
+ this.keySetupSpanStart,
2546
+ Date.now(),
2547
+ messageProps
2548
+ );
2549
+ this.keySetupSpanStart = null;
2550
+ }
2510
2551
  const keySystemOptions = (_a = this.options.keySystems[keySystem]) != null ? _a : this.options.keySystems["*"];
2511
2552
  const licenseServerOptionsProvider = keySystemOptions == null ? void 0 : keySystemOptions.licenseServer;
2512
2553
  const licenseServerOptions = (_b = (0, import_vinyl_util24.clone)(await (0, import_vinyl_util24.resolveValueProvider)(licenseServerOptionsProvider))) != null ? _b : {};
@@ -2528,13 +2569,12 @@ var DrmControllerImpl = class extends import_vinyl_util24.EventHostImpl {
2528
2569
  challenge
2529
2570
  );
2530
2571
  if (this.disposed) return;
2531
- this.dispatch("loadSpanMeasured", __spreadValues({
2532
- kind: "license",
2533
- startTime: licenseSpanStart,
2534
- endTime: Date.now()
2535
- }, messageProps.trackUri != null && {
2536
- trackUri: messageProps.trackUri
2537
- }));
2572
+ this.dispatchLoadSpan(
2573
+ "license",
2574
+ licenseSpanStart,
2575
+ Date.now(),
2576
+ messageProps
2577
+ );
2538
2578
  this.pendingMessageProps = null;
2539
2579
  if (session.disposed) return;
2540
2580
  (0, import_vinyl_util24.logDebug)(this, "update");
@@ -2777,7 +2817,7 @@ function configureVinylGlobal(options) {
2777
2817
  var import_vinyl_util27 = require("@amazon/vinyl-util");
2778
2818
  var vinylVersion = /* @__PURE__ */ (0, import_vinyl_util27.parseVersion)(
2779
2819
  /* istanbul ignore next */
2780
- "3.1.0"
2820
+ "3.2.0"
2781
2821
  );
2782
2822
 
2783
2823
  // src/global/globalRef.ts
@@ -5108,16 +5148,102 @@ function filterContentTypes(contentTypes, allowedContentTypes) {
5108
5148
  // src/streaming/createDefaultMediaTimelineTransformer.ts
5109
5149
  var import_vinyl_observable2 = require("@amazon/vinyl-observable");
5110
5150
 
5151
+ // src/streaming/MediaQualityMetadata.ts
5152
+ var import_vinyl_util53 = require("@amazon/vinyl-util");
5153
+ var import_vinyl_validation10 = require("@amazon/vinyl-validation");
5154
+
5155
+ // src/streaming/DescriptorRecord.ts
5156
+ var import_vinyl_validation9 = require("@amazon/vinyl-validation");
5157
+ var import_vinyl_util52 = require("@amazon/vinyl-util");
5158
+ function getDescriptorValue(record4, uri, id) {
5159
+ var _a, _b;
5160
+ let arr = record4[uri];
5161
+ if (!arr) return null;
5162
+ if (id !== void 0) arr = arr.filter((descriptor) => descriptor.id === id);
5163
+ return (_b = (_a = (0, import_vinyl_util52.first)(arr)) == null ? void 0 : _a.value) != null ? _b : null;
5164
+ }
5165
+ var descriptorValidator = /* @__PURE__ */ (0, import_vinyl_validation9.object)({
5166
+ id: /* @__PURE__ */ (0, import_vinyl_validation9.string)().maybe().optional(),
5167
+ value: /* @__PURE__ */ (0, import_vinyl_validation9.string)().maybe().optional()
5168
+ });
5169
+ var descriptorRecordValidator = /* @__PURE__ */ (0, import_vinyl_validation9.record)(/* @__PURE__ */ (0, import_vinyl_validation9.string)(), /* @__PURE__ */ (0, import_vinyl_validation9.array)(descriptorValidator).readonly().orUndefined());
5170
+
5171
+ // src/streaming/MediaQualityMetadata.ts
5172
+ var ALL_CONTENT_TYPES = [
5173
+ "video",
5174
+ "audio",
5175
+ "text"
5176
+ ];
5177
+ var RESTRICTABLE_CONTENT_TYPES = [
5178
+ "video",
5179
+ "audio"
5180
+ ];
5181
+ var drmProtectionValidator = /* @__PURE__ */ descriptorValidator.extend({
5182
+ keySystem: /* @__PURE__ */ (0, import_vinyl_validation10.enumOf)(DrmKeySystem),
5183
+ pro: /* @__PURE__ */ (0, import_vinyl_validation10.string)().maybe().optional(),
5184
+ pssh: /* @__PURE__ */ (0, import_vinyl_validation10.string)().maybe().optional()
5185
+ });
5186
+ var mediaFormatMetadataValidator = /* @__PURE__ */ (0, import_vinyl_validation10.object)({
5187
+ contentProtections: /* @__PURE__ */ (0, import_vinyl_validation10.array)(drmProtectionValidator).readonly(),
5188
+ contentType: /* @__PURE__ */ (0, import_vinyl_validation10.isOneOf)("audio", "video", "text").orNull(),
5189
+ initDataType: /* @__PURE__ */ (0, import_vinyl_validation10.string)().orNull(),
5190
+ encryptionScheme: /* @__PURE__ */ (0, import_vinyl_validation10.string)().orNull(),
5191
+ mimeType: /* @__PURE__ */ (0, import_vinyl_validation10.string)().orNull()
5192
+ });
5193
+ function createEmptyMediaFormatMetadata() {
5194
+ return {
5195
+ contentType: null,
5196
+ mimeType: null,
5197
+ initDataType: null,
5198
+ encryptionScheme: null,
5199
+ contentProtections: []
5200
+ };
5201
+ }
5202
+ function createEmptyMediaQualityMetadata() {
5203
+ return __spreadProps(__spreadValues({}, createEmptyMediaFormatMetadata()), {
5204
+ decoderId: (0, import_vinyl_util53.createShortUid)(),
5205
+ qualityId: (0, import_vinyl_util53.createShortUid)(),
5206
+ codecs: null,
5207
+ bandwidth: null,
5208
+ bandwidthTotal: null,
5209
+ supplementalProperties: {},
5210
+ audioSamplingRate: null,
5211
+ frameRate: null,
5212
+ height: null,
5213
+ width: null,
5214
+ lang: null,
5215
+ characteristics: [],
5216
+ groupId: (0, import_vinyl_util53.createShortUid)(),
5217
+ switchingGroupIds: null
5218
+ });
5219
+ }
5220
+ var mediaQualityMetadataValidator = /* @__PURE__ */ mediaFormatMetadataValidator.extend({
5221
+ audioSamplingRate: /* @__PURE__ */ (0, import_vinyl_validation10.array)(/* @__PURE__ */ (0, import_vinyl_validation10.number)()).readonly().orNull(),
5222
+ bandwidth: /* @__PURE__ */ (0, import_vinyl_validation10.number)().orNull(),
5223
+ bandwidthTotal: /* @__PURE__ */ (0, import_vinyl_validation10.number)().orNull(),
5224
+ codecs: /* @__PURE__ */ (0, import_vinyl_validation10.string)().orNull(),
5225
+ decoderId: /* @__PURE__ */ (0, import_vinyl_validation10.string)(),
5226
+ frameRate: /* @__PURE__ */ (0, import_vinyl_validation10.tuple)(/* @__PURE__ */ (0, import_vinyl_validation10.number)(), /* @__PURE__ */ (0, import_vinyl_validation10.number)()).readonly().orNull(),
5227
+ height: /* @__PURE__ */ (0, import_vinyl_validation10.number)().orNull(),
5228
+ qualityId: /* @__PURE__ */ (0, import_vinyl_validation10.string)(),
5229
+ supplementalProperties: descriptorRecordValidator,
5230
+ width: /* @__PURE__ */ (0, import_vinyl_validation10.number)().orNull(),
5231
+ lang: /* @__PURE__ */ (0, import_vinyl_validation10.string)().orNull(),
5232
+ characteristics: /* @__PURE__ */ (0, import_vinyl_validation10.array)(/* @__PURE__ */ (0, import_vinyl_validation10.string)()).readonly(),
5233
+ groupId: /* @__PURE__ */ (0, import_vinyl_validation10.string)(),
5234
+ switchingGroupIds: /* @__PURE__ */ (0, import_vinyl_validation10.array)(/* @__PURE__ */ (0, import_vinyl_validation10.string)()).readonly().orNull()
5235
+ });
5236
+
5111
5237
  // src/streaming/mediaTimelineFilter.ts
5112
- var import_vinyl_util54 = require("@amazon/vinyl-util");
5238
+ var import_vinyl_util56 = require("@amazon/vinyl-util");
5113
5239
 
5114
5240
  // src/streaming/mediaTimelineLanguageFilter.ts
5115
- var import_vinyl_util53 = require("@amazon/vinyl-util");
5241
+ var import_vinyl_util55 = require("@amazon/vinyl-util");
5116
5242
 
5117
5243
  // src/track/filters/languageFilter.ts
5118
- var import_vinyl_util52 = require("@amazon/vinyl-util");
5244
+ var import_vinyl_util54 = require("@amazon/vinyl-util");
5119
5245
  function throwLanguagesUnsupported() {
5120
- throw new import_vinyl_util52.MediaUnsupportedError(
5246
+ throw new import_vinyl_util54.MediaUnsupportedError(
5121
5247
  "No content matching preferred language",
5122
5248
  "language"
5123
5249
  );
@@ -5347,9 +5473,9 @@ function languageRelatedness(target, candidate) {
5347
5473
  return 1;
5348
5474
  }
5349
5475
  function findBestLanguageMatch(target, available) {
5350
- return (0, import_vinyl_util52.max)(
5476
+ return (0, import_vinyl_util54.max)(
5351
5477
  available,
5352
- (0, import_vinyl_util52.compareBy)((lang) => languageRelatedness(target, lang))
5478
+ (0, import_vinyl_util54.compareBy)((lang) => languageRelatedness(target, lang))
5353
5479
  );
5354
5480
  }
5355
5481
 
@@ -5373,7 +5499,7 @@ function createLanguageFilter(preferredLanguage, contentType2) {
5373
5499
  }
5374
5500
  return best;
5375
5501
  };
5376
- const bestScoreForPeriod = (0, import_vinyl_util53.memoize)(
5502
+ const bestScoreForPeriod = (0, import_vinyl_util55.memoize)(
5377
5503
  (array6) => {
5378
5504
  let best = 0;
5379
5505
  for (const quality of Array.from(array6)) {
@@ -5396,10 +5522,17 @@ function createLanguageFilter(preferredLanguage, contentType2) {
5396
5522
  }
5397
5523
 
5398
5524
  // src/streaming/mediaTimelineFilter.ts
5525
+ function assertMediaStreamsRetained(original, filtered, throwError) {
5526
+ for (const contentType2 of RESTRICTABLE_CONTENT_TYPES) {
5527
+ if (original.some((q) => q.metadata.contentType === contentType2) && !filtered.some((q) => q.metadata.contentType === contentType2)) {
5528
+ throwError();
5529
+ }
5530
+ }
5531
+ }
5399
5532
  function filterTimelineQualities(filter, throwError, timeline) {
5400
5533
  if (!filter) return timeline;
5401
- const mapMetadataArray = (0, import_vinyl_util54.memoize)(
5402
- (qualities) => (0, import_vinyl_util54.map)(qualities, (q) => q.metadata),
5534
+ const mapMetadataArray = (0, import_vinyl_util56.memoize)(
5535
+ (qualities) => (0, import_vinyl_util56.map)(qualities, (q) => q.metadata),
5403
5536
  (qualities) => qualities,
5404
5537
  1
5405
5538
  );
@@ -5407,16 +5540,14 @@ function filterTimelineQualities(filter, throwError, timeline) {
5407
5540
  const filtered = period.qualities.filter(
5408
5541
  (q, index) => filter(q.metadata, index, mapMetadataArray(period.qualities))
5409
5542
  );
5543
+ assertMediaStreamsRetained(period.qualities, filtered, throwError);
5410
5544
  return __spreadProps(__spreadValues({}, period), { qualities: filtered });
5411
5545
  });
5412
- if (periods.some((p) => p.qualities.length === 0)) {
5413
- throwError();
5414
- }
5415
5546
  return __spreadProps(__spreadValues({}, timeline), { periods });
5416
5547
  }
5417
5548
  async function filterTimelineQualitiesAsync(filter, throwError, timeline) {
5418
- const mapMetadataArray = (0, import_vinyl_util54.memoize)(
5419
- (qualities) => (0, import_vinyl_util54.map)(qualities, (q) => q.metadata),
5549
+ const mapMetadataArray = (0, import_vinyl_util56.memoize)(
5550
+ (qualities) => (0, import_vinyl_util56.map)(qualities, (q) => q.metadata),
5420
5551
  (qualities) => qualities,
5421
5552
  1
5422
5553
  );
@@ -5429,18 +5560,16 @@ async function filterTimelineQualitiesAsync(filter, throwError, timeline) {
5429
5560
  filtered.push(period.qualities[i]);
5430
5561
  }
5431
5562
  }
5563
+ assertMediaStreamsRetained(period.qualities, filtered, throwError);
5432
5564
  periods.push(__spreadProps(__spreadValues({}, period), { qualities: filtered }));
5433
5565
  }
5434
- if (periods.some((p) => p.qualities.length === 0)) {
5435
- throwError();
5436
- }
5437
5566
  return __spreadProps(__spreadValues({}, timeline), { periods });
5438
5567
  }
5439
5568
 
5440
5569
  // src/streaming/mediaTimelineAccessibilityFilter.ts
5441
- var import_vinyl_util55 = require("@amazon/vinyl-util");
5570
+ var import_vinyl_util57 = require("@amazon/vinyl-util");
5442
5571
  function throwNoPlayableAudio() {
5443
- throw new import_vinyl_util55.MediaUnsupportedError("No playable audio rendition", "audio");
5572
+ throw new import_vinyl_util57.MediaUnsupportedError("No playable audio rendition", "audio");
5444
5573
  }
5445
5574
  var AUDIO_DESCRIPTION_CHARACTERISTICS = [
5446
5575
  "public.accessibility.describes-video",
@@ -5452,7 +5581,7 @@ function isAudioDescription(quality) {
5452
5581
  );
5453
5582
  }
5454
5583
  function createAudioDescriptionFilter(preferDescription) {
5455
- const periodFlags = (0, import_vinyl_util55.memoize)(
5584
+ const periodFlags = (0, import_vinyl_util57.memoize)(
5456
5585
  (array6) => {
5457
5586
  let hasDescription = false;
5458
5587
  let hasMain = false;
@@ -5479,9 +5608,9 @@ function createAudioDescriptionFilter(preferDescription) {
5479
5608
  }
5480
5609
 
5481
5610
  // src/track/filters/resourceTypeFilter.ts
5482
- var import_vinyl_util56 = require("@amazon/vinyl-util");
5611
+ var import_vinyl_util58 = require("@amazon/vinyl-util");
5483
5612
  function throwMimeTypesUnsupported() {
5484
- throw new import_vinyl_util56.MediaUnsupportedError(
5613
+ throw new import_vinyl_util58.MediaUnsupportedError(
5485
5614
  "No resource type supported (container/codec).",
5486
5615
  "resource-type"
5487
5616
  );
@@ -5492,9 +5621,9 @@ function canPlayMimeType(deps, metadata) {
5492
5621
  }
5493
5622
 
5494
5623
  // src/track/filters/keySystemFilter.ts
5495
- var import_vinyl_util57 = require("@amazon/vinyl-util");
5624
+ var import_vinyl_util59 = require("@amazon/vinyl-util");
5496
5625
  function throwKeySystemsUnsupported() {
5497
- throw new import_vinyl_util57.MediaUnsupportedError("No key system supported.", "key-system");
5626
+ throw new import_vinyl_util59.MediaUnsupportedError("No key system supported.", "key-system");
5498
5627
  }
5499
5628
  async function canPlayKeySystem(deps, metadata) {
5500
5629
  if (!metadata.contentProtections.length) return true;
@@ -5502,32 +5631,37 @@ async function canPlayKeySystem(deps, metadata) {
5502
5631
  }
5503
5632
 
5504
5633
  // src/track/filters/sampleRateFilter.ts
5505
- var import_vinyl_util58 = require("@amazon/vinyl-util");
5634
+ var import_vinyl_util60 = require("@amazon/vinyl-util");
5506
5635
  function throwSamplingRatesUnsupported() {
5507
- throw new import_vinyl_util58.MediaUnsupportedError("No supported sample rate", "sampling-rate");
5636
+ throw new import_vinyl_util60.MediaUnsupportedError("No supported sample rate", "sampling-rate");
5508
5637
  }
5509
5638
  function withinAudioSampleRateRange(options, metadata, _index, array6) {
5510
5639
  var _a;
5511
5640
  if (metadata.contentType !== "audio") return true;
5512
- const samplingRate = (0, import_vinyl_util58.last)(metadata.audioSamplingRate);
5641
+ const samplingRate = (0, import_vinyl_util60.last)(metadata.audioSamplingRate);
5513
5642
  if (!samplingRate) return true;
5514
- const audioRates = () => (0, import_vinyl_util58.map)(
5643
+ const { minSampleRate } = options;
5644
+ const maxSampleRate = (_a = options.maxSampleRate) != null ? _a : options.capabilities.sampleRate;
5645
+ const audioRates = () => (0, import_vinyl_util60.map)(
5515
5646
  array6,
5516
- (item) => item.contentType === "audio" ? (0, import_vinyl_util58.last)(item.audioSamplingRate) : void 0
5647
+ (item) => item.contentType === "audio" ? (0, import_vinyl_util60.last)(item.audioSamplingRate) : void 0
5517
5648
  ).filter((rate) => rate != null);
5518
- const { minSampleRate } = options;
5649
+ const outOfBandFallback = () => {
5650
+ const rates = audioRates();
5651
+ const inBand = (rate) => (minSampleRate == null || rate >= minSampleRate) && (!maxSampleRate || rate <= maxSampleRate);
5652
+ if (rates.some(inBand)) return void 0;
5653
+ const decodable = maxSampleRate ? rates.filter((rate) => rate <= maxSampleRate) : rates;
5654
+ return decodable.length ? (0, import_vinyl_util60.max)(decodable) : (0, import_vinyl_util60.min)(rates);
5655
+ };
5519
5656
  if (minSampleRate != null && samplingRate < minSampleRate) {
5520
- const rates2 = audioRates();
5521
- return (0, import_vinyl_util58.every)(rates2, (rate) => rate < minSampleRate) && samplingRate === (0, import_vinyl_util58.max)(rates2);
5657
+ return samplingRate === outOfBandFallback();
5522
5658
  }
5523
- const maxSampleRate = (_a = options.maxSampleRate) != null ? _a : options.capabilities.sampleRate;
5524
5659
  if (!maxSampleRate) return true;
5525
- if ((0, import_vinyl_util58.hasBrowser)(import_vinyl_util58.Browser.FIREFOX)) {
5660
+ if ((0, import_vinyl_util60.hasBrowser)(import_vinyl_util60.Browser.FIREFOX)) {
5526
5661
  return samplingRate <= 48e3;
5527
5662
  }
5528
5663
  if (samplingRate <= maxSampleRate) return true;
5529
- const rates = audioRates();
5530
- return (0, import_vinyl_util58.every)(rates, (rate) => rate > maxSampleRate) && samplingRate === (0, import_vinyl_util58.min)(rates);
5664
+ return samplingRate === outOfBandFallback();
5531
5665
  }
5532
5666
 
5533
5667
  // src/util/media/codecOverrides.ts
@@ -5614,33 +5748,17 @@ function createDefaultMediaTimelineTransformer(deps) {
5614
5748
  });
5615
5749
  }
5616
5750
 
5617
- // src/streaming/DescriptorRecord.ts
5618
- var import_vinyl_validation9 = require("@amazon/vinyl-validation");
5619
- var import_vinyl_util59 = require("@amazon/vinyl-util");
5620
- function getDescriptorValue(record4, uri, id) {
5621
- var _a, _b;
5622
- let arr = record4[uri];
5623
- if (!arr) return null;
5624
- if (id !== void 0) arr = arr.filter((descriptor) => descriptor.id === id);
5625
- return (_b = (_a = (0, import_vinyl_util59.first)(arr)) == null ? void 0 : _a.value) != null ? _b : null;
5626
- }
5627
- var descriptorValidator = /* @__PURE__ */ (0, import_vinyl_validation9.object)({
5628
- id: /* @__PURE__ */ (0, import_vinyl_validation9.string)().maybe().optional(),
5629
- value: /* @__PURE__ */ (0, import_vinyl_validation9.string)().maybe().optional()
5630
- });
5631
- var descriptorRecordValidator = /* @__PURE__ */ (0, import_vinyl_validation9.record)(/* @__PURE__ */ (0, import_vinyl_validation9.string)(), /* @__PURE__ */ (0, import_vinyl_validation9.array)(descriptorValidator).readonly().orUndefined());
5632
-
5633
5751
  // src/streaming/ManifestControllerImpl.ts
5634
5752
  var import_vinyl_observable3 = require("@amazon/vinyl-observable");
5635
- var import_vinyl_util60 = require("@amazon/vinyl-util");
5753
+ var import_vinyl_util61 = require("@amazon/vinyl-util");
5636
5754
  var ManifestControllerImpl = class {
5637
5755
  constructor(deps) {
5638
5756
  __publicField(this, "deps", deps);
5639
5757
  __publicField(this, "_data");
5640
5758
  __publicField(this, "_error", null);
5641
- __publicField(this, "abortSlot", /* @__PURE__ */ (0, import_vinyl_util60.createAbortSlot)());
5642
- __publicField(this, "disposer", /* @__PURE__ */ (0, import_vinyl_util60.createDisposer)());
5643
- __publicField(this, "events", /* @__PURE__ */ new import_vinyl_util60.EventHostImpl());
5759
+ __publicField(this, "abortSlot", /* @__PURE__ */ (0, import_vinyl_util61.createAbortSlot)());
5760
+ __publicField(this, "disposer", /* @__PURE__ */ (0, import_vinyl_util61.createDisposer)());
5761
+ __publicField(this, "events", /* @__PURE__ */ new import_vinyl_util61.EventHostImpl());
5644
5762
  __publicField(this, "manifestSpanArmed", true);
5645
5763
  __publicField(this, "__eventMapType", this.events.__eventMapType);
5646
5764
  this._data = (0, import_vinyl_observable3.data)(this.requestManifest());
@@ -5667,7 +5785,7 @@ var ManifestControllerImpl = class {
5667
5785
  return this._error;
5668
5786
  }
5669
5787
  refresh() {
5670
- (0, import_vinyl_util60.logDebug)(this, "refresh");
5788
+ (0, import_vinyl_util61.logDebug)(this, "refresh");
5671
5789
  this._data.value = this.requestManifest();
5672
5790
  }
5673
5791
  requestManifest() {
@@ -5698,7 +5816,7 @@ var ManifestControllerImpl = class {
5698
5816
  );
5699
5817
  }
5700
5818
  reset() {
5701
- (0, import_vinyl_util60.logDebug)(this, "reset");
5819
+ (0, import_vinyl_util61.logDebug)(this, "reset");
5702
5820
  if (this._error) {
5703
5821
  this.refresh();
5704
5822
  }
@@ -5731,74 +5849,6 @@ var ManifestControllerImpl = class {
5731
5849
  }
5732
5850
  };
5733
5851
 
5734
- // src/streaming/MediaQualityMetadata.ts
5735
- var import_vinyl_util61 = require("@amazon/vinyl-util");
5736
- var import_vinyl_validation10 = require("@amazon/vinyl-validation");
5737
- var ALL_CONTENT_TYPES = [
5738
- "video",
5739
- "audio",
5740
- "text"
5741
- ];
5742
- var RESTRICTABLE_CONTENT_TYPES = [
5743
- "video",
5744
- "audio"
5745
- ];
5746
- var drmProtectionValidator = /* @__PURE__ */ descriptorValidator.extend({
5747
- keySystem: /* @__PURE__ */ (0, import_vinyl_validation10.enumOf)(DrmKeySystem),
5748
- pro: /* @__PURE__ */ (0, import_vinyl_validation10.string)().maybe().optional(),
5749
- pssh: /* @__PURE__ */ (0, import_vinyl_validation10.string)().maybe().optional()
5750
- });
5751
- var mediaFormatMetadataValidator = /* @__PURE__ */ (0, import_vinyl_validation10.object)({
5752
- contentProtections: /* @__PURE__ */ (0, import_vinyl_validation10.array)(drmProtectionValidator).readonly(),
5753
- contentType: /* @__PURE__ */ (0, import_vinyl_validation10.isOneOf)("audio", "video", "text").orNull(),
5754
- initDataType: /* @__PURE__ */ (0, import_vinyl_validation10.string)().orNull(),
5755
- encryptionScheme: /* @__PURE__ */ (0, import_vinyl_validation10.string)().orNull(),
5756
- mimeType: /* @__PURE__ */ (0, import_vinyl_validation10.string)().orNull()
5757
- });
5758
- function createEmptyMediaFormatMetadata() {
5759
- return {
5760
- contentType: null,
5761
- mimeType: null,
5762
- initDataType: null,
5763
- encryptionScheme: null,
5764
- contentProtections: []
5765
- };
5766
- }
5767
- function createEmptyMediaQualityMetadata() {
5768
- return __spreadProps(__spreadValues({}, createEmptyMediaFormatMetadata()), {
5769
- decoderId: (0, import_vinyl_util61.createShortUid)(),
5770
- qualityId: (0, import_vinyl_util61.createShortUid)(),
5771
- codecs: null,
5772
- bandwidth: null,
5773
- bandwidthTotal: null,
5774
- supplementalProperties: {},
5775
- audioSamplingRate: null,
5776
- frameRate: null,
5777
- height: null,
5778
- width: null,
5779
- lang: null,
5780
- characteristics: [],
5781
- groupId: (0, import_vinyl_util61.createShortUid)(),
5782
- switchingGroupIds: null
5783
- });
5784
- }
5785
- var mediaQualityMetadataValidator = /* @__PURE__ */ mediaFormatMetadataValidator.extend({
5786
- audioSamplingRate: /* @__PURE__ */ (0, import_vinyl_validation10.array)(/* @__PURE__ */ (0, import_vinyl_validation10.number)()).readonly().orNull(),
5787
- bandwidth: /* @__PURE__ */ (0, import_vinyl_validation10.number)().orNull(),
5788
- bandwidthTotal: /* @__PURE__ */ (0, import_vinyl_validation10.number)().orNull(),
5789
- codecs: /* @__PURE__ */ (0, import_vinyl_validation10.string)().orNull(),
5790
- decoderId: /* @__PURE__ */ (0, import_vinyl_validation10.string)(),
5791
- frameRate: /* @__PURE__ */ (0, import_vinyl_validation10.tuple)(/* @__PURE__ */ (0, import_vinyl_validation10.number)(), /* @__PURE__ */ (0, import_vinyl_validation10.number)()).readonly().orNull(),
5792
- height: /* @__PURE__ */ (0, import_vinyl_validation10.number)().orNull(),
5793
- qualityId: /* @__PURE__ */ (0, import_vinyl_validation10.string)(),
5794
- supplementalProperties: descriptorRecordValidator,
5795
- width: /* @__PURE__ */ (0, import_vinyl_validation10.number)().orNull(),
5796
- lang: /* @__PURE__ */ (0, import_vinyl_validation10.string)().orNull(),
5797
- characteristics: /* @__PURE__ */ (0, import_vinyl_validation10.array)(/* @__PURE__ */ (0, import_vinyl_validation10.string)()).readonly(),
5798
- groupId: /* @__PURE__ */ (0, import_vinyl_validation10.string)(),
5799
- switchingGroupIds: /* @__PURE__ */ (0, import_vinyl_validation10.array)(/* @__PURE__ */ (0, import_vinyl_validation10.string)()).readonly().orNull()
5800
- });
5801
-
5802
5852
  // src/streaming/MediaTimeline.ts
5803
5853
  var import_vinyl_util62 = require("@amazon/vinyl-util");
5804
5854
  function getMediaPeriodAtTime(timeline, time) {
@@ -7955,10 +8005,7 @@ var MseTrack = class extends TrackBase {
7955
8005
  this.deps = deps;
7956
8006
  add(
7957
8007
  deps.contentTypesValue.onData((contentTypesPromise) => {
7958
- contentTypesPromise.then((value) => {
7959
- this.setContentTypes(value);
7960
- this.validateRequiredContentTypesPlayable();
7961
- }).catch(this.errorHandler);
8008
+ contentTypesPromise.then((value) => this.setContentTypes(value)).catch(this.errorHandler);
7962
8009
  })
7963
8010
  );
7964
8011
  this.on("streamingQualityChange", (event) => {
@@ -8059,33 +8106,8 @@ var MseTrack = class extends TrackBase {
8059
8106
  });
8060
8107
  }
8061
8108
  }
8062
- this.validateRequiredContentTypesPlayable();
8063
8109
  });
8064
8110
  }
8065
- /**
8066
- * Fails fast when a media content type the manifest declared (audio/video)
8067
- * has no playable qualities left after timeline filtering. Its stream can
8068
- * never create a source buffer, so without this the track waits forever for
8069
- * a source buffer that never arrives, surfacing only as an opaque
8070
- * `readyToAppend` timeout. Runs once both the required content types and the
8071
- * filtered timeline qualities are known (either order).
8072
- */
8073
- validateRequiredContentTypesPlayable() {
8074
- const qualities = this._qualities;
8075
- if (!qualities) return;
8076
- const present = new Set(qualities.map((q) => q.contentType));
8077
- for (const contentType2 of this._contentTypes) {
8078
- if (!present.has(contentType2)) {
8079
- this.errorHandler(
8080
- new import_vinyl_util80.MediaUnsupportedError(
8081
- `No playable ${contentType2} rendition`,
8082
- `no-playable-${contentType2}`
8083
- )
8084
- );
8085
- return;
8086
- }
8087
- }
8088
- }
8089
8111
  async getAds() {
8090
8112
  const timeline = await this.deps.mediaTimeline.value;
8091
8113
  return {
@@ -10482,6 +10504,7 @@ var VinylPlayer = class extends import_vinyl_util99.EventHostImpl {
10482
10504
  playerRegistryRef.value.addPlayer(this);
10483
10505
  this.redispatchSubControllerEvents();
10484
10506
  this.redispatchCurrentTrackEvents();
10507
+ this.initializeLoadSpanLogging();
10485
10508
  this.initializeAutoResetHandling();
10486
10509
  }
10487
10510
  get [Symbol.toStringTag]() {
@@ -10499,6 +10522,26 @@ var VinylPlayer = class extends import_vinyl_util99.EventHostImpl {
10499
10522
  get autoResetController() {
10500
10523
  return this.deps.autoResetController;
10501
10524
  }
10525
+ /**
10526
+ * Logs each republished load span once at the verbose level, formatting its
10527
+ * bounds as ISO date strings and its duration in milliseconds.
10528
+ */
10529
+ initializeLoadSpanLogging() {
10530
+ this.disposer.add(
10531
+ this.on("loadSpan", (span) => {
10532
+ if ((0, import_vinyl_util99.getLogLevel)() > import_vinyl_util99.LogLevel.VERBOSE) return;
10533
+ (0, import_vinyl_util99.logVerbose)(this, "loadSpan", {
10534
+ kind: span.kind,
10535
+ trackUri: span.trackUri,
10536
+ mimeType: span.mimeType,
10537
+ contentType: span.contentType,
10538
+ startTime: new Date(span.startTime).toISOString(),
10539
+ endTime: new Date(span.endTime).toISOString(),
10540
+ durationMs: (span.endTime - span.startTime).toFixed(2)
10541
+ });
10542
+ })
10543
+ );
10544
+ }
10502
10545
  redispatchSubControllerEvents() {
10503
10546
  const add = this.disposer.add;
10504
10547
  add(