@amazon/vinyl 4.0.0 → 4.0.1-next.20261016220320

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 (76) hide show
  1. package/dist/index.cjs +40 -3
  2. package/dist/index.cjs.map +2 -2
  3. package/dist/index.js +41 -3
  4. package/dist/index.js.map +2 -2
  5. package/dist/test/benchmark.es5.js +5 -4
  6. package/dist/test/benchmark.js +11 -2
  7. package/dist/test/benchmark.js.map +3 -3
  8. package/dist/test/errata/mse-changetype-sequence.html +65 -0
  9. package/dist/test/errata/mse-changetype-sequence.js +179 -0
  10. package/dist/test/index.html +2 -2
  11. package/dist/test/integ.es5.js +287 -276
  12. package/dist/test/integ.js +629 -245
  13. package/dist/test/integ.js.map +4 -4
  14. package/dist/test/styles.css +23 -13
  15. package/dist/types/current/playback/PlaybackControllerImpl.d.ts +12 -0
  16. package/dist/types/current/playback/PlaybackControllerImpl.d.ts.map +1 -1
  17. package/dist/types/current/playback/PlaybackControllerImpl.js +42 -1
  18. package/dist/types/current/streaming/buffering/BufferingController.d.ts.map +1 -1
  19. package/dist/types/current/streaming/buffering/BufferingController.js +9 -2
  20. package/dist/types/current/streaming/buffering/MediaSourceController.d.ts.map +1 -1
  21. package/dist/types/current/streaming/buffering/MediaSourceController.js +4 -2
  22. package/dist/types/current/tsconfig.tsbuildinfo +1 -1
  23. package/dist/types/ts3.7/playback/PlaybackControllerImpl.d.ts +12 -0
  24. package/dist/types/ts4.1/playback/PlaybackControllerImpl.d.ts +12 -0
  25. package/dist/types/ts4.7/playback/PlaybackControllerImpl.d.ts +12 -0
  26. package/dist/unit/types/current/playback/PlaybackControllerImpl.test.js +86 -0
  27. package/dist/unit/types/current/setup.js +6 -5
  28. package/dist/unit/types/current/streaming/SegmentControllerImpl.test.js +44 -1
  29. package/dist/unit/types/current/streaming/buffering/BufferingController.test.js +14 -0
  30. package/dist/unit/types/current/streaming/buffering/MediaSourceController.test.js +13 -0
  31. package/dist/unit/types/current/track/dash/createDashFactories.test.js +15 -5
  32. package/dist/unit/types/current/track/hls/createHlsFactories.test.js +36 -12
  33. package/dist/unit/types/current/tsconfig.tsbuildinfo +1 -1
  34. package/dist/unit/types/current/vinyl/VinylPlayerAdBreaks.test.js +8 -5
  35. package/dist/vinylTestUtil/index.js +92 -60
  36. package/dist/vinylTestUtil/index.js.map +4 -4
  37. package/dist/vinylTestUtil/types/current/media/FrequencyAnalyzer.d.ts +8 -5
  38. package/dist/vinylTestUtil/types/current/media/FrequencyAnalyzer.d.ts.map +1 -1
  39. package/dist/vinylTestUtil/types/current/media/FrequencyAnalyzer.js +23 -29
  40. package/dist/vinylTestUtil/types/current/media/unlockMediaElement.d.ts +10 -1
  41. package/dist/vinylTestUtil/types/current/media/unlockMediaElement.d.ts.map +1 -1
  42. package/dist/vinylTestUtil/types/current/media/unlockMediaElement.js +34 -6
  43. package/dist/vinylTestUtil/types/current/player/createVinylSuite.d.ts.map +1 -1
  44. package/dist/vinylTestUtil/types/current/player/createVinylSuite.js +6 -1
  45. package/dist/vinylTestUtil/types/current/player/mediaRef.d.ts +7 -0
  46. package/dist/vinylTestUtil/types/current/player/mediaRef.d.ts.map +1 -1
  47. package/dist/vinylTestUtil/types/current/player/mediaRef.js +8 -1
  48. package/dist/vinylTestUtil/types/current/tsconfig.tsbuildinfo +1 -1
  49. package/dist/vinylTestUtil/types/current/ui/requireUserInteraction.d.ts +6 -2
  50. package/dist/vinylTestUtil/types/current/ui/requireUserInteraction.d.ts.map +1 -1
  51. package/dist/vinylTestUtil/types/current/ui/requireUserInteraction.js +31 -15
  52. package/dist/vinylTestUtil/types/current/util/playback/expectTrackPlays.d.ts +9 -2
  53. package/dist/vinylTestUtil/types/current/util/playback/expectTrackPlays.d.ts.map +1 -1
  54. package/dist/vinylTestUtil/types/current/util/playback/expectTrackPlays.js +10 -7
  55. package/dist/vinylTestUtil/types/current/util/playback/expectTrackPlaysUntil.d.ts +4 -1
  56. package/dist/vinylTestUtil/types/current/util/playback/expectTrackPlaysUntil.d.ts.map +1 -1
  57. package/dist/vinylTestUtil/types/current/util/playback/expectTrackPlaysUntil.js +3 -2
  58. package/dist/vinylTestUtil/types/ts3.7/media/FrequencyAnalyzer.d.ts +8 -5
  59. package/dist/vinylTestUtil/types/ts3.7/media/unlockMediaElement.d.ts +10 -1
  60. package/dist/vinylTestUtil/types/ts3.7/player/mediaRef.d.ts +7 -0
  61. package/dist/vinylTestUtil/types/ts3.7/ui/requireUserInteraction.d.ts +6 -2
  62. package/dist/vinylTestUtil/types/ts3.7/util/playback/expectTrackPlays.d.ts +9 -2
  63. package/dist/vinylTestUtil/types/ts3.7/util/playback/expectTrackPlaysUntil.d.ts +4 -1
  64. package/dist/vinylTestUtil/types/ts4.1/media/FrequencyAnalyzer.d.ts +8 -5
  65. package/dist/vinylTestUtil/types/ts4.1/media/unlockMediaElement.d.ts +10 -1
  66. package/dist/vinylTestUtil/types/ts4.1/player/mediaRef.d.ts +7 -0
  67. package/dist/vinylTestUtil/types/ts4.1/ui/requireUserInteraction.d.ts +6 -2
  68. package/dist/vinylTestUtil/types/ts4.1/util/playback/expectTrackPlays.d.ts +9 -2
  69. package/dist/vinylTestUtil/types/ts4.1/util/playback/expectTrackPlaysUntil.d.ts +4 -1
  70. package/dist/vinylTestUtil/types/ts4.7/media/FrequencyAnalyzer.d.ts +8 -5
  71. package/dist/vinylTestUtil/types/ts4.7/media/unlockMediaElement.d.ts +10 -1
  72. package/dist/vinylTestUtil/types/ts4.7/player/mediaRef.d.ts +7 -0
  73. package/dist/vinylTestUtil/types/ts4.7/ui/requireUserInteraction.d.ts +6 -2
  74. package/dist/vinylTestUtil/types/ts4.7/util/playback/expectTrackPlays.d.ts +9 -2
  75. package/dist/vinylTestUtil/types/ts4.7/util/playback/expectTrackPlaysUntil.d.ts +4 -1
  76. package/package.json +11 -10
