@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.
- package/dist/index.cjs +207 -164
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +195 -151
- package/dist/index.js.map +4 -4
- package/dist/test/integ.es5.js +201 -199
- package/dist/test/integ.js +417 -222
- package/dist/test/integ.js.map +4 -4
- package/dist/types/current/drm/DrmControllerImpl.d.ts +17 -1
- package/dist/types/current/drm/DrmControllerImpl.d.ts.map +1 -1
- package/dist/types/current/drm/DrmControllerImpl.js +45 -10
- package/dist/types/current/streaming/LoadMetric.d.ts +15 -1
- package/dist/types/current/streaming/LoadMetric.d.ts.map +1 -1
- package/dist/types/current/streaming/mediaTimelineFilter.d.ts +4 -2
- package/dist/types/current/streaming/mediaTimelineFilter.d.ts.map +1 -1
- package/dist/types/current/streaming/mediaTimelineFilter.js +23 -8
- package/dist/types/current/track/filters/sampleRateFilter.d.ts +8 -4
- package/dist/types/current/track/filters/sampleRateFilter.d.ts.map +1 -1
- package/dist/types/current/track/filters/sampleRateFilter.js +31 -21
- package/dist/types/current/track/mse/MseTrack.d.ts +0 -9
- package/dist/types/current/track/mse/MseTrack.d.ts.map +1 -1
- package/dist/types/current/track/mse/MseTrack.js +2 -29
- package/dist/types/current/tsconfig.tsbuildinfo +1 -1
- package/dist/types/current/vinyl/VinylPlayer.d.ts +5 -0
- package/dist/types/current/vinyl/VinylPlayer.d.ts.map +1 -1
- package/dist/types/current/vinyl/VinylPlayer.js +23 -1
- package/dist/types/ts3.7/drm/DrmControllerImpl.d.ts +17 -1
- package/dist/types/ts3.7/streaming/LoadMetric.d.ts +15 -1
- package/dist/types/ts3.7/streaming/mediaTimelineFilter.d.ts +4 -2
- package/dist/types/ts3.7/track/filters/sampleRateFilter.d.ts +8 -4
- package/dist/types/ts3.7/track/mse/MseTrack.d.ts +0 -9
- package/dist/types/ts3.7/vinyl/VinylPlayer.d.ts +5 -0
- package/dist/types/ts4.1/drm/DrmControllerImpl.d.ts +17 -1
- package/dist/types/ts4.1/streaming/LoadMetric.d.ts +15 -1
- package/dist/types/ts4.1/streaming/mediaTimelineFilter.d.ts +4 -2
- package/dist/types/ts4.1/track/filters/sampleRateFilter.d.ts +8 -4
- package/dist/types/ts4.1/track/mse/MseTrack.d.ts +0 -9
- package/dist/types/ts4.1/vinyl/VinylPlayer.d.ts +5 -0
- package/dist/types/ts4.7/drm/DrmControllerImpl.d.ts +17 -1
- package/dist/types/ts4.7/streaming/LoadMetric.d.ts +15 -1
- package/dist/types/ts4.7/streaming/mediaTimelineFilter.d.ts +4 -2
- package/dist/types/ts4.7/track/filters/sampleRateFilter.d.ts +8 -4
- package/dist/types/ts4.7/track/mse/MseTrack.d.ts +0 -9
- package/dist/types/ts4.7/vinyl/VinylPlayer.d.ts +5 -0
- package/dist/unit/types/current/drm/DrmControllerImpl.test.js +53 -9
- package/dist/unit/types/current/streaming/MseTrack.test.js +11 -8
- package/dist/unit/types/current/streaming/mediaTimelineFilter.test.js +60 -54
- package/dist/unit/types/current/track/filters/sampleRateFilter.test.js +75 -0
- package/dist/unit/types/current/tsconfig.tsbuildinfo +1 -1
- package/dist/unit/types/current/vinyl/VinylPlayer.test.js +33 -2
- package/dist/vinylTestUtil/types/current/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
|
@@ -2,7 +2,7 @@ import { EventHostImpl, type Maybe } from '@amazon/vinyl-util';
|
|
|
2
2
|
import { type DrmOptions } from './DrmOptions';
|
|
3
3
|
import type { DrmController, DrmControllerEventMap, DrmKeySystemSupport, DrmPlaybackOptions } from './DrmController';
|
|
4
4
|
import type { CommonEme, CommonMediaKeyMessageEvent, CommonMediaKeys, CommonMediaKeySession } from './commonEme/CommonEme';
|
|
5
|
-
import type { MediaFormatMetadata } from '../streaming/MediaQualityMetadata';
|
|
5
|
+
import type { ContentType, MediaFormatMetadata } from '../streaming/MediaQualityMetadata';
|
|
6
6
|
import type { TrackUri } from '../track/Track';
|
|
7
7
|
/**
|
|
8
8
|
* The number of seconds a license request will be allowed before timing out.
|
|
@@ -30,6 +30,13 @@ export interface DrmControllerMessageProps {
|
|
|
30
30
|
* to their own track.
|
|
31
31
|
*/
|
|
32
32
|
readonly trackUri: TrackUri | null;
|
|
33
|
+
/**
|
|
34
|
+
* The MIME and content type of the session's content, captured at creation
|
|
35
|
+
* so the license span can distinguish the certificate exchange from the
|
|
36
|
+
* per-content-type license exchanges.
|
|
37
|
+
*/
|
|
38
|
+
readonly mimeType: string;
|
|
39
|
+
readonly contentType: ContentType | null;
|
|
33
40
|
}
|
|
34
41
|
export declare class DrmControllerImpl extends EventHostImpl<DrmControllerEventMap> implements DrmController {
|
|
35
42
|
private readonly deps;
|
|
@@ -44,6 +51,8 @@ export declare class DrmControllerImpl extends EventHostImpl<DrmControllerEventM
|
|
|
44
51
|
private bufferingTrackUri;
|
|
45
52
|
private sessionAbort;
|
|
46
53
|
private pendingMessageProps;
|
|
54
|
+
private keySetupSpanArmed;
|
|
55
|
+
private keySetupSpanStart;
|
|
47
56
|
private readonly disposer;
|
|
48
57
|
constructor(deps: DrmControllerImplDeps, options?: Maybe<Partial<DrmOptions>>);
|
|
49
58
|
configure(options: Maybe<Partial<DrmOptions>>): void;
|
|
@@ -64,6 +73,13 @@ export declare class DrmControllerImpl extends EventHostImpl<DrmControllerEventM
|
|
|
64
73
|
* The new session will be added to the current sessions list.
|
|
65
74
|
*/
|
|
66
75
|
private maybeCreateSession;
|
|
76
|
+
/**
|
|
77
|
+
* Captures the key-setup span start at the top of the session-creation path
|
|
78
|
+
* (before media keys are attached), latching so only the first session of
|
|
79
|
+
* the current track load is measured.
|
|
80
|
+
*/
|
|
81
|
+
private markKeySetupStart;
|
|
82
|
+
private dispatchLoadSpan;
|
|
67
83
|
initializeForPlayback(drmInfo: MediaFormatMetadata | null, options?: DrmPlaybackOptions): void;
|
|
68
84
|
/** True when the manifest carried pssh (sessions come from it, not events). */
|
|
69
85
|
private manifestProvidesInitData;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DrmControllerImpl.d.ts","sourceRoot":"","sources":["../../../../src/drm/DrmControllerImpl.ts"],"names":[],"mappings":"AAKA,OAAO,EAUH,aAAa,EAMb,KAAK,KAAK,
|
|
1
|
+
{"version":3,"file":"DrmControllerImpl.d.ts","sourceRoot":"","sources":["../../../../src/drm/DrmControllerImpl.ts"],"names":[],"mappings":"AAKA,OAAO,EAUH,aAAa,EAMb,KAAK,KAAK,EAUb,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAEH,KAAK,UAAU,EAGlB,MAAM,cAAc,CAAA;AACrB,OAAO,KAAK,EACR,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EACrB,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EACR,SAAS,EAET,0BAA0B,EAC1B,eAAe,EACf,qBAAqB,EAExB,MAAM,uBAAuB,CAAA;AAK9B,OAAO,KAAK,EACR,WAAW,EACX,mBAAmB,EACtB,MAAM,mCAAmC,CAAA;AAS1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAG9C;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,KAAK,CAAA;AAGjC;;GAEG;AACH,MAAM,WAAW,qBAAqB;IAClC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAA;CACvC;AAED,MAAM,WAAW,yBAAyB;IACtC,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAA;IACvC,QAAQ,CAAC,KAAK,EAAE,0BAA0B,CAAA;IAC1C;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IAClC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAAA;CAC3C;AAyBD,qBAAa,iBACT,SAAQ,aAAa,CAAC,qBAAqB,CAC3C,YAAW,aAAa;IA4BpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IA1BzB,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,MAAM,CAEjC;IAED,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAY;IACxC,OAAO,CAAC,OAAO,CAAY;IAE3B,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,gBAAgB,CAAwC;IAChE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;IAEvD,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,iBAAiB,CAAwB;IACjD,OAAO,CAAC,YAAY,CAA6B;IAEjD,OAAO,CAAC,mBAAmB,CAAyC;IAIpE,OAAO,CAAC,iBAAiB,CAAO;IAChC,OAAO,CAAC,iBAAiB,CAAyB;IAElD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmB;gBAGvB,IAAI,EAAE,qBAAqB,EAC5C,OAAO,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAgBxC,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI;IAWpD,OAAO,KAAK,eAAe,GAE1B;IAED,IAAI,KAAK,IAAI,KAAK,GAAG,IAAI,CAExB;IAED,cAAc,IAAI,OAAO;IAInB,WAAW,CACb,OAAO,EAAE,mBAAmB,GAC7B,OAAO,CAAC,mBAAmB,CAAC;IAS/B,OAAO,CAAC,sBAAsB,CAgC7B;IAED,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CA2CpC;IAED;;;OAGG;YACW,eAAe;IAsB7B;;;;OAIG;YACW,kBAAkB;IAiEhC;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,gBAAgB;IAsBxB,qBAAqB,CACjB,OAAO,EAAE,mBAAmB,GAAG,IAAI,EACnC,OAAO,CAAC,EAAE,kBAAkB,GAC7B,IAAI;IAWP,+EAA+E;IAC/E,OAAO,CAAC,wBAAwB;IAOhC,mBAAmB,CACf,OAAO,EAAE,mBAAmB,GAAG,IAAI,EACnC,OAAO,CAAC,EAAE,kBAAkB,GAC7B,IAAI;IAYP;;;OAGG;YACW,yBAAyB;IAkCvC;;OAEG;YACW,YAAY;IAmC1B;;OAEG;IACH,OAAO,CAAC,gCAAgC;IAyDxC,OAAO,CAAC,wBAAwB;IAiBhC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAmCxB;;OAEG;YACW,cAAc;IAoE5B;;;OAGG;IACH,aAAa;IAKb,OAAO,CAAC,YAAY;IAcpB;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAM3B;IAED;;OAEG;IACH,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED;;OAEG;IACH,OAAO,CAAC,cAAc;IAUtB,SAAS,CAAC,eAAe;IAIzB,KAAK;IA2BL,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,OAAO,IAAI,IAAI;IAOf,OAAO,CAAC,oBAAoB;IAU5B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CASnC;CACJ"}
|
|
@@ -35,6 +35,10 @@ export class DrmControllerImpl extends EventHostImpl {
|
|
|
35
35
|
bufferingTrackUri = null;
|
|
36
36
|
sessionAbort = null;
|
|
37
37
|
pendingMessageProps = null;
|
|
38
|
+
// Armed per track load; latches on the first session so only the
|
|
39
|
+
// critical-path session's EME/CDM setup is measured.
|
|
40
|
+
keySetupSpanArmed = true;
|
|
41
|
+
keySetupSpanStart = null;
|
|
38
42
|
disposer = createDisposer();
|
|
39
43
|
constructor(deps, options) {
|
|
40
44
|
super();
|
|
@@ -160,6 +164,7 @@ export class DrmControllerImpl extends EventHostImpl {
|
|
|
160
164
|
if (!hasMimeType(drmInfo)) {
|
|
161
165
|
throw new DrmError('Encrypted content must have a mimeType.');
|
|
162
166
|
}
|
|
167
|
+
this.markKeySetupStart();
|
|
163
168
|
const mediaKeys = await this.attachMediaKeys(drmInfo);
|
|
164
169
|
this.abortIfDisposed();
|
|
165
170
|
// Resolve server certificate from configuration
|
|
@@ -204,6 +209,33 @@ export class DrmControllerImpl extends EventHostImpl {
|
|
|
204
209
|
});
|
|
205
210
|
return newSession;
|
|
206
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Captures the key-setup span start at the top of the session-creation path
|
|
214
|
+
* (before media keys are attached), latching so only the first session of
|
|
215
|
+
* the current track load is measured.
|
|
216
|
+
*/
|
|
217
|
+
markKeySetupStart() {
|
|
218
|
+
if (!this.keySetupSpanArmed)
|
|
219
|
+
return;
|
|
220
|
+
this.keySetupSpanArmed = false;
|
|
221
|
+
this.keySetupSpanStart = Date.now();
|
|
222
|
+
}
|
|
223
|
+
dispatchLoadSpan(kind, startTime, endTime, messageProps) {
|
|
224
|
+
this.dispatch('loadSpanMeasured', {
|
|
225
|
+
kind,
|
|
226
|
+
startTime,
|
|
227
|
+
endTime,
|
|
228
|
+
mimeType: messageProps.mimeType,
|
|
229
|
+
// Attributed at the source to the session's track; omitted (not set
|
|
230
|
+
// to undefined) when unknown, per exactOptionalPropertyTypes.
|
|
231
|
+
...(messageProps.trackUri != null && {
|
|
232
|
+
trackUri: messageProps.trackUri,
|
|
233
|
+
}),
|
|
234
|
+
...(messageProps.contentType != null && {
|
|
235
|
+
contentType: messageProps.contentType,
|
|
236
|
+
}),
|
|
237
|
+
});
|
|
238
|
+
}
|
|
207
239
|
initializeForPlayback(drmInfo, options) {
|
|
208
240
|
logDebug(this, 'initializeForPlayback', drmInfo);
|
|
209
241
|
if (drmInfo?.contentProtections.length) {
|
|
@@ -222,6 +254,9 @@ export class DrmControllerImpl extends EventHostImpl {
|
|
|
222
254
|
this.drmInfo = drmInfo;
|
|
223
255
|
this.bufferingTrackUri = options?.trackUri ?? null;
|
|
224
256
|
this.sessionAbort = options?.abort ?? null;
|
|
257
|
+
// Re-arm so the new track load's first session is measured.
|
|
258
|
+
this.keySetupSpanArmed = true;
|
|
259
|
+
this.keySetupSpanStart = null;
|
|
225
260
|
}
|
|
226
261
|
/**
|
|
227
262
|
* If the drm metadata contains initialization data for the current key system, create a new session.
|
|
@@ -232,6 +267,7 @@ export class DrmControllerImpl extends EventHostImpl {
|
|
|
232
267
|
this.handleError(new DrmError('DRM not supported.'));
|
|
233
268
|
return;
|
|
234
269
|
}
|
|
270
|
+
this.markKeySetupStart();
|
|
235
271
|
const mediaKeys = await this.attachMediaKeys(drmInfo);
|
|
236
272
|
const drmProtection = drmInfo.contentProtections.find((cP) => {
|
|
237
273
|
return cP.keySystem === mediaKeys.keySystem;
|
|
@@ -355,6 +391,8 @@ export class DrmControllerImpl extends EventHostImpl {
|
|
|
355
391
|
// Captured per session, so a concurrent preloaded track's
|
|
356
392
|
// license exchange keeps its own attribution.
|
|
357
393
|
trackUri: trackUri,
|
|
394
|
+
mimeType: drmInfo.mimeType,
|
|
395
|
+
contentType: drmInfo.contentType,
|
|
358
396
|
}), LICENSE_TIMEOUT, { message: LICENSE_TIMEOUT_MESSAGE }).catch(this.handleError);
|
|
359
397
|
});
|
|
360
398
|
session.on('error', (event) => {
|
|
@@ -372,6 +410,12 @@ export class DrmControllerImpl extends EventHostImpl {
|
|
|
372
410
|
this.pendingMessageProps = messageProps;
|
|
373
411
|
const keySystem = mediaKeys.keySystem;
|
|
374
412
|
logDebug(this, 'message', keySystem, event.message.byteLength);
|
|
413
|
+
// The CDM's first message ends the setup span; it is contiguous with the
|
|
414
|
+
// license round-trip measured below.
|
|
415
|
+
if (this.keySetupSpanStart != null) {
|
|
416
|
+
this.dispatchLoadSpan('keySetup', this.keySetupSpanStart, Date.now(), messageProps);
|
|
417
|
+
this.keySetupSpanStart = null;
|
|
418
|
+
}
|
|
375
419
|
const keySystemOptions = this.options.keySystems[keySystem] ?? this.options.keySystems['*'];
|
|
376
420
|
const licenseServerOptionsProvider = keySystemOptions?.licenseServer;
|
|
377
421
|
// Get the license server configuration for the current key system.
|
|
@@ -393,16 +437,7 @@ export class DrmControllerImpl extends EventHostImpl {
|
|
|
393
437
|
const key = await this.licenseProvider(keySystem, licenseServerOptions, challenge);
|
|
394
438
|
if (this.disposed)
|
|
395
439
|
return;
|
|
396
|
-
this.
|
|
397
|
-
kind: 'license',
|
|
398
|
-
startTime: licenseSpanStart,
|
|
399
|
-
endTime: Date.now(),
|
|
400
|
-
// Attributed at the source to the session's track; omitted (not set
|
|
401
|
-
// to undefined) when unknown, per exactOptionalPropertyTypes.
|
|
402
|
-
...(messageProps.trackUri != null && {
|
|
403
|
-
trackUri: messageProps.trackUri,
|
|
404
|
-
}),
|
|
405
|
-
});
|
|
440
|
+
this.dispatchLoadSpan('license', licenseSpanStart, Date.now(), messageProps);
|
|
406
441
|
this.pendingMessageProps = null;
|
|
407
442
|
if (session.disposed)
|
|
408
443
|
return;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import type { Timestamp } from '@amazon/vinyl-util';
|
|
2
2
|
import type { TrackUri } from '../track/Track';
|
|
3
|
+
import type { ContentType } from './MediaQualityMetadata';
|
|
3
4
|
/**
|
|
4
5
|
* The stage of the track-load journey a {@link LoadSpanMeasurement} describes.
|
|
5
6
|
*
|
|
6
7
|
* - `manifest`: fetching and parsing the DASH/HLS manifest.
|
|
8
|
+
* - `keySetup`: the EME/CDM setup, from session creation to the CDM's first
|
|
9
|
+
* license message. Precedes and is contiguous with `license`.
|
|
7
10
|
* - `license`: the DRM license request/response exchange.
|
|
8
11
|
* - `initSegment`: fetching the initialization segment.
|
|
9
12
|
* - `firstSegment`: fetching the first media segment.
|
|
10
13
|
*/
|
|
11
|
-
export type LoadSpanKind = 'manifest' | 'license' | 'initSegment' | 'firstSegment';
|
|
14
|
+
export type LoadSpanKind = 'manifest' | 'keySetup' | 'license' | 'initSegment' | 'firstSegment';
|
|
12
15
|
/**
|
|
13
16
|
* A timed span for one stage of a track load.
|
|
14
17
|
*
|
|
@@ -35,6 +38,17 @@ export interface LoadSpanMeasurement {
|
|
|
35
38
|
* buffering DRM info is set).
|
|
36
39
|
*/
|
|
37
40
|
readonly trackUri?: TrackUri;
|
|
41
|
+
/**
|
|
42
|
+
* The MIME type of the content this span was measured for, when known. Set
|
|
43
|
+
* for DRM `license` spans so a certificate exchange and the per-content-type
|
|
44
|
+
* license exchanges are distinguishable.
|
|
45
|
+
*/
|
|
46
|
+
readonly mimeType?: string;
|
|
47
|
+
/**
|
|
48
|
+
* The content type this span was measured for, when known. Set alongside
|
|
49
|
+
* {@link mimeType} for DRM `license` spans.
|
|
50
|
+
*/
|
|
51
|
+
readonly contentType?: ContentType;
|
|
38
52
|
}
|
|
39
53
|
/**
|
|
40
54
|
* A {@link LoadSpanMeasurement} attributed to the track it was measured for.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoadMetric.d.ts","sourceRoot":"","sources":["../../../../src/streaming/LoadMetric.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"LoadMetric.d.ts","sourceRoot":"","sources":["../../../../src/streaming/LoadMetric.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEzD;;;;;;;;;GASG;AACH,MAAM,MAAM,YAAY,GACpB,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,aAAa,GAAG,cAAc,CAAA;AAExE;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAChC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;IAE3B;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAE7B;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAE3B;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAA;IAE5B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAE1B;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAA;CACrC;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAc,SAAQ,mBAAmB;IACtD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;CACnC"}
|
|
@@ -3,12 +3,14 @@ import type { MediaQualityMetadata } from './MediaQualityMetadata';
|
|
|
3
3
|
import type { FilterPredicate, FilterPredicateAsync, Maybe } from '@amazon/vinyl-util';
|
|
4
4
|
/**
|
|
5
5
|
* Filters qualities in a MediaTimeline using a synchronous predicate.
|
|
6
|
-
* If filtering
|
|
6
|
+
* If filtering drops an audio or video stream to zero in any period, throws via
|
|
7
|
+
* `throwError`.
|
|
7
8
|
*/
|
|
8
9
|
export declare function filterTimelineQualities(filter: Maybe<FilterPredicate<MediaQualityMetadata>>, throwError: () => never, timeline: MediaTimeline): MediaTimeline;
|
|
9
10
|
/**
|
|
10
11
|
* Filters qualities in a MediaTimeline using an asynchronous predicate.
|
|
11
|
-
* If filtering
|
|
12
|
+
* If filtering drops an audio or video stream to zero in any period, throws via
|
|
13
|
+
* `throwError`.
|
|
12
14
|
*/
|
|
13
15
|
export declare function filterTimelineQualitiesAsync(filter: FilterPredicateAsync<MediaQualityMetadata>, throwError: () => never, timeline: MediaTimeline): Promise<MediaTimeline>;
|
|
14
16
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mediaTimelineFilter.d.ts","sourceRoot":"","sources":["../../../../src/streaming/mediaTimelineFilter.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAGR,aAAa,EAChB,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"mediaTimelineFilter.d.ts","sourceRoot":"","sources":["../../../../src/streaming/mediaTimelineFilter.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAGR,aAAa,EAChB,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAElE,OAAO,KAAK,EACR,eAAe,EACf,oBAAoB,EACpB,KAAK,EACR,MAAM,oBAAoB,CAAA;AA0B3B;;;;GAIG;AACH,wBAAgB,uBAAuB,CACnC,MAAM,EAAE,KAAK,CAAC,eAAe,CAAC,oBAAoB,CAAC,CAAC,EACpD,UAAU,EAAE,MAAM,KAAK,EACvB,QAAQ,EAAE,aAAa,GACxB,aAAa,CAkBf;AAED;;;;GAIG;AACH,wBAAsB,4BAA4B,CAC9C,MAAM,EAAE,oBAAoB,CAAC,oBAAoB,CAAC,EAClD,UAAU,EAAE,MAAM,KAAK,EACvB,QAAQ,EAAE,aAAa,GACxB,OAAO,CAAC,aAAa,CAAC,CAsBxB;AAED;;GAEG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAA"}
|
|
@@ -2,10 +2,28 @@
|
|
|
2
2
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
+
import { RESTRICTABLE_CONTENT_TYPES } from './MediaQualityMetadata';
|
|
5
6
|
import { map, memoize } from '@amazon/vinyl-util';
|
|
7
|
+
/**
|
|
8
|
+
* Throws via `throwError` when filtering drops every rendition of an audio or
|
|
9
|
+
* video stream the period originally carried. Each surviving media stream needs
|
|
10
|
+
* a source buffer to append to; a stream filtered to zero can never create one,
|
|
11
|
+
* stalling playback on an unfulfilled `readyToAppend`, so a whole-stream drop is
|
|
12
|
+
* treated as unsupported media rather than a silent stall. Text is excluded —
|
|
13
|
+
* captions are an optional sidecar pipeline, not an MSE source buffer.
|
|
14
|
+
*/
|
|
15
|
+
function assertMediaStreamsRetained(original, filtered, throwError) {
|
|
16
|
+
for (const contentType of RESTRICTABLE_CONTENT_TYPES) {
|
|
17
|
+
if (original.some((q) => q.metadata.contentType === contentType) &&
|
|
18
|
+
!filtered.some((q) => q.metadata.contentType === contentType)) {
|
|
19
|
+
throwError();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
6
23
|
/**
|
|
7
24
|
* Filters qualities in a MediaTimeline using a synchronous predicate.
|
|
8
|
-
* If filtering
|
|
25
|
+
* If filtering drops an audio or video stream to zero in any period, throws via
|
|
26
|
+
* `throwError`.
|
|
9
27
|
*/
|
|
10
28
|
export function filterTimelineQualities(filter, throwError, timeline) {
|
|
11
29
|
if (!filter)
|
|
@@ -13,16 +31,15 @@ export function filterTimelineQualities(filter, throwError, timeline) {
|
|
|
13
31
|
const mapMetadataArray = memoize((qualities) => map(qualities, (q) => q.metadata), (qualities) => qualities, 1);
|
|
14
32
|
const periods = timeline.periods.map((period) => {
|
|
15
33
|
const filtered = period.qualities.filter((q, index) => filter(q.metadata, index, mapMetadataArray(period.qualities)));
|
|
34
|
+
assertMediaStreamsRetained(period.qualities, filtered, throwError);
|
|
16
35
|
return { ...period, qualities: filtered };
|
|
17
36
|
});
|
|
18
|
-
if (periods.some((p) => p.qualities.length === 0)) {
|
|
19
|
-
throwError();
|
|
20
|
-
}
|
|
21
37
|
return { ...timeline, periods };
|
|
22
38
|
}
|
|
23
39
|
/**
|
|
24
40
|
* Filters qualities in a MediaTimeline using an asynchronous predicate.
|
|
25
|
-
* If filtering
|
|
41
|
+
* If filtering drops an audio or video stream to zero in any period, throws via
|
|
42
|
+
* `throwError`.
|
|
26
43
|
*/
|
|
27
44
|
export async function filterTimelineQualitiesAsync(filter, throwError, timeline) {
|
|
28
45
|
const mapMetadataArray = memoize((qualities) => map(qualities, (q) => q.metadata), (qualities) => qualities, 1);
|
|
@@ -35,11 +52,9 @@ export async function filterTimelineQualitiesAsync(filter, throwError, timeline)
|
|
|
35
52
|
filtered.push(period.qualities[i]);
|
|
36
53
|
}
|
|
37
54
|
}
|
|
55
|
+
assertMediaStreamsRetained(period.qualities, filtered, throwError);
|
|
38
56
|
periods.push({ ...period, qualities: filtered });
|
|
39
57
|
}
|
|
40
|
-
if (periods.some((p) => p.qualities.length === 0)) {
|
|
41
|
-
throwError();
|
|
42
|
-
}
|
|
43
58
|
return { ...timeline, periods };
|
|
44
59
|
}
|
|
45
60
|
/**
|
|
@@ -18,10 +18,14 @@ export interface AudioSampleRateRangeOptions {
|
|
|
18
18
|
* The upper bound is `maxSampleRate` when set, otherwise the platform's
|
|
19
19
|
* `AudioContext`-reported output rate (Firefox is hard-capped at 48kHz, which it
|
|
20
20
|
* cannot decode beyond via MSE). The optional lower bound is `minSampleRate`.
|
|
21
|
-
* Both bounds are soft
|
|
22
|
-
*
|
|
23
|
-
* playback is never stranded
|
|
24
|
-
*
|
|
21
|
+
* Both bounds are soft, and soft *together*: when no audio rendition sits in the
|
|
22
|
+
* acceptable `[minSampleRate, maxSampleRate]` band, a single fallback is kept so
|
|
23
|
+
* playback is never stranded — the highest rate the ceiling can decode, or, when
|
|
24
|
+
* every rate is above the ceiling, the lowest. This holds even when renditions
|
|
25
|
+
* straddle an empty band (some below the floor, some above the ceiling). Only
|
|
26
|
+
* audio renditions count toward the fallback — a co-present video quality (no
|
|
27
|
+
* audio rate) never influences it. Firefox is the exception: its 48kHz cap is
|
|
28
|
+
* hard, with no fallback.
|
|
25
29
|
*/
|
|
26
30
|
export declare function withinAudioSampleRateRange(options: AudioSampleRateRangeOptions, metadata: MediaQualityMetadata, _index: number, array: ArrayLike<MediaQualityMetadata>): boolean;
|
|
27
31
|
//# sourceMappingURL=sampleRateFilter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sampleRateFilter.d.ts","sourceRoot":"","sources":["../../../../../src/track/filters/sampleRateFilter.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAA;
|
|
1
|
+
{"version":3,"file":"sampleRateFilter.d.ts","sourceRoot":"","sources":["../../../../../src/track/filters/sampleRateFilter.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAA;AAUhF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAE7D,wBAAgB,6BAA6B,IAAI,KAAK,CAErD;AAED,MAAM,WAAW,2BAA2B;IACxC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAA;IACnC;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtC,+CAA+C;IAC/C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACzC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,0BAA0B,CACtC,OAAO,EAAE,2BAA2B,EACpC,QAAQ,EAAE,oBAAoB,EAC9B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,SAAS,CAAC,oBAAoB,CAAC,GACvC,OAAO,CAmDT"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
|
-
import { hasBrowser, Browser, last, MediaUnsupportedError,
|
|
5
|
+
import { hasBrowser, Browser, last, MediaUnsupportedError, map, max, min, } from '@amazon/vinyl-util';
|
|
6
6
|
export function throwSamplingRatesUnsupported() {
|
|
7
7
|
throw new MediaUnsupportedError('No supported sample rate', 'sampling-rate');
|
|
8
8
|
}
|
|
@@ -13,34 +13,46 @@ export function throwSamplingRatesUnsupported() {
|
|
|
13
13
|
* The upper bound is `maxSampleRate` when set, otherwise the platform's
|
|
14
14
|
* `AudioContext`-reported output rate (Firefox is hard-capped at 48kHz, which it
|
|
15
15
|
* cannot decode beyond via MSE). The optional lower bound is `minSampleRate`.
|
|
16
|
-
* Both bounds are soft
|
|
17
|
-
*
|
|
18
|
-
* playback is never stranded
|
|
19
|
-
*
|
|
16
|
+
* Both bounds are soft, and soft *together*: when no audio rendition sits in the
|
|
17
|
+
* acceptable `[minSampleRate, maxSampleRate]` band, a single fallback is kept so
|
|
18
|
+
* playback is never stranded — the highest rate the ceiling can decode, or, when
|
|
19
|
+
* every rate is above the ceiling, the lowest. This holds even when renditions
|
|
20
|
+
* straddle an empty band (some below the floor, some above the ceiling). Only
|
|
21
|
+
* audio renditions count toward the fallback — a co-present video quality (no
|
|
22
|
+
* audio rate) never influences it. Firefox is the exception: its 48kHz cap is
|
|
23
|
+
* hard, with no fallback.
|
|
20
24
|
*/
|
|
21
25
|
export function withinAudioSampleRateRange(options, metadata, _index, array) {
|
|
22
|
-
//
|
|
23
|
-
// content type (including muxed video that happens to carry an audio rate)
|
|
24
|
-
// pass through untouched.
|
|
26
|
+
// Muxed video carrying an audio rate, and every non-audio type, pass through.
|
|
25
27
|
if (metadata.contentType !== 'audio')
|
|
26
28
|
return true;
|
|
27
29
|
const samplingRate = last(metadata.audioSamplingRate);
|
|
28
30
|
if (!samplingRate)
|
|
29
31
|
return true; // sampling rate not set
|
|
32
|
+
const { minSampleRate } = options;
|
|
33
|
+
// An explicit maxSampleRate takes precedence over the AudioContext rate.
|
|
34
|
+
const maxSampleRate = options.maxSampleRate ?? options.capabilities.sampleRate;
|
|
30
35
|
const audioRates = () => map(array, (item) => item.contentType === 'audio'
|
|
31
36
|
? last(item.audioSamplingRate)
|
|
32
37
|
: undefined).filter((rate) => rate != null);
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
// The single rate to keep when this rendition is out of band — or undefined
|
|
39
|
+
// when some rendition IS in band, so out-of-band renditions are dropped.
|
|
40
|
+
// Evaluating both bounds together is what stops a straddle from stranding.
|
|
41
|
+
const outOfBandFallback = () => {
|
|
37
42
|
const rates = audioRates();
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
const inBand = (rate) => (minSampleRate == null || rate >= minSampleRate) &&
|
|
44
|
+
(!maxSampleRate || rate <= maxSampleRate);
|
|
45
|
+
if (rates.some(inBand))
|
|
46
|
+
return undefined;
|
|
47
|
+
const decodable = maxSampleRate
|
|
48
|
+
? rates.filter((rate) => rate <= maxSampleRate)
|
|
49
|
+
: rates;
|
|
50
|
+
return decodable.length ? max(decodable) : min(rates);
|
|
51
|
+
};
|
|
52
|
+
// Lower bound (soft floor), independent of the platform max.
|
|
53
|
+
if (minSampleRate != null && samplingRate < minSampleRate) {
|
|
54
|
+
return samplingRate === outOfBandFallback();
|
|
40
55
|
}
|
|
41
|
-
// Upper bound. An explicit maxSampleRate takes precedence over the
|
|
42
|
-
// AudioContext-reported output rate.
|
|
43
|
-
const maxSampleRate = options.maxSampleRate ?? options.capabilities.sampleRate;
|
|
44
56
|
// No platform max to gauge support: keep. This also lets >48kHz through on
|
|
45
57
|
// Firefox (its cap below is skipped) — accepted.
|
|
46
58
|
if (!maxSampleRate)
|
|
@@ -51,8 +63,6 @@ export function withinAudioSampleRateRange(options, metadata, _index, array) {
|
|
|
51
63
|
}
|
|
52
64
|
if (samplingRate <= maxSampleRate)
|
|
53
65
|
return true;
|
|
54
|
-
// Above the
|
|
55
|
-
|
|
56
|
-
return (every(rates, (rate) => rate > maxSampleRate) &&
|
|
57
|
-
samplingRate === min(rates));
|
|
66
|
+
// Above the ceiling (soft): keep only the fallback when no rate is in band.
|
|
67
|
+
return samplingRate === outOfBandFallback();
|
|
58
68
|
}
|
|
@@ -71,15 +71,6 @@ export declare class MseTrack extends TrackBase {
|
|
|
71
71
|
* Updates the cached qualities list from the transformed timeline for the current period.
|
|
72
72
|
*/
|
|
73
73
|
private updateQualities;
|
|
74
|
-
/**
|
|
75
|
-
* Fails fast when a media content type the manifest declared (audio/video)
|
|
76
|
-
* has no playable qualities left after timeline filtering. Its stream can
|
|
77
|
-
* never create a source buffer, so without this the track waits forever for
|
|
78
|
-
* a source buffer that never arrives, surfacing only as an opaque
|
|
79
|
-
* `readyToAppend` timeout. Runs once both the required content types and the
|
|
80
|
-
* filtered timeline qualities are known (either order).
|
|
81
|
-
*/
|
|
82
|
-
private validateRequiredContentTypesPlayable;
|
|
83
74
|
getAds(): Promise<TrackAds>;
|
|
84
75
|
/**
|
|
85
76
|
* Updates the cached unfiltered qualities list from the raw timeline for the current period.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MseTrack.d.ts","sourceRoot":"","sources":["../../../../../src/track/mse/MseTrack.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,EAOH,KAAK,KAAK,
|
|
1
|
+
{"version":3,"file":"MseTrack.d.ts","sourceRoot":"","sources":["../../../../../src/track/mse/MseTrack.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { TrackBase } from '../TrackBase';
|
|
6
|
-
import { Abort, equalDeep, first, IntersectionRanges, logDebug,
|
|
6
|
+
import { Abort, equalDeep, first, IntersectionRanges, logDebug, redispatchEvents, } from '@amazon/vinyl-util';
|
|
7
7
|
import { createContainer } from '@amazon/vinyl-di';
|
|
8
8
|
import { getMediaPeriodAtTime, } from '../../streaming/MediaTimeline';
|
|
9
9
|
/**
|
|
@@ -40,10 +40,7 @@ export class MseTrack extends TrackBase {
|
|
|
40
40
|
this.deps = deps;
|
|
41
41
|
add(deps.contentTypesValue.onData((contentTypesPromise) => {
|
|
42
42
|
contentTypesPromise
|
|
43
|
-
.then((value) =>
|
|
44
|
-
this.setContentTypes(value);
|
|
45
|
-
this.validateRequiredContentTypesPlayable();
|
|
46
|
-
})
|
|
43
|
+
.then((value) => this.setContentTypes(value))
|
|
47
44
|
.catch(this.errorHandler);
|
|
48
45
|
}));
|
|
49
46
|
// DRM
|
|
@@ -139,32 +136,8 @@ export class MseTrack extends TrackBase {
|
|
|
139
136
|
});
|
|
140
137
|
}
|
|
141
138
|
}
|
|
142
|
-
this.validateRequiredContentTypesPlayable();
|
|
143
139
|
});
|
|
144
140
|
}
|
|
145
|
-
/**
|
|
146
|
-
* Fails fast when a media content type the manifest declared (audio/video)
|
|
147
|
-
* has no playable qualities left after timeline filtering. Its stream can
|
|
148
|
-
* never create a source buffer, so without this the track waits forever for
|
|
149
|
-
* a source buffer that never arrives, surfacing only as an opaque
|
|
150
|
-
* `readyToAppend` timeout. Runs once both the required content types and the
|
|
151
|
-
* filtered timeline qualities are known (either order).
|
|
152
|
-
*/
|
|
153
|
-
validateRequiredContentTypesPlayable() {
|
|
154
|
-
const qualities = this._qualities;
|
|
155
|
-
if (!qualities)
|
|
156
|
-
return;
|
|
157
|
-
const present = new Set(qualities.map((q) => q.contentType));
|
|
158
|
-
// contentTypesValue only ever yields audio/video (text is a sidecar
|
|
159
|
-
// pipeline, never an MSE source buffer), so every required type must
|
|
160
|
-
// have a playable quality left in the filtered timeline.
|
|
161
|
-
for (const contentType of this._contentTypes) {
|
|
162
|
-
if (!present.has(contentType)) {
|
|
163
|
-
this.errorHandler(new MediaUnsupportedError(`No playable ${contentType} rendition`, `no-playable-${contentType}`));
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
141
|
async getAds() {
|
|
169
142
|
const timeline = await this.deps.mediaTimeline.value;
|
|
170
143
|
return {
|