@@ -1,5 +1,9 @@
1
1
  /**
2
- * Displays a prompt awaiting user interaction, resolving after a click, keypress, or touch event.
2
+ * Displays a full-page prompt, resolving after a click or key press.
3
+ *
4
+ * @param onInteraction If provided, invoked from within the click or key event handler, so that it may start media
5
+ * playback or resume an AudioContext. If its promise rejects, the error is logged and the prompt remains until the
6
+ * next interaction.
3
7
  */
4
- export declare function requireUserInteraction(): Promise<void>;
8
+ export declare function requireUserInteraction(onInteraction?: () => Promise<void>): Promise<void>;
5
9
  //# sourceMappingURL=requireUserInteraction.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"requireUserInteraction.d.ts","sourceRoot":"","sources":["../../../../../test/vinylTestUtil/ui/requireUserInteraction.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC,CAkB5D"}
1
+ {"version":3,"file":"requireUserInteraction.d.ts","sourceRoot":"","sources":["../../../../../test/vinylTestUtil/ui/requireUserInteraction.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CACxC,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC,CAgCf"}
@@ -3,23 +3,39 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
  /**
6
- * Displays a prompt awaiting user interaction, resolving after a click, keypress, or touch event.
6
+ * Displays a full-page prompt, resolving after a click or key press.
7
+ *
8
+ * @param onInteraction If provided, invoked from within the click or key event handler, so that it may start media
9
+ * playback or resume an AudioContext. If its promise rejects, the error is logged and the prompt remains until the
10
+ * next interaction.
7
11
  */
8
- export async function requireUserInteraction() {
9
- const audioPrompt = document.getElementById('unlockAudioPrompt');
10
- audioPrompt.style.removeProperty('display');
11
- const body = document.body;
12
- body.focus();
12
+ export async function requireUserInteraction(onInteraction) {
13
+ const prompt = document.getElementById('unlockAudioPrompt');
14
+ prompt.style.removeProperty('display');
15
+ prompt.querySelector('button')?.focus();
13
16
  await new Promise((resolve) => {
14
- const done = () => {
15
- body.removeEventListener('click', done);
16
- body.removeEventListener('keypress', done);
17
- body.removeEventListener('touchend', done);
18
- return resolve(void 0);
17
+ let handling = false;
18
+ const handler = (event) => {
19
+ if (handling)
20
+ return;
21
+ handling = true;
22
+ const result = onInteraction?.() ?? Promise.resolve();
23
+ result
24
+ .then(() => {
25
+ prompt.removeEventListener('click', handler);
26
+ document.removeEventListener('keydown', handler);
27
+ resolve();
28
+ })
29
+ .catch((error) => {
30
+ console.warn(`The ${event.type} (isTrusted: ${event.isTrusted}) was not accepted as a user gesture; ` +
31
+ 'interact again.', error);
32
+ })
33
+ .finally(() => {
34
+ handling = false;
35
+ });
19
36
  };
20
- body.addEventListener('click', done);
21
- body.addEventListener('keypress', done);
22
- body.addEventListener('touchend', done);
37
+ prompt.addEventListener('click', handler);
38
+ document.addEventListener('keydown', handler);
23
39
  });
24
- audioPrompt.style.display = 'none';
40
+ prompt.style.display = 'none';
25
41
  }
@@ -1,6 +1,12 @@
1
1
  import type { VinylPlayer } from '@amazon/vinyl';
2
2
  import { type TrackLoadOptions } from '@amazon/vinyl';
3
- export declare function expectTrackPlays(player: VinylPlayer<any>): Promise<void>;
3
+ export interface ExpectTrackPlaysOptions {
4
+ /**
5
+ * Multiplies the time allowed to play, for environments that play slower than real time. Default: 1
6
+ */
7
+ readonly timeoutScale?: number;
8
+ }
9
+ export declare function expectTrackPlays(player: VinylPlayer<any>, { timeoutScale }?: ExpectTrackPlaysOptions): Promise<void>;
4
10
  /**
5
11
  * Asserts that every track in a playlist plays.
6
12
  * Has assertions for queue events, playback events, time updates, duration,
@@ -8,6 +14,7 @@ export declare function expectTrackPlays(player: VinylPlayer<any>): Promise<void
8
14
  *
9
15
  * @param player
10
16
  * @param playlist
17
+ * @param options
11
18
  */
12
- export declare function expectPlaylistPlays<T extends TrackLoadOptions>(player: VinylPlayer<T>, playlist: T[]): Promise<void>;
19
+ export declare function expectPlaylistPlays<T extends TrackLoadOptions>(player: VinylPlayer<T>, playlist: T[], { timeoutScale }?: ExpectTrackPlaysOptions): Promise<void>;
13
20
  //# sourceMappingURL=expectTrackPlays.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"expectTrackPlays.d.ts","sourceRoot":"","sources":["../../../../../../test/vinylTestUtil/util/playback/expectTrackPlays.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAarD,wBAAsB,gBAAgB,CAClC,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,GACzB,OAAO,CAAC,IAAI,CAAC,CAqCf;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,SAAS,gBAAgB,EAChE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,QAAQ,EAAE,CAAC,EAAE,GACd,OAAO,CAAC,IAAI,CAAC,CA4Bf"}
1
+ {"version":3,"file":"expectTrackPlays.d.ts","sourceRoot":"","sources":["../../../../../../test/vinylTestUtil/util/playback/expectTrackPlays.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAarD,MAAM,WAAW,uBAAuB;IACpC;;OAEG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CACjC;AAED,wBAAsB,gBAAgB,CAClC,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,EACxB,EAAE,YAAgB,EAAE,GAAE,uBAA4B,GACnD,OAAO,CAAC,IAAI,CAAC,CAuCf;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,SAAS,gBAAgB,EAChE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EACtB,QAAQ,EAAE,CAAC,EAAE,EACb,EAAE,YAAgB,EAAE,GAAE,uBAA4B,GACnD,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
@@ -12,7 +12,7 @@ import { expectTrackPlaysUntil } from './expectTrackPlaysUntil';
12
12
  * track.
13
13
  */
14
14
  const PLAYBACK_DURATION = 6;
15
- export async function expectTrackPlays(player) {
15
+ export async function expectTrackPlays(player, { timeoutScale = 1 } = {}) {
16
16
  const { dispose, add } = createDisposer();
17
17
  const ended = add(createEventSpy(player, 'ended'));
18
18
  const timeUpdate = add(createEventSpy(player, 'timeUpdate'));
@@ -27,7 +27,7 @@ export async function expectTrackPlays(player) {
27
27
  if (player.duration > PLAYBACK_DURATION) {
28
28
  // For longer tracks, play from the beginning, then seek to near the end
29
29
  // All tracks will play for at most PLAYBACK_DURATION seconds.
30
- await expectTrackPlaysUntil(player, player.currentTime + PLAYBACK_DURATION / 2);
30
+ await expectTrackPlaysUntil(player, player.currentTime + PLAYBACK_DURATION / 2, undefined, { timeoutScale });
31
31
  const time = player.duration - PLAYBACK_DURATION / 2;
32
32
  await player.seekTo(time);
33
33
  }
@@ -36,7 +36,7 @@ export async function expectTrackPlays(player) {
36
36
  // the expectation will fail due to the next track starting.
37
37
  // Add a large buffer for the timeout; Seeking in a progressive track
38
38
  // can take a long time on some browsers.
39
- await ended.next(PLAYBACK_DURATION + 10);
39
+ await ended.next((PLAYBACK_DURATION + 10) * timeoutScale);
40
40
  expect(player.currentTime).toBeCloseToWithin(duration, 3);
41
41
  expect(player.ended).withContext('ended').toBeTrue();
42
42
  // Expect at least one update per second. This varies among platforms.
@@ -50,11 +50,12 @@ export async function expectTrackPlays(player) {
50
50
  *
51
51
  * @param player
52
52
  * @param playlist
53
+ * @param options
53
54
  */
54
- export async function expectPlaylistPlays(player, playlist) {
55
+ export async function expectPlaylistPlays(player, playlist, { timeoutScale = 1 } = {}) {
55
56
  const { dispose, add } = createDisposer();
56
57
  // Add a significant buffer to the timeout; progressive tracks can take a long time to load after a seek.
57
- const trackTimeout = PLAYBACK_DURATION + 60; // Timeout to give each track
58
+ const trackTimeout = (PLAYBACK_DURATION + 60) * timeoutScale; // Timeout to give each track
58
59
  const queueEnded = add(createEventSpy(player, 'queueEnded'));
59
60
  const queueChange = add(createEventSpy(player, 'queueChange'));
60
61
  const trackChange = add(createEventSpy(player, 'trackActivated'));
@@ -73,8 +74,10 @@ export async function expectPlaylistPlays(player, playlist) {
73
74
  const nextTrack = isLastTrack
74
75
  ? queueEnded.next(trackTimeout)
75
76
  : trackChange.next(trackTimeout);
76
- await expectTrackPlays(player);
77
- await nextTrack;
77
+ await Promise.all([
78
+ expectTrackPlays(player, { timeoutScale }),
79
+ nextTrack,
80
+ ]);
78
81
  assertQueueChangeCount(isLastTrack ? 0 : 1);
79
82
  }
80
83
  dispose();
@@ -7,6 +7,9 @@ import type { ReadonlyPlaybackController } from '@amazon/vinyl';
7
7
  * @param endTime
8
8
  * @param timeout A timeout beyond the expected amount of time to play.
9
9
  * This does not affect waiting for ready state.
10
+ * @param timeoutScale Multiplies the time allowed to play, for environments that play slower than real time.
10
11
  */
11
- export declare function expectTrackPlaysUntil(player: ReadonlyPlaybackController, endTime: number, timeout?: number): Promise<void>;
12
+ export declare function expectTrackPlaysUntil(player: ReadonlyPlaybackController, endTime: number, timeout?: number, { timeoutScale }?: {
13
+ readonly timeoutScale?: number;
14
+ }): Promise<void>;
12
15
  //# sourceMappingURL=expectTrackPlaysUntil.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"expectTrackPlaysUntil.d.ts","sourceRoot":"","sources":["../../../../../../test/vinylTestUtil/util/playback/expectTrackPlaysUntil.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAA;AAO/D;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACvC,MAAM,EAAE,0BAA0B,EAClC,OAAO,EAAE,MAAM,EACf,OAAO,SAAK,iBA2Bf"}
1
+ {"version":3,"file":"expectTrackPlaysUntil.d.ts","sourceRoot":"","sources":["../../../../../../test/vinylTestUtil/util/playback/expectTrackPlaysUntil.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAA;AAO/D;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACvC,MAAM,EAAE,0BAA0B,EAClC,OAAO,EAAE,MAAM,EACf,OAAO,SAAK,EACZ,EAAE,YAAgB,EAAE,GAAE;IAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAO,iBA2BhE"}
@@ -16,8 +16,9 @@ const affordanceAfter = 3;
16
16
  * @param endTime
17
17
  * @param timeout A timeout beyond the expected amount of time to play.
18
18
  * This does not affect waiting for ready state.
19
+ * @param timeoutScale Multiplies the time allowed to play, for environments that play slower than real time.
19
20
  */
20
- export async function expectTrackPlaysUntil(player, endTime, timeout = 20) {
21
+ export async function expectTrackPlaysUntil(player, endTime, timeout = 20, { timeoutScale = 1 } = {}) {
21
22
  await onPlaying(player);
22
23
  // Safari does not always have an updated currentTime after a seeked event. Await the next time update before
23
24
  // asserting currentTime values.
@@ -29,7 +30,7 @@ export async function expectTrackPlaysUntil(player, endTime, timeout = 20) {
29
30
  const startedBeforeEnd = player.currentTime < endTime;
30
31
  await assertFrequency();
31
32
  let elapsed = 0;
32
- const maxTime = endTime - player.currentTime + timeout;
33
+ const maxTime = (endTime - player.currentTime + timeout) * timeoutScale;
33
34
  while (!player.ended && player.currentTime < endTime && elapsed < maxTime) {
34
35
  await sleep(sleepInterval);
35
36
  elapsed += sleepInterval;
@@ -29,6 +29,11 @@ export declare class FrequencyAnalyzer implements LogTarget {
29
29
  */
30
30
  assertFrequency(timeout?: number): Promise<void>;
31
31
  }
32
+ /**
33
+ * The volume integ tests play at when checkAudio is set. Analyzers do not work at volume 0 or muted, and the
34
+ * measured dB is affected at very low volumes.
35
+ */
36
+ export declare const ANALYZER_VOLUME = 0.01;
32
37
  /**
33
38
  * A query param, if present, will indicate that audio should be analyzed. Does not work in CI environments.
34
39
  */
@@ -39,12 +44,10 @@ export declare const shouldCheckAudio: boolean;
39
44
  */
40
45
  export declare function assertFrequency(): Promise<void>;
41
46
  /**
42
- * Displays an interaction prompt if checkAudio is present in the query params.
47
+ * Attaches an analyzer to the shared media element if checkAudio is present in the query params.
43
48
  *
44
- * The checkAudio query param, if present, indicates that the actual sound output should be analyzed. This requires
45
- * a user gesture unless the UA doesn't require it. Most browsers require the gesture, but some platforms this
46
- * requirement may be skipped with a flag. Note that Google deprecated --autoplay-policy=no-user-gesture-required
47
- * March 2023, but older versions may still support it.
49
+ * The checkAudio query param, if present, indicates that the actual sound output should be analyzed. The analyzer is
50
+ * created after the media element is unlocked, so `initializeMediaUnlock` must be called first.
48
51
  */
49
52
  export declare function initializeFrequencyAnalyzer(): void;
50
53
  //# sourceMappingURL=FrequencyAnalyzer.d.ts.map
@@ -1,6 +1,15 @@
1
1
  /**
2
- * In response to a user-gesture, 'unlocks' the media element by playing and immediately pausing a src track.
2
+ * 'Unlocks' the media element by playing and immediately pausing a src track, and resumes the AudioContext.
3
3
  * This allows play() to settle on the media element without a user gesture later.
4
+ *
5
+ * Must be called synchronously from a user gesture handler. Rejects if the browser did not accept the gesture.
4
6
  */
5
7
  export declare function unlockMediaElement(): Promise<void>;
8
+ /**
9
+ * In a browser, prompts for a click before any spec runs, unlocking the shared media element in response.
10
+ *
11
+ * Starting playback without a user gesture is only allowed for muted media, and some browsers (Safari 27)
12
+ * end progressive playback that starts silently without one, so integ tests play unmuted after this unlock.
13
+ */
14
+ export declare function initializeMediaUnlock(): void;
6
15
  //# sourceMappingURL=unlockMediaElement.d.ts.map
@@ -1,6 +1,13 @@
1
+ /**
2
+ * The volume integ tests play at: low enough not to be heard, but not 0 or muted. Safari 27 ends progressive
3
+ * playback that starts silently without a user gesture, and the media element is unlocked at this volume.
4
+ */
5
+ export declare const MEDIA_VOLUME = 0.0001;
1
6
  /**
2
7
  * For reliable integ tests on 3P devices, there should be a single media element.
3
8
  * When using the media element, unload any sources and reset any state after each test.
9
+ *
10
+ * The element is unmuted at {@link MEDIA_VOLUME}; see `initializeMediaUnlock`.
4
11
  */
5
12
  export declare const mediaRef: import("@amazon/vinyl-util").Lazy<HTMLMediaElement>;
6
13
  //# sourceMappingURL=mediaRef.d.ts.map
@@ -1,5 +1,9 @@
1
1
  /**
2
- * Displays a prompt awaiting user interaction, resolving after a click, keypress, or touch event.
2
+ * Displays a full-page prompt, resolving after a click or key press.
3
+ *
4
+ * @param onInteraction If provided, invoked from within the click or key event handler, so that it may start media
5
+ * playback or resume an AudioContext. If its promise rejects, the error is logged and the prompt remains until the
6
+ * next interaction.
3
7
  */
4
- export declare function requireUserInteraction(): Promise<void>;
8
+ export declare function requireUserInteraction(onInteraction?: () => Promise<void>): Promise<void>;
5
9
  //# sourceMappingURL=requireUserInteraction.d.ts.map
@@ -1,6 +1,12 @@
1
1
  import { VinylPlayer } from '@amazon/vinyl';
2
2
  import { TrackLoadOptions } from '@amazon/vinyl';
3
- export declare function expectTrackPlays(player: VinylPlayer<any>): Promise<void>;
3
+ export interface ExpectTrackPlaysOptions {
4
+ /**
5
+ * Multiplies the time allowed to play, for environments that play slower than real time. Default: 1
6
+ */
7
+ readonly timeoutScale?: number;
8
+ }
9
+ export declare function expectTrackPlays(player: VinylPlayer<any>, { timeoutScale }?: ExpectTrackPlaysOptions): Promise<void>;
4
10
  /**
5
11
  * Asserts that every track in a playlist plays.
6
12
  * Has assertions for queue events, playback events, time updates, duration,
@@ -8,6 +14,7 @@ export declare function expectTrackPlays(player: VinylPlayer<any>): Promise<void
8
14
  *
9
15
  * @param player
10
16
  * @param playlist
17
+ * @param options
11
18
  */
12
- export declare function expectPlaylistPlays<T extends TrackLoadOptions>(player: VinylPlayer<T>, playlist: T[]): Promise<void>;
19
+ export declare function expectPlaylistPlays<T extends TrackLoadOptions>(player: VinylPlayer<T>, playlist: T[], { timeoutScale }?: ExpectTrackPlaysOptions): Promise<void>;
13
20
  //# sourceMappingURL=expectTrackPlays.d.ts.map
@@ -7,6 +7,9 @@ import { ReadonlyPlaybackController } from '@amazon/vinyl';
7
7
  * @param endTime
8
8
  * @param timeout A timeout beyond the expected amount of time to play.
9
9
  * This does not affect waiting for ready state.
10
+ * @param timeoutScale Multiplies the time allowed to play, for environments that play slower than real time.
10
11
  */
11
- export declare function expectTrackPlaysUntil(player: ReadonlyPlaybackController, endTime: number, timeout?: number): Promise<void>;
12
+ export declare function expectTrackPlaysUntil(player: ReadonlyPlaybackController, endTime: number, timeout?: number, { timeoutScale }?: {
13
+ readonly timeoutScale?: number;
14
+ }): Promise<void>;
12
15
  //# sourceMappingURL=expectTrackPlaysUntil.d.ts.map
@@ -29,6 +29,11 @@ export declare class FrequencyAnalyzer implements LogTarget {
29
29
  */
30
30
  assertFrequency(timeout?: number): Promise<void>;
31
31
  }
32
+ /**
33
+ * The volume integ tests play at when checkAudio is set. Analyzers do not work at volume 0 or muted, and the
34
+ * measured dB is affected at very low volumes.
35
+ */
36
+ export declare const ANALYZER_VOLUME = 0.01;
32
37
  /**
33
38
  * A query param, if present, will indicate that audio should be analyzed. Does not work in CI environments.
34
39
  */
@@ -39,12 +44,10 @@ export declare const shouldCheckAudio: boolean;
39
44
  */
40
45
  export declare function assertFrequency(): Promise<void>;
41
46
  /**
42
- * Displays an interaction prompt if checkAudio is present in the query params.
47
+ * Attaches an analyzer to the shared media element if checkAudio is present in the query params.
43
48
  *
44
- * The checkAudio query param, if present, indicates that the actual sound output should be analyzed. This requires
45
- * a user gesture unless the UA doesn't require it. Most browsers require the gesture, but some platforms this
46
- * requirement may be skipped with a flag. Note that Google deprecated --autoplay-policy=no-user-gesture-required
47
- * March 2023, but older versions may still support it.
49
+ * The checkAudio query param, if present, indicates that the actual sound output should be analyzed. The analyzer is
50
+ * created after the media element is unlocked, so `initializeMediaUnlock` must be called first.
48
51
  */
49
52
  export declare function initializeFrequencyAnalyzer(): void;
50
53
  //# sourceMappingURL=FrequencyAnalyzer.d.ts.map
@@ -1,6 +1,15 @@
1
1
  /**
2
- * In response to a user-gesture, 'unlocks' the media element by playing and immediately pausing a src track.
2
+ * 'Unlocks' the media element by playing and immediately pausing a src track, and resumes the AudioContext.
3
3
  * This allows play() to settle on the media element without a user gesture later.
4
+ *
5
+ * Must be called synchronously from a user gesture handler. Rejects if the browser did not accept the gesture.
4
6
  */
5
7
  export declare function unlockMediaElement(): Promise<void>;
8
+ /**
9
+ * In a browser, prompts for a click before any spec runs, unlocking the shared media element in response.
10
+ *
11
+ * Starting playback without a user gesture is only allowed for muted media, and some browsers (Safari 27)
12
+ * end progressive playback that starts silently without one, so integ tests play unmuted after this unlock.
13
+ */
14
+ export declare function initializeMediaUnlock(): void;
6
15
  //# sourceMappingURL=unlockMediaElement.d.ts.map
@@ -1,6 +1,13 @@
1
+ /**
2
+ * The volume integ tests play at: low enough not to be heard, but not 0 or muted. Safari 27 ends progressive
3
+ * playback that starts silently without a user gesture, and the media element is unlocked at this volume.
4
+ */
5
+ export declare const MEDIA_VOLUME = 0.0001;
1
6
  /**
2
7
  * For reliable integ tests on 3P devices, there should be a single media element.
3
8
  * When using the media element, unload any sources and reset any state after each test.
9
+ *
10
+ * The element is unmuted at {@link MEDIA_VOLUME}; see `initializeMediaUnlock`.
4
11
  */
5
12
  export declare const mediaRef: import("@amazon/vinyl-util").Lazy<HTMLMediaElement>;
6
13
  //# sourceMappingURL=mediaRef.d.ts.map
@@ -1,5 +1,9 @@
1
1
  /**
2
- * Displays a prompt awaiting user interaction, resolving after a click, keypress, or touch event.
2
+ * Displays a full-page prompt, resolving after a click or key press.
3
+ *
4
+ * @param onInteraction If provided, invoked from within the click or key event handler, so that it may start media
5
+ * playback or resume an AudioContext. If its promise rejects, the error is logged and the prompt remains until the
6
+ * next interaction.
3
7
  */
4
- export declare function requireUserInteraction(): Promise<void>;
8
+ export declare function requireUserInteraction(onInteraction?: () => Promise<void>): Promise<void>;
5
9
  //# sourceMappingURL=requireUserInteraction.d.ts.map
@@ -1,6 +1,12 @@
1
1
  import type { VinylPlayer } from '@amazon/vinyl';
2
2
  import type { TrackLoadOptions } from '@amazon/vinyl';
3
- export declare function expectTrackPlays(player: VinylPlayer<any>): Promise<void>;
3
+ export interface ExpectTrackPlaysOptions {
4
+ /**
5
+ * Multiplies the time allowed to play, for environments that play slower than real time. Default: 1
6
+ */
7
+ readonly timeoutScale?: number;
8
+ }
9
+ export declare function expectTrackPlays(player: VinylPlayer<any>, { timeoutScale }?: ExpectTrackPlaysOptions): Promise<void>;
4
10
  /**
5
11
  * Asserts that every track in a playlist plays.
6
12
  * Has assertions for queue events, playback events, time updates, duration,
@@ -8,6 +14,7 @@ export declare function expectTrackPlays(player: VinylPlayer<any>): Promise<void
8
14
  *
9
15
  * @param player
10
16
  * @param playlist
17
+ * @param options
11
18
  */
12
- export declare function expectPlaylistPlays<T extends TrackLoadOptions>(player: VinylPlayer<T>, playlist: T[]): Promise<void>;
19
+ export declare function expectPlaylistPlays<T extends TrackLoadOptions>(player: VinylPlayer<T>, playlist: T[], { timeoutScale }?: ExpectTrackPlaysOptions): Promise<void>;
13
20
  //# sourceMappingURL=expectTrackPlays.d.ts.map
@@ -7,6 +7,9 @@ import type { ReadonlyPlaybackController } from '@amazon/vinyl';
7
7
  * @param endTime
8
8
  * @param timeout A timeout beyond the expected amount of time to play.
9
9
  * This does not affect waiting for ready state.
10
+ * @param timeoutScale Multiplies the time allowed to play, for environments that play slower than real time.
10
11
  */
11
- export declare function expectTrackPlaysUntil(player: ReadonlyPlaybackController, endTime: number, timeout?: number): Promise<void>;
12
+ export declare function expectTrackPlaysUntil(player: ReadonlyPlaybackController, endTime: number, timeout?: number, { timeoutScale }?: {
13
+ readonly timeoutScale?: number;
14
+ }): Promise<void>;
12
15
  //# sourceMappingURL=expectTrackPlaysUntil.d.ts.map
@@ -35,6 +35,11 @@ export declare class FrequencyAnalyzer implements LogTarget {
35
35
  */
36
36
  assertFrequency(timeout?: number): Promise<void>;
37
37
  }
38
+ /**
39
+ * The volume integ tests play at when checkAudio is set. Analyzers do not work at volume 0 or muted, and the
40
+ * measured dB is affected at very low volumes.
41
+ */
42
+ export declare const ANALYZER_VOLUME = 0.01;
38
43
  /**
39
44
  * A query param, if present, will indicate that audio should be analyzed. Does not work in CI environments.
40
45
  */
@@ -45,12 +50,10 @@ export declare const shouldCheckAudio: boolean;
45
50
  */
46
51
  export declare function assertFrequency(): Promise<void>;
47
52
  /**
48
- * Displays an interaction prompt if checkAudio is present in the query params.
53
+ * Attaches an analyzer to the shared media element if checkAudio is present in the query params.
49
54
  *
50
- * The checkAudio query param, if present, indicates that the actual sound output should be analyzed. This requires
51
- * a user gesture unless the UA doesn't require it. Most browsers require the gesture, but some platforms this
52
- * requirement may be skipped with a flag. Note that Google deprecated --autoplay-policy=no-user-gesture-required
53
- * March 2023, but older versions may still support it.
55
+ * The checkAudio query param, if present, indicates that the actual sound output should be analyzed. The analyzer is
56
+ * created after the media element is unlocked, so `initializeMediaUnlock` must be called first.
54
57
  */
55
58
  export declare function initializeFrequencyAnalyzer(): void;
56
59
  //# sourceMappingURL=FrequencyAnalyzer.d.ts.map
@@ -1,6 +1,15 @@
1
1
  /**
2
- * In response to a user-gesture, 'unlocks' the media element by playing and immediately pausing a src track.
2
+ * 'Unlocks' the media element by playing and immediately pausing a src track, and resumes the AudioContext.
3
3
  * This allows play() to settle on the media element without a user gesture later.
4
+ *
5
+ * Must be called synchronously from a user gesture handler. Rejects if the browser did not accept the gesture.
4
6
  */
5
7
  export declare function unlockMediaElement(): Promise<void>;
8
+ /**
9
+ * In a browser, prompts for a click before any spec runs, unlocking the shared media element in response.
10
+ *
11
+ * Starting playback without a user gesture is only allowed for muted media, and some browsers (Safari 27)
12
+ * end progressive playback that starts silently without one, so integ tests play unmuted after this unlock.
13
+ */
14
+ export declare function initializeMediaUnlock(): void;
6
15
  //# sourceMappingURL=unlockMediaElement.d.ts.map
@@ -1,6 +1,13 @@
1
+ /**
2
+ * The volume integ tests play at: low enough not to be heard, but not 0 or muted. Safari 27 ends progressive
3
+ * playback that starts silently without a user gesture, and the media element is unlocked at this volume.
4
+ */
5
+ export declare const MEDIA_VOLUME = 0.0001;
1
6
  /**
2
7
  * For reliable integ tests on 3P devices, there should be a single media element.
3
8
  * When using the media element, unload any sources and reset any state after each test.
9
+ *
10
+ * The element is unmuted at {@link MEDIA_VOLUME}; see `initializeMediaUnlock`.
4
11
  */
5
12
  export declare const mediaRef: import("@amazon/vinyl-util").Lazy<HTMLMediaElement>;
6
13
  //# sourceMappingURL=mediaRef.d.ts.map
@@ -1,5 +1,9 @@
1
1
  /**
2
- * Displays a prompt awaiting user interaction, resolving after a click, keypress, or touch event.
2
+ * Displays a full-page prompt, resolving after a click or key press.
3
+ *
4
+ * @param onInteraction If provided, invoked from within the click or key event handler, so that it may start media
5
+ * playback or resume an AudioContext. If its promise rejects, the error is logged and the prompt remains until the
6
+ * next interaction.
3
7
  */
4
- export declare function requireUserInteraction(): Promise<void>;
8
+ export declare function requireUserInteraction(onInteraction?: () => Promise<void>): Promise<void>;
5
9
  //# sourceMappingURL=requireUserInteraction.d.ts.map
@@ -1,6 +1,12 @@
1
1
  import type { VinylPlayer } from '@amazon/vinyl';
2
2
  import { type TrackLoadOptions } from '@amazon/vinyl';
3
- export declare function expectTrackPlays(player: VinylPlayer<any>): Promise<void>;
3
+ export interface ExpectTrackPlaysOptions {
4
+ /**
5
+ * Multiplies the time allowed to play, for environments that play slower than real time. Default: 1
6
+ */
7
+ readonly timeoutScale?: number;
8
+ }
9
+ export declare function expectTrackPlays(player: VinylPlayer<any>, { timeoutScale }?: ExpectTrackPlaysOptions): Promise<void>;
4
10
  /**
5
11
  * Asserts that every track in a playlist plays.
6
12
  * Has assertions for queue events, playback events, time updates, duration,
@@ -8,6 +14,7 @@ export declare function expectTrackPlays(player: VinylPlayer<any>): Promise<void
8
14
  *
9
15
  * @param player
10
16
  * @param playlist
17
+ * @param options
11
18
  */
12
- export declare function expectPlaylistPlays<T extends TrackLoadOptions>(player: VinylPlayer<T>, playlist: T[]): Promise<void>;
19
+ export declare function expectPlaylistPlays<T extends TrackLoadOptions>(player: VinylPlayer<T>, playlist: T[], { timeoutScale }?: ExpectTrackPlaysOptions): Promise<void>;
13
20
  //# sourceMappingURL=expectTrackPlays.d.ts.map
@@ -7,6 +7,9 @@ import type { ReadonlyPlaybackController } from '@amazon/vinyl';
7
7
  * @param endTime
8
8
  * @param timeout A timeout beyond the expected amount of time to play.
9
9
  * This does not affect waiting for ready state.
10
+ * @param timeoutScale Multiplies the time allowed to play, for environments that play slower than real time.
10
11
  */
11
- export declare function expectTrackPlaysUntil(player: ReadonlyPlaybackController, endTime: number, timeout?: number): Promise<void>;
12
+ export declare function expectTrackPlaysUntil(player: ReadonlyPlaybackController, endTime: number, timeout?: number, { timeoutScale }?: {
13
+ readonly timeoutScale?: number;
14
+ }): Promise<void>;
12
15
  //# sourceMappingURL=expectTrackPlaysUntil.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amazon/vinyl",
3
- "version": "4.0.0",
3
+ "version": "4.0.1-next.20261016220320",
4
4
  "description": "An HTML5 streaming media player",
5
5
  "repository": {
6
6
  "type": "git",
@@ -81,6 +81,7 @@
81
81
  "test": "tsx ../../node_modules/jasmine/bin/jasmine --config=test/unit/jasmine.config.json",
82
82
  "test:coverage": "c8 npm run test",
83
83
  "test:browserstack": "npm run build:release && tsx buildSrc/runBrowserStack.ts",
84
+ "test:integ": "npm run build:release && tsx buildSrc/runInteg.ts",
84
85
  "benchmark:abr": "tsx test/abrBenchmark/run.ts",
85
86
  "start": "tsx buildSrc/build.ts --serve",
86
87
  "start:release": "tsx buildSrc/build.ts --serve --release",
@@ -90,18 +91,18 @@
90
91
  "oxlint:write": "oxlint --type-aware --fix"
91
92
  },
92
93
  "devDependencies": {
93
- "@amazon/vinyl-browserstack": "^4.0.0",
94
- "@amazon/vinyl-build-utils": "^4.0.0",
94
+ "@amazon/vinyl-browserstack": "4.0.1-next.20261016220320",
95
+ "@amazon/vinyl-build-utils": "4.0.1-next.20261016220320",
95
96
  "commander": "^15.0.0"
96
97
  },
97
98
  "dependencies": {
98
- "@amazon/vinyl-di": "^4.0.0",
99
- "@amazon/vinyl-hls-parser": "^4.0.0",
100
- "@amazon/vinyl-mpd-parser": "^4.0.0",
101
- "@amazon/vinyl-observable": "^4.0.0",
102
- "@amazon/vinyl-transmux": "^4.0.0",
103
- "@amazon/vinyl-util": "^4.0.0",
104
- "@amazon/vinyl-validation": "^4.0.0"
99
+ "@amazon/vinyl-di": "4.0.1-next.20261016220320",
100
+ "@amazon/vinyl-hls-parser": "4.0.1-next.20261016220320",
101
+ "@amazon/vinyl-mpd-parser": "4.0.1-next.20261016220320",
102
+ "@amazon/vinyl-observable": "4.0.1-next.20261016220320",
103
+ "@amazon/vinyl-transmux": "4.0.1-next.20261016220320",
104
+ "@amazon/vinyl-util": "4.0.1-next.20261016220320",
105
+ "@amazon/vinyl-validation": "4.0.1-next.20261016220320"
105
106
  },
106
107
  "publishConfig": {
107
108
  "access": "public"