@remotion/media 4.0.430 → 4.0.432

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 (63) hide show
  1. package/dist/audio/audio-for-preview.d.ts +1 -0
  2. package/dist/audio/audio-preview-iterator.d.ts +16 -9
  3. package/dist/audio/props.d.ts +1 -0
  4. package/dist/audio-iterator-manager.d.ts +24 -13
  5. package/dist/debug-overlay/preview-overlay.d.ts +24 -14
  6. package/dist/esm/index.mjs +755 -537
  7. package/dist/make-iterator-with-priming.d.ts +6 -0
  8. package/dist/media-player.d.ts +12 -7
  9. package/dist/prewarm-iterator-for-looping.d.ts +3 -2
  10. package/dist/set-global-time-anchor.d.ts +11 -0
  11. package/dist/shared-audio-context-for-media-player.d.ts +8 -0
  12. package/dist/use-common-effects.d.ts +32 -0
  13. package/dist/video/props.d.ts +1 -0
  14. package/dist/video/video-for-preview.d.ts +1 -0
  15. package/package.json +4 -4
  16. package/dist/audio/allow-wait.d.ts +0 -6
  17. package/dist/audio/allow-wait.js +0 -15
  18. package/dist/audio/audio-for-preview.js +0 -304
  19. package/dist/audio/audio-for-rendering.js +0 -194
  20. package/dist/audio/audio-preview-iterator.js +0 -176
  21. package/dist/audio/audio.js +0 -20
  22. package/dist/audio/props.js +0 -1
  23. package/dist/audio-extraction/audio-cache.js +0 -66
  24. package/dist/audio-extraction/audio-iterator.js +0 -132
  25. package/dist/audio-extraction/audio-manager.js +0 -113
  26. package/dist/audio-extraction/extract-audio.js +0 -132
  27. package/dist/audio-iterator-manager.js +0 -228
  28. package/dist/browser-can-use-webgl2.js +0 -13
  29. package/dist/caches.js +0 -61
  30. package/dist/calculate-playbacktime.js +0 -4
  31. package/dist/convert-audiodata/apply-volume.js +0 -17
  32. package/dist/convert-audiodata/combine-audiodata.js +0 -23
  33. package/dist/convert-audiodata/convert-audiodata.js +0 -73
  34. package/dist/convert-audiodata/resample-audiodata.js +0 -94
  35. package/dist/debug-overlay/preview-overlay.js +0 -42
  36. package/dist/extract-frame-and-audio.js +0 -101
  37. package/dist/get-sink.js +0 -15
  38. package/dist/get-time-in-seconds.js +0 -40
  39. package/dist/helpers/round-to-4-digits.js +0 -4
  40. package/dist/index.js +0 -12
  41. package/dist/is-type-of-error.js +0 -20
  42. package/dist/looped-frame.js +0 -10
  43. package/dist/media-player.js +0 -431
  44. package/dist/nonce-manager.js +0 -13
  45. package/dist/prewarm-iterator-for-looping.js +0 -56
  46. package/dist/render-timestamp-range.js +0 -9
  47. package/dist/show-in-timeline.js +0 -31
  48. package/dist/use-media-in-timeline.js +0 -103
  49. package/dist/video/props.js +0 -1
  50. package/dist/video/video-for-preview.js +0 -331
  51. package/dist/video/video-for-rendering.js +0 -263
  52. package/dist/video/video-preview-iterator.js +0 -122
  53. package/dist/video/video.js +0 -35
  54. package/dist/video-extraction/add-broadcast-channel-listener.js +0 -125
  55. package/dist/video-extraction/extract-frame-via-broadcast-channel.js +0 -113
  56. package/dist/video-extraction/extract-frame.js +0 -85
  57. package/dist/video-extraction/get-allocation-size.js +0 -6
  58. package/dist/video-extraction/get-frames-since-keyframe.js +0 -108
  59. package/dist/video-extraction/keyframe-bank.js +0 -159
  60. package/dist/video-extraction/keyframe-manager.js +0 -206
  61. package/dist/video-extraction/remember-actual-matroska-timestamps.js +0 -19
  62. package/dist/video-extraction/rotate-frame.js +0 -34
  63. package/dist/video-iterator-manager.js +0 -109
@@ -37,19 +37,12 @@ var __callDispose = (stack, error, hasError) => {
37
37
  };
38
38
 
39
39
  // src/audio/audio.tsx
40
- import { Internals as Internals15, useRemotionEnvironment as useRemotionEnvironment2 } from "remotion";
40
+ import { Internals as Internals19, useRemotionEnvironment as useRemotionEnvironment2 } from "remotion";
41
41
 
42
42
  // src/audio/audio-for-preview.tsx
43
+ import { useContext as useContext3, useEffect as useEffect2, useMemo as useMemo2, useRef, useState as useState2 } from "react";
43
44
  import {
44
- useContext as useContext2,
45
- useEffect as useEffect2,
46
- useLayoutEffect,
47
- useMemo as useMemo2,
48
- useRef,
49
- useState as useState2
50
- } from "react";
51
- import {
52
- Internals as Internals6,
45
+ Internals as Internals10,
53
46
  Audio as RemotionAudio,
54
47
  useBufferState,
55
48
  useCurrentFrame as useCurrentFrame2,
@@ -109,27 +102,65 @@ var calculateEndTime = ({
109
102
 
110
103
  // src/media-player.ts
111
104
  import { ALL_FORMATS, Input, UrlSource } from "mediabunny";
112
- import { Internals as Internals3 } from "remotion";
105
+ import { Internals as Internals6 } from "remotion";
113
106
 
114
107
  // src/audio-iterator-manager.ts
115
108
  import { AudioBufferSink, InputDisposedError } from "mediabunny";
109
+ import { Internals as Internals4 } from "remotion";
110
+
111
+ // src/audio/audio-preview-iterator.ts
112
+ import { Internals as Internals3 } from "remotion";
116
113
 
117
114
  // src/helpers/round-to-4-digits.ts
118
115
  var roundTo4Digits = (timestamp) => {
119
116
  return Math.round(timestamp * 1000) / 1000;
120
117
  };
121
118
 
119
+ // src/set-global-time-anchor.ts
120
+ import { Internals as Internals2 } from "remotion";
121
+ var ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT = 0.1;
122
+ var setGlobalTimeAnchor = ({
123
+ audioContext,
124
+ audioSyncAnchor,
125
+ absoluteTimeInSeconds,
126
+ globalPlaybackRate,
127
+ debugAudioScheduling,
128
+ logLevel
129
+ }) => {
130
+ const newAnchor = audioContext.currentTime - absoluteTimeInSeconds / globalPlaybackRate;
131
+ const shift = (newAnchor - audioSyncAnchor.value) * globalPlaybackRate;
132
+ if (Math.abs(shift) < ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT) {
133
+ return;
134
+ }
135
+ if (debugAudioScheduling) {
136
+ Internals2.Log.info({ logLevel, tag: "audio-scheduling" }, "Anchor changed from %s to %s with shift %s", audioSyncAnchor.value, newAnchor, shift);
137
+ }
138
+ audioSyncAnchor.value = newAnchor;
139
+ };
140
+
122
141
  // src/audio/audio-preview-iterator.ts
123
- var makeAudioIterator = (startFromSecond, cache) => {
142
+ var makeAudioIterator = (startFromSecond, maximumTimestamp, cache, debugAudioScheduling) => {
124
143
  let destroyed = false;
125
- const iterator = cache.makeIteratorOrUsePrewarmed(startFromSecond);
144
+ const iterator = cache.makeIteratorOrUsePrewarmed(startFromSecond, maximumTimestamp);
126
145
  const queuedAudioNodes = [];
127
146
  const audioChunksForAfterResuming = [];
128
147
  let mostRecentTimestamp = -Infinity;
129
148
  let pendingNext = null;
130
- const cleanupAudioQueue = () => {
149
+ const cleanupAudioQueue = (audioContext) => {
131
150
  for (const node of queuedAudioNodes) {
132
- node.node.stop();
151
+ try {
152
+ const currentlyHearing = audioContext.getOutputTimestamp().contextTime;
153
+ const nodeEndTime = node.scheduledTime + node.buffer.duration / node.playbackRate;
154
+ const isAlreadyPlaying = node.scheduledTime - ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT < audioContext.currentTime;
155
+ const shouldKeep = isAlreadyPlaying;
156
+ if (shouldKeep) {
157
+ continue;
158
+ }
159
+ if (debugAudioScheduling) {
160
+ Internals3.Log.info({ logLevel: "trace", tag: "audio-scheduling" }, `Stopping node ${node.timestamp.toFixed(3)}, currently hearing = ${currentlyHearing.toFixed(3)} currentTime = ${audioContext.currentTime.toFixed(3)} nodeEndTime = ${nodeEndTime.toFixed(3)} scheduledTime = ${node.scheduledTime.toFixed(3)}`);
161
+ }
162
+ node.node.stop();
163
+ } catch {}
133
164
  }
134
165
  queuedAudioNodes.length = 0;
135
166
  };
@@ -238,26 +269,34 @@ var makeAudioIterator = (startFromSecond, cache) => {
238
269
  const removeAndReturnAllQueuedAudioNodes = () => {
239
270
  const nodes = queuedAudioNodes.slice();
240
271
  for (const node of nodes) {
241
- node.node.stop();
272
+ try {
273
+ node.node.stop();
274
+ } catch {}
242
275
  }
243
276
  queuedAudioNodes.length = 0;
244
277
  return nodes;
245
278
  };
246
- const addChunkForAfterResuming = (buffer, timestamp, maxDuration) => {
247
- audioChunksForAfterResuming.push({ buffer, timestamp, maxDuration });
279
+ const addChunkForAfterResuming = (buffer, timestamp) => {
280
+ audioChunksForAfterResuming.push({
281
+ buffer,
282
+ timestamp
283
+ });
248
284
  };
249
285
  const moveQueuedChunksToPauseQueue = () => {
250
286
  const toQueue = removeAndReturnAllQueuedAudioNodes();
251
287
  for (const chunk of toQueue) {
252
- addChunkForAfterResuming(chunk.buffer, chunk.timestamp, chunk.maxDuration);
288
+ addChunkForAfterResuming(chunk.buffer, chunk.timestamp);
289
+ }
290
+ if (debugAudioScheduling && toQueue.length > 0) {
291
+ Internals3.Log.trace({ logLevel: "trace", tag: "audio-scheduling" }, `Moved ${toQueue.length} ${toQueue.length === 1 ? "chunk" : "chunks"} to pause queue (${toQueue[0].timestamp.toFixed(3)}-${toQueue[toQueue.length - 1].timestamp + toQueue[toQueue.length - 1].buffer.duration.toFixed(3)})`);
253
292
  }
254
293
  };
255
294
  const getNumberOfChunksAfterResuming = () => {
256
295
  return audioChunksForAfterResuming.length;
257
296
  };
258
297
  return {
259
- destroy: () => {
260
- cleanupAudioQueue();
298
+ destroy: (audioContext) => {
299
+ cleanupAudioQueue(audioContext);
261
300
  destroyed = true;
262
301
  iterator.return().catch(() => {
263
302
  return;
@@ -274,8 +313,20 @@ var makeAudioIterator = (startFromSecond, cache) => {
274
313
  isDestroyed: () => {
275
314
  return destroyed;
276
315
  },
277
- addQueuedAudioNode: (node, timestamp, buffer, maxDuration) => {
278
- queuedAudioNodes.push({ node, timestamp, buffer, maxDuration });
316
+ addQueuedAudioNode: ({
317
+ node,
318
+ timestamp,
319
+ buffer,
320
+ scheduledTime,
321
+ playbackRate
322
+ }) => {
323
+ queuedAudioNodes.push({
324
+ node,
325
+ timestamp,
326
+ buffer,
327
+ scheduledTime,
328
+ playbackRate
329
+ });
279
330
  },
280
331
  removeQueuedAudioNode: (node) => {
281
332
  const index = queuedAudioNodes.findIndex((n) => n.node === node);
@@ -321,6 +372,121 @@ var isAlreadyQueued = (time, queuedPeriod) => {
321
372
  return time >= queuedPeriod.from && time < queuedPeriod.until;
322
373
  };
323
374
 
375
+ // src/make-iterator-with-priming.ts
376
+ var AUDIO_PRIMING_SECONDS = 0.5;
377
+ var PREDECODE_AHEAD_SECONDS = 8;
378
+ function makePredecodingIterator(inner) {
379
+ const buffer = [];
380
+ let consumerEndTime = 0;
381
+ let innerDone = false;
382
+ let returned = false;
383
+ let fetching = false;
384
+ let waiter = null;
385
+ const prefetch = () => {
386
+ if (fetching || returned || innerDone) {
387
+ return;
388
+ }
389
+ const lastBuffered = buffer.length > 0 ? buffer[buffer.length - 1] : null;
390
+ const bufferedEndTime = lastBuffered ? lastBuffered.timestamp + lastBuffered.duration : consumerEndTime;
391
+ if (bufferedEndTime >= consumerEndTime + PREDECODE_AHEAD_SECONDS) {
392
+ return;
393
+ }
394
+ fetching = true;
395
+ inner.next().then((result) => {
396
+ fetching = false;
397
+ if (returned) {
398
+ return;
399
+ }
400
+ if (result.done) {
401
+ innerDone = true;
402
+ if (waiter) {
403
+ const w = waiter;
404
+ waiter = null;
405
+ w({ value: undefined, done: true });
406
+ }
407
+ return;
408
+ }
409
+ if (waiter) {
410
+ const w = waiter;
411
+ waiter = null;
412
+ const buf = result.value;
413
+ consumerEndTime = buf.timestamp + buf.duration;
414
+ w({ value: buf, done: false });
415
+ prefetch();
416
+ return;
417
+ }
418
+ buffer.push(result.value);
419
+ prefetch();
420
+ }, () => {
421
+ fetching = false;
422
+ innerDone = true;
423
+ if (waiter) {
424
+ const w = waiter;
425
+ waiter = null;
426
+ w({ value: undefined, done: true });
427
+ }
428
+ });
429
+ };
430
+ prefetch();
431
+ const iterator = {
432
+ next() {
433
+ if (buffer.length > 0) {
434
+ const buf = buffer.shift();
435
+ consumerEndTime = buf.timestamp + buf.duration;
436
+ prefetch();
437
+ return Promise.resolve({ value: buf, done: false });
438
+ }
439
+ if (innerDone) {
440
+ return Promise.resolve({
441
+ value: undefined,
442
+ done: true
443
+ });
444
+ }
445
+ return new Promise((resolve) => {
446
+ waiter = resolve;
447
+ prefetch();
448
+ });
449
+ },
450
+ return() {
451
+ returned = true;
452
+ buffer.length = 0;
453
+ if (waiter) {
454
+ const w = waiter;
455
+ waiter = null;
456
+ w({ value: undefined, done: true });
457
+ }
458
+ inner.return(undefined);
459
+ return Promise.resolve({ value: undefined, done: true });
460
+ },
461
+ throw(e) {
462
+ returned = true;
463
+ buffer.length = 0;
464
+ return inner.throw(e);
465
+ },
466
+ [Symbol.asyncIterator]() {
467
+ return iterator;
468
+ }
469
+ };
470
+ return iterator;
471
+ }
472
+ async function* makeIteratorWithPrimingInner(audioSink, timeToSeek, maximumTimestamp) {
473
+ const primingStart = Math.max(0, timeToSeek - AUDIO_PRIMING_SECONDS);
474
+ const iterator = audioSink.buffers(primingStart, maximumTimestamp);
475
+ for await (const buffer of iterator) {
476
+ if (buffer.timestamp + buffer.duration <= timeToSeek) {
477
+ continue;
478
+ }
479
+ yield buffer;
480
+ }
481
+ }
482
+ var makeIteratorWithPriming = ({
483
+ audioSink,
484
+ timeToSeek,
485
+ maximumTimestamp
486
+ }) => {
487
+ return makePredecodingIterator(makeIteratorWithPrimingInner(audioSink, timeToSeek, maximumTimestamp));
488
+ };
489
+
324
490
  // src/prewarm-iterator-for-looping.ts
325
491
  var makePrewarmedVideoIteratorCache = (videoSink) => {
326
492
  const prewarmedVideoIterators = new Map;
@@ -350,20 +516,30 @@ var makePrewarmedVideoIteratorCache = (videoSink) => {
350
516
  destroy
351
517
  };
352
518
  };
519
+ var makeKey = (timeToSeek, maximumTimestamp) => {
520
+ return `${timeToSeek}-${maximumTimestamp}`;
521
+ };
353
522
  var makePrewarmedAudioIteratorCache = (audioSink) => {
354
523
  const prewarmedAudioIterators = new Map;
355
- const prewarmIteratorForLooping = ({ timeToSeek }) => {
356
- if (!prewarmedAudioIterators.has(timeToSeek)) {
357
- prewarmedAudioIterators.set(timeToSeek, audioSink.buffers(timeToSeek));
524
+ const prewarmIteratorForLooping = ({
525
+ timeToSeek,
526
+ maximumTimestamp
527
+ }) => {
528
+ if (!prewarmedAudioIterators.has(makeKey(timeToSeek, maximumTimestamp))) {
529
+ prewarmedAudioIterators.set(makeKey(timeToSeek, maximumTimestamp), makeIteratorWithPriming({ audioSink, timeToSeek, maximumTimestamp }));
358
530
  }
359
531
  };
360
- const makeIteratorOrUsePrewarmed = (timeToSeek) => {
361
- const prewarmedIterator = prewarmedAudioIterators.get(timeToSeek);
532
+ const makeIteratorOrUsePrewarmed = (timeToSeek, maximumTimestamp) => {
533
+ const prewarmedIterator = prewarmedAudioIterators.get(makeKey(timeToSeek, maximumTimestamp));
362
534
  if (prewarmedIterator) {
363
- prewarmedAudioIterators.delete(timeToSeek);
535
+ prewarmedAudioIterators.delete(makeKey(timeToSeek, maximumTimestamp));
364
536
  return prewarmedIterator;
365
537
  }
366
- const iterator = audioSink.buffers(timeToSeek);
538
+ const iterator = makeIteratorWithPriming({
539
+ audioSink,
540
+ timeToSeek,
541
+ maximumTimestamp
542
+ });
367
543
  return iterator;
368
544
  };
369
545
  const destroy = () => {
@@ -405,11 +581,14 @@ var audioIteratorManager = ({
405
581
  mediaTimestamp,
406
582
  playbackRate,
407
583
  scheduleAudioNode,
408
- maxDuration
584
+ debugAudioScheduling
409
585
  }) => {
410
586
  if (!audioBufferIterator) {
411
587
  throw new Error("Audio buffer iterator not found");
412
588
  }
589
+ if (sharedAudioContext.state !== "running") {
590
+ throw new Error("Tried to schedule node while audio context is not running");
591
+ }
413
592
  if (muted) {
414
593
  return;
415
594
  }
@@ -417,42 +596,88 @@ var audioIteratorManager = ({
417
596
  node.buffer = buffer;
418
597
  node.playbackRate.value = playbackRate;
419
598
  node.connect(gainNode);
420
- scheduleAudioNode(node, mediaTimestamp, maxDuration);
599
+ const started = scheduleAudioNode(node, mediaTimestamp);
600
+ if (started.type === "not-started") {
601
+ if (debugAudioScheduling) {
602
+ Internals4.Log.info({ logLevel: "trace", tag: "audio-scheduling" }, "not started, disconnected: %s %s", mediaTimestamp.toFixed(3), buffer.duration.toFixed(3));
603
+ }
604
+ node.disconnect();
605
+ return;
606
+ }
421
607
  const iterator = audioBufferIterator;
422
- iterator.addQueuedAudioNode(node, mediaTimestamp, buffer, maxDuration);
608
+ iterator.addQueuedAudioNode({
609
+ node,
610
+ timestamp: mediaTimestamp,
611
+ buffer,
612
+ scheduledTime: started.scheduledTime,
613
+ playbackRate
614
+ });
423
615
  node.onended = () => {
424
616
  setTimeout(() => {
425
617
  iterator.removeQueuedAudioNode(node);
426
618
  }, 30);
427
619
  };
428
620
  };
621
+ const resumeScheduledAudioChunks = ({
622
+ playbackRate,
623
+ scheduleAudioNode,
624
+ debugAudioScheduling
625
+ }) => {
626
+ if (muted) {
627
+ return;
628
+ }
629
+ if (!audioBufferIterator) {
630
+ return;
631
+ }
632
+ for (const chunk of audioBufferIterator.getAndClearAudioChunksForAfterResuming()) {
633
+ scheduleAudioChunk({
634
+ buffer: chunk.buffer,
635
+ mediaTimestamp: chunk.timestamp,
636
+ playbackRate,
637
+ scheduleAudioNode,
638
+ debugAudioScheduling
639
+ });
640
+ }
641
+ };
429
642
  const onAudioChunk = ({
430
643
  getIsPlaying,
431
644
  buffer,
432
645
  playbackRate,
433
- scheduleAudioNode
646
+ scheduleAudioNode,
647
+ debugAudioScheduling
434
648
  }) => {
435
649
  if (muted) {
436
650
  return;
437
651
  }
652
+ const startTime = getStartTime();
438
653
  const endTime = getEndTime();
654
+ if (buffer.timestamp + buffer.duration <= startTime) {
655
+ return;
656
+ }
439
657
  if (buffer.timestamp >= endTime) {
440
658
  return;
441
659
  }
442
- const maxDuration = buffer.timestamp + buffer.duration > endTime ? endTime - buffer.timestamp : null;
443
- if (getIsPlaying()) {
660
+ if (getIsPlaying() && sharedAudioContext.state === "running" && (sharedAudioContext.getOutputTimestamp().contextTime ?? 0) > 0) {
661
+ resumeScheduledAudioChunks({
662
+ playbackRate,
663
+ scheduleAudioNode,
664
+ debugAudioScheduling
665
+ });
444
666
  scheduleAudioChunk({
445
667
  buffer: buffer.buffer,
446
668
  mediaTimestamp: buffer.timestamp,
447
669
  playbackRate,
448
670
  scheduleAudioNode,
449
- maxDuration
671
+ debugAudioScheduling
450
672
  });
451
673
  } else {
452
674
  if (!audioBufferIterator) {
453
675
  throw new Error("Audio buffer iterator not found");
454
676
  }
455
- audioBufferIterator.addChunkForAfterResuming(buffer.buffer, buffer.timestamp, maxDuration);
677
+ if (debugAudioScheduling) {
678
+ Internals4.Log.info({ logLevel: "trace", tag: "audio-scheduling" }, "not ready, added to queue: %s %s", buffer.timestamp.toFixed(3), buffer.duration.toFixed(3));
679
+ }
680
+ audioBufferIterator.addChunkForAfterResuming(buffer.buffer, buffer.timestamp);
456
681
  }
457
682
  drawDebugOverlay();
458
683
  };
@@ -461,17 +686,18 @@ var audioIteratorManager = ({
461
686
  playbackRate,
462
687
  startFromSecond,
463
688
  getIsPlaying,
464
- scheduleAudioNode
689
+ scheduleAudioNode,
690
+ debugAudioScheduling
465
691
  }) => {
466
692
  let __stack = [];
467
693
  try {
468
694
  if (muted) {
469
695
  return;
470
696
  }
471
- audioBufferIterator?.destroy();
697
+ audioBufferIterator?.destroy(sharedAudioContext);
472
698
  const delayHandle = __using(__stack, delayPlaybackHandleIfNotPremounting(), 0);
473
699
  currentDelayHandle = delayHandle;
474
- const iterator = makeAudioIterator(startFromSecond, prewarmedAudioIteratorCache);
700
+ const iterator = makeAudioIterator(startFromSecond, getEndTime(), prewarmedAudioIteratorCache, debugAudioScheduling);
475
701
  audioIteratorsCreated++;
476
702
  audioBufferIterator = iterator;
477
703
  try {
@@ -490,7 +716,8 @@ var audioIteratorManager = ({
490
716
  getIsPlaying,
491
717
  buffer: result.value,
492
718
  playbackRate,
493
- scheduleAudioNode
719
+ scheduleAudioNode,
720
+ debugAudioScheduling
494
721
  });
495
722
  }
496
723
  await iterator.bufferAsFarAsPossible((buffer) => {
@@ -499,7 +726,8 @@ var audioIteratorManager = ({
499
726
  getIsPlaying,
500
727
  buffer,
501
728
  playbackRate,
502
- scheduleAudioNode
729
+ scheduleAudioNode,
730
+ debugAudioScheduling
503
731
  });
504
732
  }
505
733
  }, Math.min(startFromSecond + MAX_BUFFER_AHEAD_SECONDS, getEndTime()));
@@ -526,7 +754,8 @@ var audioIteratorManager = ({
526
754
  nonce,
527
755
  playbackRate,
528
756
  getIsPlaying,
529
- scheduleAudioNode
757
+ scheduleAudioNode,
758
+ debugAudioScheduling
530
759
  }) => {
531
760
  if (muted) {
532
761
  return;
@@ -534,7 +763,8 @@ var audioIteratorManager = ({
534
763
  if (getIsLooping()) {
535
764
  if (getEndTime() - newTime < 1) {
536
765
  prewarmedAudioIteratorCache.prewarmIteratorForLooping({
537
- timeToSeek: getStartTime()
766
+ timeToSeek: getStartTime(),
767
+ maximumTimestamp: getEndTime()
538
768
  });
539
769
  }
540
770
  }
@@ -544,7 +774,8 @@ var audioIteratorManager = ({
544
774
  playbackRate,
545
775
  startFromSecond: newTime,
546
776
  getIsPlaying,
547
- scheduleAudioNode
777
+ scheduleAudioNode,
778
+ debugAudioScheduling
548
779
  });
549
780
  return;
550
781
  }
@@ -557,7 +788,8 @@ var audioIteratorManager = ({
557
788
  getIsPlaying,
558
789
  buffer,
559
790
  playbackRate,
560
- scheduleAudioNode
791
+ scheduleAudioNode,
792
+ debugAudioScheduling
561
793
  });
562
794
  }
563
795
  });
@@ -573,7 +805,8 @@ var audioIteratorManager = ({
573
805
  playbackRate,
574
806
  startFromSecond: newTime,
575
807
  getIsPlaying,
576
- scheduleAudioNode
808
+ scheduleAudioNode,
809
+ debugAudioScheduling
577
810
  });
578
811
  return;
579
812
  }
@@ -585,31 +818,12 @@ var audioIteratorManager = ({
585
818
  getIsPlaying,
586
819
  buffer,
587
820
  playbackRate,
588
- scheduleAudioNode
821
+ scheduleAudioNode,
822
+ debugAudioScheduling
589
823
  });
590
824
  }
591
825
  }, Math.min(newTime + MAX_BUFFER_AHEAD_SECONDS, getEndTime()));
592
826
  };
593
- const resumeScheduledAudioChunks = ({
594
- playbackRate,
595
- scheduleAudioNode
596
- }) => {
597
- if (muted) {
598
- return;
599
- }
600
- if (!audioBufferIterator) {
601
- return;
602
- }
603
- for (const chunk of audioBufferIterator.getAndClearAudioChunksForAfterResuming()) {
604
- scheduleAudioChunk({
605
- buffer: chunk.buffer,
606
- mediaTimestamp: chunk.timestamp,
607
- playbackRate,
608
- scheduleAudioNode,
609
- maxDuration: chunk.maxDuration
610
- });
611
- }
612
- };
613
827
  return {
614
828
  startAudioIterator,
615
829
  resumeScheduledAudioChunks,
@@ -617,7 +831,7 @@ var audioIteratorManager = ({
617
831
  getAudioBufferIterator: () => audioBufferIterator,
618
832
  destroyIterator: () => {
619
833
  prewarmedAudioIteratorCache.destroy();
620
- audioBufferIterator?.destroy();
834
+ audioBufferIterator?.destroy(sharedAudioContext);
621
835
  audioBufferIterator = null;
622
836
  if (currentDelayHandle) {
623
837
  currentDelayHandle.unblock();
@@ -638,16 +852,6 @@ var audioIteratorManager = ({
638
852
  };
639
853
  };
640
854
 
641
- // src/calculate-playbacktime.ts
642
- var calculatePlaybackTime = ({
643
- audioSyncAnchor,
644
- currentTime,
645
- playbackRate
646
- }) => {
647
- const timeSinceAnchor = currentTime - audioSyncAnchor;
648
- return timeSinceAnchor * playbackRate;
649
- };
650
-
651
855
  // src/debug-overlay/preview-overlay.ts
652
856
  var drawPreviewOverlay = ({
653
857
  context,
@@ -659,18 +863,19 @@ var drawPreviewOverlay = ({
659
863
  videoIteratorManager,
660
864
  playbackRate
661
865
  }) => {
866
+ const anchorValue = audioSyncAnchor?.value ?? 0;
662
867
  const lines = [
663
868
  "Debug overlay",
664
869
  `Video iterators created: ${videoIteratorManager?.getVideoIteratorsCreated()}`,
665
870
  `Audio iterators created: ${audioIteratorManager2?.getAudioIteratorsCreated()}`,
666
871
  `Frames rendered: ${videoIteratorManager?.getFramesRendered()}`,
667
872
  `Audio context state: ${audioContextState}`,
668
- audioTime ? `Audio time: ${((audioTime - audioSyncAnchor) * playbackRate).toFixed(3)}s` : null
873
+ audioTime ? `Audio time: ${((audioTime - anchorValue) * playbackRate).toFixed(3)}s` : null
669
874
  ].filter(Boolean);
670
875
  if (audioIteratorManager2) {
671
876
  const queuedPeriod = audioIteratorManager2.getAudioBufferIterator()?.getQueuedPeriod();
672
877
  if (queuedPeriod) {
673
- const aheadText = audioTime ? ` (${(queuedPeriod.until - (audioTime - audioSyncAnchor) * playbackRate).toFixed(3)}s ahead)` : "";
878
+ const aheadText = audioTime ? ` (${(queuedPeriod.until - (audioTime - anchorValue) * playbackRate).toFixed(3)}s ahead)` : "";
674
879
  lines.push(`Audio queued until ${queuedPeriod.until.toFixed(3)}s${aheadText}`);
675
880
  }
676
881
  lines.push(`Playing: ${playing}`);
@@ -720,7 +925,7 @@ var makeNonceManager = () => {
720
925
 
721
926
  // src/video-iterator-manager.ts
722
927
  import { CanvasSink } from "mediabunny";
723
- import { Internals as Internals2 } from "remotion";
928
+ import { Internals as Internals5 } from "remotion";
724
929
 
725
930
  // src/video/video-preview-iterator.ts
726
931
  var createVideoIterator = async (timeToSeek, cache) => {
@@ -890,7 +1095,7 @@ var videoIteratorManager = ({
890
1095
  if (callback) {
891
1096
  callback(frame.canvas);
892
1097
  }
893
- Internals2.Log.trace({ logLevel, tag: "@remotion/media" }, `[MediaPlayer] Drew frame ${frame.timestamp.toFixed(3)}s`);
1098
+ Internals5.Log.trace({ logLevel, tag: "@remotion/media" }, `[MediaPlayer] Drew frame ${frame.timestamp.toFixed(3)}s`);
894
1099
  };
895
1100
  const startVideoIterator = async (timeToSeek, nonce) => {
896
1101
  let __stack = [];
@@ -975,7 +1180,7 @@ class MediaPlayer {
975
1180
  sharedAudioContext;
976
1181
  audioIteratorManager = null;
977
1182
  videoIteratorManager = null;
978
- audioSyncAnchor = 0;
1183
+ sequenceOffset;
979
1184
  playing = false;
980
1185
  loop = false;
981
1186
  fps;
@@ -984,6 +1189,7 @@ class MediaPlayer {
984
1189
  durationInFrames;
985
1190
  totalDuration;
986
1191
  debugOverlay = false;
1192
+ debugAudioScheduling = false;
987
1193
  nonceManager;
988
1194
  onVideoFrameCallback = null;
989
1195
  initializationPromise = null;
@@ -1004,12 +1210,14 @@ class MediaPlayer {
1004
1210
  audioStreamIndex,
1005
1211
  fps,
1006
1212
  debugOverlay,
1213
+ debugAudioScheduling,
1007
1214
  bufferState,
1008
1215
  isPremounting,
1009
1216
  isPostmounting,
1010
1217
  durationInFrames,
1011
1218
  onVideoFrameCallback,
1012
- playing
1219
+ playing,
1220
+ sequenceOffset
1013
1221
  }) {
1014
1222
  this.canvas = canvas ?? null;
1015
1223
  this.src = src;
@@ -1023,6 +1231,7 @@ class MediaPlayer {
1023
1231
  this.audioStreamIndex = audioStreamIndex ?? 0;
1024
1232
  this.fps = fps;
1025
1233
  this.debugOverlay = debugOverlay;
1234
+ this.debugAudioScheduling = debugAudioScheduling;
1026
1235
  this.bufferState = bufferState;
1027
1236
  this.isPremounting = isPremounting;
1028
1237
  this.isPostmounting = isPostmounting;
@@ -1030,6 +1239,7 @@ class MediaPlayer {
1030
1239
  this.nonceManager = makeNonceManager();
1031
1240
  this.onVideoFrameCallback = onVideoFrameCallback;
1032
1241
  this.playing = playing;
1242
+ this.sequenceOffset = sequenceOffset;
1033
1243
  this.input = new Input({
1034
1244
  source: new UrlSource(this.src),
1035
1245
  formats: ALL_FORMATS
@@ -1093,7 +1303,7 @@ class MediaPlayer {
1093
1303
  if (isNetworkError(err)) {
1094
1304
  throw error;
1095
1305
  }
1096
- Internals3.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, `[MediaPlayer] Failed to recognize format for ${this.src}`, error);
1306
+ Internals6.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, `[MediaPlayer] Failed to recognize format for ${this.src}`, error);
1097
1307
  return { type: "unknown-container-format" };
1098
1308
  }
1099
1309
  const [durationInSeconds, videoTrack, audioTracks] = await Promise.all([
@@ -1134,7 +1344,6 @@ class MediaPlayer {
1134
1344
  if (startTime === null) {
1135
1345
  throw new Error(`should have asserted that the time is not null`);
1136
1346
  }
1137
- this.setAudioPlaybackTime(startTime);
1138
1347
  if (audioTrack && this.sharedAudioContext) {
1139
1348
  const canDecode = await audioTrack.canDecode();
1140
1349
  if (!canDecode) {
@@ -1146,7 +1355,7 @@ class MediaPlayer {
1146
1355
  this.audioIteratorManager = audioIteratorManager({
1147
1356
  audioTrack,
1148
1357
  delayPlaybackHandleIfNotPremounting: this.delayPlaybackHandleIfNotPremounting,
1149
- sharedAudioContext: this.sharedAudioContext,
1358
+ sharedAudioContext: this.sharedAudioContext.audioContext,
1150
1359
  getIsLooping: () => this.loop,
1151
1360
  getEndTime: () => this.getEndTime(),
1152
1361
  getStartTime: () => this.getStartTime(),
@@ -1162,7 +1371,8 @@ class MediaPlayer {
1162
1371
  playbackRate: this.playbackRate * this.globalPlaybackRate,
1163
1372
  startFromSecond: startTime,
1164
1373
  getIsPlaying: () => this.playing,
1165
- scheduleAudioNode: this.scheduleAudioNode
1374
+ scheduleAudioNode: this.scheduleAudioNode,
1375
+ debugAudioScheduling: this.debugAudioScheduling
1166
1376
  }) : Promise.resolve(),
1167
1377
  this.videoIteratorManager ? this.videoIteratorManager.startVideoIterator(startTime, nonce) : Promise.resolve()
1168
1378
  ]);
@@ -1170,16 +1380,16 @@ class MediaPlayer {
1170
1380
  if (this.isDisposalError()) {
1171
1381
  return { type: "disposed" };
1172
1382
  }
1173
- Internals3.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, "[MediaPlayer] Failed to start audio and video iterators", error);
1383
+ Internals6.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, "[MediaPlayer] Failed to start audio and video iterators", error);
1174
1384
  }
1175
1385
  return { type: "success", durationInSeconds };
1176
1386
  } catch (error) {
1177
1387
  const err = error;
1178
1388
  if (isNetworkError(err)) {
1179
- Internals3.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, `[MediaPlayer] Network/CORS error for ${this.src}`, err);
1389
+ Internals6.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, `[MediaPlayer] Network/CORS error for ${this.src}`, err);
1180
1390
  return { type: "network-error" };
1181
1391
  }
1182
- Internals3.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, "[MediaPlayer] Failed to initialize", error);
1392
+ Internals6.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, "[MediaPlayer] Failed to initialize", error);
1183
1393
  throw error;
1184
1394
  }
1185
1395
  } catch (_catch) {
@@ -1205,46 +1415,44 @@ class MediaPlayer {
1205
1415
  if (nonce.isStale()) {
1206
1416
  return;
1207
1417
  }
1208
- const shouldSeekAudio = this.audioIteratorManager && this.sharedAudioContext && this.getAudioPlaybackTime() !== newTime;
1209
- if (shouldSeekAudio) {
1210
- this.setAudioPlaybackTime(newTime);
1211
- }
1212
- await Promise.all([
1213
- this.videoIteratorManager?.seek({
1214
- newTime,
1215
- nonce
1216
- }),
1217
- shouldSeekAudio ? this.audioIteratorManager?.seek({
1218
- newTime,
1219
- nonce,
1220
- playbackRate: this.playbackRate * this.globalPlaybackRate,
1221
- getIsPlaying: () => this.playing,
1222
- scheduleAudioNode: this.scheduleAudioNode
1223
- }) : null
1224
- ]);
1225
- }
1226
- async playAudio(time) {
1227
- const newTime = this.getTrimmedTime(time);
1228
- if (newTime === null) {
1229
- throw new Error(`should have asserted that the time is not null`);
1418
+ const shouldSeekAudio = this.audioIteratorManager && this.getAudioPlaybackTime(this.sharedAudioContext?.audioContext.currentTime ?? 0) !== newTime;
1419
+ try {
1420
+ await Promise.all([
1421
+ this.videoIteratorManager?.seek({
1422
+ newTime,
1423
+ nonce
1424
+ }),
1425
+ shouldSeekAudio ? this.audioIteratorManager?.seek({
1426
+ newTime,
1427
+ nonce,
1428
+ playbackRate: this.playbackRate * this.globalPlaybackRate,
1429
+ getIsPlaying: () => this.playing,
1430
+ scheduleAudioNode: this.scheduleAudioNode,
1431
+ debugAudioScheduling: this.debugAudioScheduling
1432
+ }) : null
1433
+ ]);
1434
+ } catch (error) {
1435
+ if (this.isDisposalError()) {
1436
+ return;
1437
+ }
1438
+ throw error;
1230
1439
  }
1231
- this.setAudioPlaybackTime(newTime);
1232
- if (this.audioIteratorManager) {
1440
+ }
1441
+ playAudio() {
1442
+ if (this.audioIteratorManager && this.sharedAudioContext?.audioContext.state === "running" && (this.sharedAudioContext?.audioContext?.getOutputTimestamp().contextTime ?? 0) > 0) {
1233
1443
  this.audioIteratorManager.resumeScheduledAudioChunks({
1234
1444
  playbackRate: this.playbackRate * this.globalPlaybackRate,
1235
- scheduleAudioNode: this.scheduleAudioNode
1445
+ scheduleAudioNode: this.scheduleAudioNode,
1446
+ debugAudioScheduling: this.debugAudioScheduling
1236
1447
  });
1237
1448
  }
1238
- if (this.sharedAudioContext && this.sharedAudioContext.state === "suspended") {
1239
- await this.sharedAudioContext.resume();
1240
- }
1241
1449
  }
1242
- async play(time) {
1450
+ play() {
1451
+ this.playAudio();
1243
1452
  if (this.playing) {
1244
1453
  return;
1245
1454
  }
1246
1455
  this.playing = true;
1247
- await this.playAudio(time);
1248
1456
  this.drawDebugOverlay();
1249
1457
  }
1250
1458
  delayPlaybackHandleIfNotPremounting = () => {
@@ -1299,7 +1507,6 @@ class MediaPlayer {
1299
1507
  const newMediaTime = this.getTrimmedTime(unloopedTimeInSeconds);
1300
1508
  this.audioIteratorManager?.destroyIterator();
1301
1509
  if (newMediaTime !== null) {
1302
- this.setAudioPlaybackTime(newMediaTime);
1303
1510
  if (!this.playing && this.videoIteratorManager) {
1304
1511
  await this.seekToWithQueue(newMediaTime);
1305
1512
  }
@@ -1320,39 +1527,43 @@ class MediaPlayer {
1320
1527
  setDebugOverlay(debugOverlay) {
1321
1528
  this.debugOverlay = debugOverlay;
1322
1529
  }
1323
- updateAudioTimeAfterPlaybackRateChange(mediaTimeBeforeChange) {
1530
+ setDebugAudioScheduling(debugAudioScheduling) {
1531
+ this.debugAudioScheduling = debugAudioScheduling;
1532
+ }
1533
+ rescheduleAudioChunks() {
1324
1534
  if (!this.audioIteratorManager) {
1325
1535
  return;
1326
1536
  }
1327
1537
  if (!this.sharedAudioContext) {
1328
1538
  return;
1329
1539
  }
1330
- this.setAudioPlaybackTime(mediaTimeBeforeChange);
1331
1540
  const iterator = this.audioIteratorManager.getAudioBufferIterator();
1332
1541
  if (!iterator) {
1333
1542
  return;
1334
1543
  }
1335
1544
  iterator.moveQueuedChunksToPauseQueue();
1336
- if (this.playing) {
1545
+ if (this.playing && this.sharedAudioContext.audioContext.state === "running" && (this.sharedAudioContext.audioContext?.getOutputTimestamp().contextTime ?? 0) > 0) {
1337
1546
  this.audioIteratorManager.resumeScheduledAudioChunks({
1338
1547
  playbackRate: this.playbackRate * this.globalPlaybackRate,
1339
- scheduleAudioNode: this.scheduleAudioNode
1548
+ scheduleAudioNode: this.scheduleAudioNode,
1549
+ debugAudioScheduling: this.debugAudioScheduling
1340
1550
  });
1341
1551
  }
1342
1552
  }
1343
1553
  async setPlaybackRate(rate, unloopedTimeInSeconds) {
1344
1554
  const previousRate = this.playbackRate;
1345
- const mediaTime = this.sharedAudioContext ? this.getAudioPlaybackTime() : 0;
1346
- this.playbackRate = rate;
1347
- this.updateAudioTimeAfterPlaybackRateChange(mediaTime);
1348
1555
  if (previousRate !== rate) {
1556
+ this.playbackRate = rate;
1557
+ this.rescheduleAudioChunks();
1349
1558
  await this.seekTo(unloopedTimeInSeconds);
1350
1559
  }
1351
1560
  }
1352
1561
  setGlobalPlaybackRate(rate) {
1353
- const mediaTime = this.sharedAudioContext ? this.getAudioPlaybackTime() : 0;
1354
- this.globalPlaybackRate = rate;
1355
- this.updateAudioTimeAfterPlaybackRateChange(mediaTime);
1562
+ const previousRate = this.globalPlaybackRate;
1563
+ if (previousRate !== rate) {
1564
+ this.globalPlaybackRate = rate;
1565
+ this.rescheduleAudioChunks();
1566
+ }
1356
1567
  }
1357
1568
  setFps(fps) {
1358
1569
  this.fps = fps;
@@ -1366,6 +1577,9 @@ class MediaPlayer {
1366
1577
  setLoop(loop) {
1367
1578
  this.loop = loop;
1368
1579
  }
1580
+ setSequenceOffset(offset) {
1581
+ this.sequenceOffset = offset;
1582
+ }
1369
1583
  setDurationInFrames(durationInFrames) {
1370
1584
  this.durationInFrames = durationInFrames;
1371
1585
  }
@@ -1380,41 +1594,40 @@ class MediaPlayer {
1380
1594
  this.audioIteratorManager?.destroyIterator();
1381
1595
  this.input.dispose();
1382
1596
  }
1383
- scheduleAudioNode = (node, mediaTimestamp, maxDuration) => {
1384
- const currentTime = this.getAudioPlaybackTime();
1385
- const delayWithoutPlaybackRate = mediaTimestamp - currentTime;
1386
- const delay = delayWithoutPlaybackRate / (this.playbackRate * this.globalPlaybackRate);
1597
+ scheduleAudioNode = (node, mediaTimestamp) => {
1387
1598
  if (!this.sharedAudioContext) {
1388
1599
  throw new Error("Shared audio context not found");
1389
1600
  }
1390
- if (delay >= 0) {
1391
- node.start(this.sharedAudioContext.currentTime + delay, 0, maxDuration ?? undefined);
1392
- } else {
1393
- const offset = -delayWithoutPlaybackRate;
1394
- node.start(this.sharedAudioContext.currentTime, offset, maxDuration !== null ? maxDuration - offset : undefined);
1395
- }
1601
+ const { audioContext } = this.sharedAudioContext;
1602
+ const { currentTime } = audioContext;
1603
+ const globalTime = (currentTime - this.sharedAudioContext.audioSyncAnchor.value) * this.globalPlaybackRate;
1604
+ const timeInSeconds = globalTime - this.sequenceOffset;
1605
+ const localTime = this.getTrimmedTime(timeInSeconds);
1606
+ if (localTime === null) {
1607
+ throw new Error("hmm, should not render!");
1608
+ }
1609
+ const targetTime = (mediaTimestamp - localTime) / (this.playbackRate * this.globalPlaybackRate);
1610
+ return this.sharedAudioContext.scheduleAudioNode({
1611
+ node,
1612
+ mediaTimestamp,
1613
+ targetTime,
1614
+ currentTime,
1615
+ sequenceEndTime: this.getEndTime(),
1616
+ sequenceStartTime: this.getStartTime(),
1617
+ debugAudioScheduling: this.debugAudioScheduling
1618
+ });
1396
1619
  };
1397
- getAudioPlaybackTime() {
1620
+ getAudioPlaybackTime(currentTime) {
1398
1621
  if (!this.sharedAudioContext) {
1399
1622
  throw new Error("Shared audio context not found");
1400
1623
  }
1401
- return calculatePlaybackTime({
1402
- audioSyncAnchor: this.audioSyncAnchor,
1403
- currentTime: this.sharedAudioContext.currentTime,
1404
- playbackRate: this.playbackRate * this.globalPlaybackRate
1405
- });
1406
- }
1407
- setAudioPlaybackTime(time) {
1408
- if (!this.sharedAudioContext) {
1409
- return;
1624
+ const globalTime = (currentTime - this.sharedAudioContext.audioSyncAnchor.value) * this.globalPlaybackRate;
1625
+ const localTime = globalTime - this.sequenceOffset;
1626
+ const trimmedTime = this.getTrimmedTime(localTime);
1627
+ if (trimmedTime !== null) {
1628
+ return trimmedTime;
1410
1629
  }
1411
- const playbackRate = this.playbackRate * this.globalPlaybackRate;
1412
- const newAnchor = this.sharedAudioContext.currentTime - time / playbackRate;
1413
- const shift = Math.abs(newAnchor - this.audioSyncAnchor) * playbackRate;
1414
- if (shift < 0.05) {
1415
- return;
1416
- }
1417
- this.audioSyncAnchor = newAnchor;
1630
+ return localTime * this.playbackRate + (this.trimBefore ?? 0) / this.fps;
1418
1631
  }
1419
1632
  setVideoFrameCallback(callback) {
1420
1633
  this.onVideoFrameCallback = callback;
@@ -1425,9 +1638,9 @@ class MediaPlayer {
1425
1638
  if (this.context && this.canvas) {
1426
1639
  drawPreviewOverlay({
1427
1640
  context: this.context,
1428
- audioTime: this.sharedAudioContext?.currentTime ?? null,
1429
- audioContextState: this.sharedAudioContext?.state ?? null,
1430
- audioSyncAnchor: this.audioSyncAnchor,
1641
+ audioTime: this.sharedAudioContext?.audioContext.currentTime ?? null,
1642
+ audioContextState: this.sharedAudioContext?.audioContext.state ?? null,
1643
+ audioSyncAnchor: this.sharedAudioContext?.audioSyncAnchor ?? null,
1431
1644
  audioIteratorManager: this.audioIteratorManager,
1432
1645
  playing: this.playing,
1433
1646
  videoIteratorManager: this.videoIteratorManager,
@@ -1460,7 +1673,7 @@ var callOnErrorAndResolve = ({
1460
1673
 
1461
1674
  // src/show-in-timeline.ts
1462
1675
  import { useMemo } from "react";
1463
- import { Internals as Internals4, useVideoConfig } from "remotion";
1676
+ import { Internals as Internals7, useVideoConfig } from "remotion";
1464
1677
  var useLoopDisplay = ({
1465
1678
  loop,
1466
1679
  mediaDurationInSeconds,
@@ -1473,7 +1686,7 @@ var useLoopDisplay = ({
1473
1686
  if (!loop || !mediaDurationInSeconds) {
1474
1687
  return;
1475
1688
  }
1476
- const durationInFrames = Internals4.calculateMediaDuration({
1689
+ const durationInFrames = Internals7.calculateMediaDuration({
1477
1690
  mediaDurationInFrames: mediaDurationInSeconds * fps,
1478
1691
  playbackRate,
1479
1692
  trimAfter,
@@ -1497,9 +1710,177 @@ var useLoopDisplay = ({
1497
1710
  return loopDisplay;
1498
1711
  };
1499
1712
 
1713
+ // src/use-common-effects.ts
1714
+ import { useContext, useLayoutEffect } from "react";
1715
+ import { Internals as Internals8 } from "remotion";
1716
+ var useCommonEffects = ({
1717
+ mediaPlayerRef,
1718
+ mediaPlayerReady,
1719
+ currentTimeRef,
1720
+ playing,
1721
+ isPlayerBuffering,
1722
+ frame,
1723
+ trimBefore,
1724
+ trimAfter,
1725
+ effectiveMuted,
1726
+ userPreferredVolume,
1727
+ playbackRate,
1728
+ globalPlaybackRate,
1729
+ fps,
1730
+ sequenceOffset,
1731
+ loop,
1732
+ debugAudioScheduling,
1733
+ durationInFrames,
1734
+ isPremounting,
1735
+ isPostmounting,
1736
+ currentTime,
1737
+ logLevel,
1738
+ sharedAudioContext,
1739
+ label
1740
+ }) => {
1741
+ const absoluteTime = Internals8.useAbsoluteTimelinePosition();
1742
+ const { playing: playingWhilePremounting } = useContext(Internals8.PremountContext);
1743
+ useLayoutEffect(() => {
1744
+ if (sharedAudioContext?.audioContext && sharedAudioContext.audioSyncAnchor) {
1745
+ setGlobalTimeAnchor({
1746
+ audioContext: sharedAudioContext.audioContext,
1747
+ audioSyncAnchor: sharedAudioContext.audioSyncAnchor,
1748
+ absoluteTimeInSeconds: absoluteTime / fps,
1749
+ globalPlaybackRate,
1750
+ debugAudioScheduling,
1751
+ logLevel
1752
+ });
1753
+ }
1754
+ }, [
1755
+ absoluteTime,
1756
+ globalPlaybackRate,
1757
+ sharedAudioContext,
1758
+ fps,
1759
+ debugAudioScheduling,
1760
+ logLevel
1761
+ ]);
1762
+ if (playingWhilePremounting) {
1763
+ mediaPlayerRef.current?.playAudio();
1764
+ }
1765
+ useLayoutEffect(() => {
1766
+ const mediaPlayer = mediaPlayerRef.current;
1767
+ if (!mediaPlayer)
1768
+ return;
1769
+ if (playing && !isPlayerBuffering) {
1770
+ mediaPlayer.play();
1771
+ } else {
1772
+ mediaPlayer.pause();
1773
+ }
1774
+ }, [
1775
+ isPlayerBuffering,
1776
+ playing,
1777
+ logLevel,
1778
+ mediaPlayerReady,
1779
+ frame,
1780
+ mediaPlayerRef
1781
+ ]);
1782
+ useLayoutEffect(() => {
1783
+ const mediaPlayer = mediaPlayerRef.current;
1784
+ if (!mediaPlayer || !mediaPlayerReady) {
1785
+ return;
1786
+ }
1787
+ mediaPlayer.setTrimBefore(trimBefore, currentTimeRef.current);
1788
+ }, [trimBefore, mediaPlayerReady, mediaPlayerRef, currentTimeRef]);
1789
+ useLayoutEffect(() => {
1790
+ const mediaPlayer = mediaPlayerRef.current;
1791
+ if (!mediaPlayer || !mediaPlayerReady) {
1792
+ return;
1793
+ }
1794
+ mediaPlayer.setTrimAfter(trimAfter, currentTimeRef.current);
1795
+ }, [trimAfter, mediaPlayerReady, mediaPlayerRef, currentTimeRef]);
1796
+ useLayoutEffect(() => {
1797
+ const mediaPlayer = mediaPlayerRef.current;
1798
+ if (!mediaPlayer || !mediaPlayerReady)
1799
+ return;
1800
+ mediaPlayer.setMuted(effectiveMuted);
1801
+ }, [effectiveMuted, mediaPlayerReady, mediaPlayerRef]);
1802
+ useLayoutEffect(() => {
1803
+ const mediaPlayer = mediaPlayerRef.current;
1804
+ if (!mediaPlayer || !mediaPlayerReady) {
1805
+ return;
1806
+ }
1807
+ mediaPlayer.setVolume(userPreferredVolume);
1808
+ }, [userPreferredVolume, mediaPlayerReady, mediaPlayerRef]);
1809
+ useLayoutEffect(() => {
1810
+ const mediaPlayer = mediaPlayerRef.current;
1811
+ if (!mediaPlayer || !mediaPlayerReady) {
1812
+ return;
1813
+ }
1814
+ mediaPlayer.setPlaybackRate(playbackRate, currentTimeRef.current);
1815
+ }, [playbackRate, mediaPlayerReady, mediaPlayerRef, currentTimeRef]);
1816
+ useLayoutEffect(() => {
1817
+ const mediaPlayer = mediaPlayerRef.current;
1818
+ if (!mediaPlayer || !mediaPlayerReady) {
1819
+ return;
1820
+ }
1821
+ mediaPlayer.setGlobalPlaybackRate(globalPlaybackRate);
1822
+ }, [globalPlaybackRate, mediaPlayerReady, mediaPlayerRef]);
1823
+ useLayoutEffect(() => {
1824
+ const mediaPlayer = mediaPlayerRef.current;
1825
+ if (!mediaPlayer || !mediaPlayerReady) {
1826
+ return;
1827
+ }
1828
+ mediaPlayer.setLoop(loop);
1829
+ }, [loop, mediaPlayerReady, mediaPlayerRef]);
1830
+ useLayoutEffect(() => {
1831
+ const mediaPlayer = mediaPlayerRef.current;
1832
+ if (!mediaPlayer || !mediaPlayerReady) {
1833
+ return;
1834
+ }
1835
+ mediaPlayer.setDurationInFrames(durationInFrames);
1836
+ }, [durationInFrames, mediaPlayerReady, mediaPlayerRef]);
1837
+ useLayoutEffect(() => {
1838
+ const mediaPlayer = mediaPlayerRef.current;
1839
+ if (!mediaPlayer || !mediaPlayerReady) {
1840
+ return;
1841
+ }
1842
+ mediaPlayer.setIsPremounting(isPremounting);
1843
+ }, [isPremounting, mediaPlayerReady, mediaPlayerRef]);
1844
+ useLayoutEffect(() => {
1845
+ const mediaPlayer = mediaPlayerRef.current;
1846
+ if (!mediaPlayer || !mediaPlayerReady) {
1847
+ return;
1848
+ }
1849
+ mediaPlayer.setIsPostmounting(isPostmounting);
1850
+ }, [isPostmounting, mediaPlayerReady, mediaPlayerRef]);
1851
+ useLayoutEffect(() => {
1852
+ const mediaPlayer = mediaPlayerRef.current;
1853
+ if (!mediaPlayer || !mediaPlayerReady) {
1854
+ return;
1855
+ }
1856
+ mediaPlayer.setFps(fps);
1857
+ }, [fps, mediaPlayerReady, mediaPlayerRef]);
1858
+ useLayoutEffect(() => {
1859
+ const mediaPlayer = mediaPlayerRef.current;
1860
+ if (!mediaPlayer || !mediaPlayerReady) {
1861
+ return;
1862
+ }
1863
+ mediaPlayer.setSequenceOffset(sequenceOffset);
1864
+ }, [sequenceOffset, mediaPlayerReady, mediaPlayerRef]);
1865
+ useLayoutEffect(() => {
1866
+ const mediaPlayer = mediaPlayerRef.current;
1867
+ if (!mediaPlayer || !mediaPlayerReady) {
1868
+ return;
1869
+ }
1870
+ mediaPlayer.setDebugAudioScheduling(debugAudioScheduling);
1871
+ }, [debugAudioScheduling, mediaPlayerReady, mediaPlayerRef]);
1872
+ useLayoutEffect(() => {
1873
+ const mediaPlayer = mediaPlayerRef.current;
1874
+ if (!mediaPlayer || !mediaPlayerReady)
1875
+ return;
1876
+ mediaPlayer.seekTo(currentTime).catch(() => {});
1877
+ Internals8.Log.trace({ logLevel, tag: "@remotion/media" }, `[${label}] Updating target time to ${currentTime.toFixed(3)}s`);
1878
+ }, [currentTime, logLevel, mediaPlayerReady, label, mediaPlayerRef]);
1879
+ };
1880
+
1500
1881
  // src/use-media-in-timeline.ts
1501
- import { useContext, useEffect, useState } from "react";
1502
- import { Internals as Internals5, useCurrentFrame } from "remotion";
1882
+ import { useContext as useContext2, useEffect, useState } from "react";
1883
+ import { Internals as Internals9, useCurrentFrame } from "remotion";
1503
1884
  var useMediaInTimeline = ({
1504
1885
  volume,
1505
1886
  mediaVolume,
@@ -1516,9 +1897,9 @@ var useMediaInTimeline = ({
1516
1897
  trimAfter,
1517
1898
  controls
1518
1899
  }) => {
1519
- const parentSequence = useContext(Internals5.SequenceContext);
1520
- const startsAt = Internals5.useMediaStartsAt();
1521
- const { registerSequence, unregisterSequence } = useContext(Internals5.SequenceManager);
1900
+ const parentSequence = useContext2(Internals9.SequenceContext);
1901
+ const startsAt = Internals9.useMediaStartsAt();
1902
+ const { registerSequence, unregisterSequence } = useContext2(Internals9.SequenceManager);
1522
1903
  const [sequenceId] = useState(() => String(Math.random()));
1523
1904
  const [mediaId] = useState(() => String(Math.random()));
1524
1905
  const frame = useCurrentFrame();
@@ -1530,7 +1911,7 @@ var useMediaInTimeline = ({
1530
1911
  rootId,
1531
1912
  isStudio,
1532
1913
  finalDisplayName
1533
- } = Internals5.useBasicMediaInTimeline({
1914
+ } = Internals9.useBasicMediaInTimeline({
1534
1915
  volume,
1535
1916
  mediaVolume,
1536
1917
  mediaType,
@@ -1640,7 +2021,7 @@ var {
1640
2021
  warnAboutTooHighVolume,
1641
2022
  usePreload,
1642
2023
  SequenceContext
1643
- } = Internals6;
2024
+ } = Internals10;
1644
2025
  var AudioForPreviewAssertedShowing = ({
1645
2026
  src,
1646
2027
  playbackRate,
@@ -1658,6 +2039,7 @@ var AudioForPreviewAssertedShowing = ({
1658
2039
  toneFrequency,
1659
2040
  audioStreamIndex,
1660
2041
  fallbackHtml5AudioProps,
2042
+ debugAudioScheduling,
1661
2043
  onError,
1662
2044
  controls
1663
2045
  }) => {
@@ -1669,9 +2051,9 @@ var AudioForPreviewAssertedShowing = ({
1669
2051
  const [mediaPlayerReady, setMediaPlayerReady] = useState2(false);
1670
2052
  const [shouldFallbackToNativeAudio, setShouldFallbackToNativeAudio] = useState2(false);
1671
2053
  const [playing] = Timeline.usePlayingState();
1672
- const timelineContext = useContext2(Internals6.TimelineContext);
2054
+ const timelineContext = useContext3(Internals10.TimelineContext);
1673
2055
  const globalPlaybackRate = timelineContext.playbackRate;
1674
- const sharedAudioContext = useContext2(SharedAudioContext);
2056
+ const sharedAudioContext = useContext3(SharedAudioContext);
1675
2057
  const buffer = useBufferState();
1676
2058
  const [mediaMuted] = useMediaMutedState();
1677
2059
  const [mediaVolume] = useMediaVolumeState();
@@ -1693,9 +2075,10 @@ var AudioForPreviewAssertedShowing = ({
1693
2075
  const currentTimeRef = useRef(currentTime);
1694
2076
  currentTimeRef.current = currentTime;
1695
2077
  const preloadedSrc = usePreload(src);
1696
- const parentSequence = useContext2(SequenceContext);
2078
+ const parentSequence = useContext3(SequenceContext);
1697
2079
  const isPremounting = Boolean(parentSequence?.premounting);
1698
2080
  const isPostmounting = Boolean(parentSequence?.postmounting);
2081
+ const sequenceOffset = ((parentSequence?.cumulatedFrom ?? 0) + (parentSequence?.relativeFrom ?? 0)) / videoConfig.fps;
1699
2082
  const loopDisplay = useLoopDisplay({
1700
2083
  loop,
1701
2084
  mediaDurationInSeconds,
@@ -1719,28 +2102,55 @@ var AudioForPreviewAssertedShowing = ({
1719
2102
  trimBefore,
1720
2103
  controls
1721
2104
  });
1722
- const bufferingContext = useContext2(Internals6.BufferingContextReact);
2105
+ const bufferingContext = useContext3(Internals10.BufferingContextReact);
1723
2106
  if (!bufferingContext) {
1724
2107
  throw new Error("useMediaPlayback must be used inside a <BufferingContext>");
1725
2108
  }
1726
2109
  const effectiveMuted = muted || mediaMuted || userPreferredVolume <= 0;
1727
- const isPlayerBuffering = Internals6.useIsPlayerBuffering(bufferingContext);
2110
+ const isPlayerBuffering = Internals10.useIsPlayerBuffering(bufferingContext);
1728
2111
  const initialPlaying = useRef(playing && !isPlayerBuffering);
1729
2112
  const initialIsPremounting = useRef(isPremounting);
1730
2113
  const initialIsPostmounting = useRef(isPostmounting);
1731
2114
  const initialGlobalPlaybackRate = useRef(globalPlaybackRate);
1732
2115
  const initialPlaybackRate = useRef(playbackRate);
1733
2116
  const initialMuted = useRef(effectiveMuted);
2117
+ const initialSequenceOffset = useRef(sequenceOffset);
2118
+ useCommonEffects({
2119
+ mediaPlayerRef,
2120
+ mediaPlayerReady,
2121
+ currentTimeRef,
2122
+ playing,
2123
+ isPlayerBuffering,
2124
+ frame,
2125
+ trimBefore,
2126
+ trimAfter,
2127
+ effectiveMuted,
2128
+ userPreferredVolume,
2129
+ playbackRate,
2130
+ globalPlaybackRate,
2131
+ fps: videoConfig.fps,
2132
+ sequenceOffset,
2133
+ loop,
2134
+ debugAudioScheduling,
2135
+ durationInFrames: videoConfig.durationInFrames,
2136
+ isPremounting,
2137
+ isPostmounting,
2138
+ currentTime,
2139
+ logLevel,
2140
+ sharedAudioContext,
2141
+ label: "AudioForPreview"
2142
+ });
1734
2143
  useEffect2(() => {
1735
2144
  if (!sharedAudioContext)
1736
2145
  return;
1737
2146
  if (!sharedAudioContext.audioContext)
1738
2147
  return;
2148
+ const { audioContext, audioSyncAnchor, scheduleAudioNode } = sharedAudioContext;
1739
2149
  try {
1740
2150
  const player = new MediaPlayer({
1741
2151
  src: preloadedSrc,
1742
2152
  logLevel,
1743
- sharedAudioContext: sharedAudioContext.audioContext,
2153
+ sharedAudioContext: { audioContext, audioSyncAnchor, scheduleAudioNode },
1744
2154
  loop,
1745
2155
  trimAfter: initialTrimAfterRef.current,
1746
2156
  trimBefore: initialTrimBeforeRef.current,
@@ -1749,13 +2159,15 @@ var AudioForPreviewAssertedShowing = ({
1749
2159
  playbackRate: initialPlaybackRate.current,
1750
2160
  audioStreamIndex: audioStreamIndex ?? 0,
1751
2161
  debugOverlay: false,
2162
+ debugAudioScheduling,
1752
2163
  bufferState: buffer,
1753
2164
  isPostmounting: initialIsPostmounting.current,
1754
2165
  isPremounting: initialIsPremounting.current,
1755
2166
  globalPlaybackRate: initialGlobalPlaybackRate.current,
1756
2167
  durationInFrames: videoConfig.durationInFrames,
1757
2168
  onVideoFrameCallback: null,
1758
- playing: initialPlaying.current
2169
+ playing: initialPlaying.current,
2170
+ sequenceOffset: initialSequenceOffset.current
1759
2171
  });
1760
2172
  mediaPlayerRef.current = player;
1761
2173
  player.initialize(currentTimeRef.current, initialMuted.current).then((result) => {
@@ -1773,7 +2185,7 @@ var AudioForPreviewAssertedShowing = ({
1773
2185
  if (action === "fail") {
1774
2186
  throw errorToUse;
1775
2187
  } else {
1776
- Internals6.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
2188
+ Internals10.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
1777
2189
  setShouldFallbackToNativeAudio(true);
1778
2190
  }
1779
2191
  };
@@ -1796,7 +2208,7 @@ var AudioForPreviewAssertedShowing = ({
1796
2208
  if (result.type === "success") {
1797
2209
  setMediaPlayerReady(true);
1798
2210
  setMediaDurationInSeconds(result.durationInSeconds);
1799
- Internals6.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] MediaPlayer initialized successfully`);
2211
+ Internals10.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] MediaPlayer initialized successfully`);
1800
2212
  }
1801
2213
  }).catch((error) => {
1802
2214
  const [action, errorToUse] = callOnErrorAndResolve({
@@ -1809,7 +2221,7 @@ var AudioForPreviewAssertedShowing = ({
1809
2221
  if (action === "fail") {
1810
2222
  throw errorToUse;
1811
2223
  } else {
1812
- Internals6.Log.error({ logLevel, tag: "@remotion/media" }, "[AudioForPreview] Failed to initialize MediaPlayer", error);
2224
+ Internals10.Log.error({ logLevel, tag: "@remotion/media" }, "[AudioForPreview] Failed to initialize MediaPlayer", error);
1813
2225
  setShouldFallbackToNativeAudio(true);
1814
2226
  }
1815
2227
  });
@@ -1824,12 +2236,12 @@ var AudioForPreviewAssertedShowing = ({
1824
2236
  if (action === "fail") {
1825
2237
  throw errorToUse;
1826
2238
  }
1827
- Internals6.Log.error({ logLevel, tag: "@remotion/media" }, "[AudioForPreview] MediaPlayer initialization failed", errorToUse);
2239
+ Internals10.Log.error({ logLevel, tag: "@remotion/media" }, "[AudioForPreview] MediaPlayer initialization failed", errorToUse);
1828
2240
  setShouldFallbackToNativeAudio(true);
1829
2241
  }
1830
2242
  return () => {
1831
2243
  if (mediaPlayerRef.current) {
1832
- Internals6.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] Disposing MediaPlayer`);
2244
+ Internals10.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] Disposing MediaPlayer`);
1833
2245
  mediaPlayerRef.current.dispose();
1834
2246
  mediaPlayerRef.current = null;
1835
2247
  }
@@ -1840,108 +2252,15 @@ var AudioForPreviewAssertedShowing = ({
1840
2252
  preloadedSrc,
1841
2253
  logLevel,
1842
2254
  sharedAudioContext,
1843
- currentTimeRef,
1844
2255
  loop,
1845
2256
  videoConfig.fps,
1846
2257
  audioStreamIndex,
1847
2258
  disallowFallbackToHtml5Audio,
2259
+ debugAudioScheduling,
1848
2260
  buffer,
1849
2261
  onError,
1850
2262
  videoConfig.durationInFrames
1851
2263
  ]);
1852
- useLayoutEffect(() => {
1853
- const audioPlayer = mediaPlayerRef.current;
1854
- if (!audioPlayer)
1855
- return;
1856
- if (playing && !isPlayerBuffering) {
1857
- audioPlayer.play(currentTimeRef.current);
1858
- } else {
1859
- audioPlayer.pause();
1860
- }
1861
- }, [isPlayerBuffering, logLevel, playing]);
1862
- useLayoutEffect(() => {
1863
- const mediaPlayer = mediaPlayerRef.current;
1864
- if (!mediaPlayer || !mediaPlayerReady) {
1865
- return;
1866
- }
1867
- mediaPlayer.setTrimBefore(trimBefore, currentTimeRef.current);
1868
- }, [trimBefore, mediaPlayerReady]);
1869
- useLayoutEffect(() => {
1870
- const mediaPlayer = mediaPlayerRef.current;
1871
- if (!mediaPlayer || !mediaPlayerReady) {
1872
- return;
1873
- }
1874
- mediaPlayer.setTrimAfter(trimAfter, currentTimeRef.current);
1875
- }, [trimAfter, mediaPlayerReady]);
1876
- useLayoutEffect(() => {
1877
- const audioPlayer = mediaPlayerRef.current;
1878
- if (!audioPlayer || !mediaPlayerReady)
1879
- return;
1880
- audioPlayer.setMuted(effectiveMuted);
1881
- }, [effectiveMuted, mediaPlayerReady]);
1882
- useEffect2(() => {
1883
- const audioPlayer = mediaPlayerRef.current;
1884
- if (!audioPlayer || !mediaPlayerReady) {
1885
- return;
1886
- }
1887
- audioPlayer.setVolume(userPreferredVolume);
1888
- }, [userPreferredVolume, mediaPlayerReady]);
1889
- useEffect2(() => {
1890
- const audioPlayer = mediaPlayerRef.current;
1891
- if (!audioPlayer || !mediaPlayerReady) {
1892
- return;
1893
- }
1894
- audioPlayer.setPlaybackRate(playbackRate, currentTimeRef.current);
1895
- }, [playbackRate, mediaPlayerReady]);
1896
- useLayoutEffect(() => {
1897
- const audioPlayer = mediaPlayerRef.current;
1898
- if (!audioPlayer || !mediaPlayerReady) {
1899
- return;
1900
- }
1901
- audioPlayer.setGlobalPlaybackRate(globalPlaybackRate);
1902
- }, [globalPlaybackRate, mediaPlayerReady]);
1903
- useLayoutEffect(() => {
1904
- const audioPlayer = mediaPlayerRef.current;
1905
- if (!audioPlayer || !mediaPlayerReady) {
1906
- return;
1907
- }
1908
- audioPlayer.setFps(videoConfig.fps);
1909
- }, [videoConfig.fps, mediaPlayerReady]);
1910
- useLayoutEffect(() => {
1911
- const mediaPlayer = mediaPlayerRef.current;
1912
- if (!mediaPlayer || !mediaPlayerReady) {
1913
- return;
1914
- }
1915
- mediaPlayer.setLoop(loop);
1916
- }, [loop, mediaPlayerReady]);
1917
- useLayoutEffect(() => {
1918
- const mediaPlayer = mediaPlayerRef.current;
1919
- if (!mediaPlayer || !mediaPlayerReady) {
1920
- return;
1921
- }
1922
- mediaPlayer.setDurationInFrames(videoConfig.durationInFrames);
1923
- }, [videoConfig.durationInFrames, mediaPlayerReady]);
1924
- useLayoutEffect(() => {
1925
- const mediaPlayer = mediaPlayerRef.current;
1926
- if (!mediaPlayer || !mediaPlayerReady) {
1927
- return;
1928
- }
1929
- mediaPlayer.setIsPremounting(isPremounting);
1930
- }, [isPremounting, mediaPlayerReady]);
1931
- useLayoutEffect(() => {
1932
- const mediaPlayer = mediaPlayerRef.current;
1933
- if (!mediaPlayer || !mediaPlayerReady) {
1934
- return;
1935
- }
1936
- mediaPlayer.setIsPostmounting(isPostmounting);
1937
- }, [isPostmounting, mediaPlayerReady]);
1938
- useLayoutEffect(() => {
1939
- const audioPlayer = mediaPlayerRef.current;
1940
- if (!audioPlayer || !mediaPlayerReady)
1941
- return;
1942
- audioPlayer.seekTo(currentTime).catch(() => {});
1943
- Internals6.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] Updating target time to ${currentTime.toFixed(3)}s`);
1944
- }, [currentTime, logLevel, mediaPlayerReady]);
1945
2264
  if (shouldFallbackToNativeAudio && !disallowFallbackToHtml5Audio) {
1946
2265
  return /* @__PURE__ */ jsx(RemotionAudio, {
1947
2266
  src,
@@ -1975,61 +2294,54 @@ var audioSchema = {
1975
2294
  },
1976
2295
  playbackRate: {
1977
2296
  type: "number",
1978
- min: 0,
2297
+ min: 0.1,
1979
2298
  step: 0.01,
1980
2299
  default: 1,
1981
2300
  description: "Playback Rate"
1982
2301
  },
1983
- trimBefore: { type: "number", min: 0, default: 0 },
1984
- trimAfter: { type: "number", min: 0, default: 0 }
2302
+ loop: { type: "boolean", default: false, description: "Loop" }
1985
2303
  };
1986
2304
  var AudioForPreview = ({
1987
- loop,
2305
+ loop: loopProp = false,
1988
2306
  src,
1989
2307
  logLevel,
1990
2308
  muted,
1991
2309
  name,
1992
2310
  volume: volumeProp,
1993
2311
  loopVolumeCurveBehavior,
1994
- playbackRate: playbackRateProp,
1995
- trimAfter: trimAfterProp,
1996
- trimBefore: trimBeforeProp,
2312
+ playbackRate: playbackRateProp = 1,
2313
+ trimAfter,
2314
+ trimBefore,
1997
2315
  showInTimeline,
1998
2316
  stack,
1999
2317
  disallowFallbackToHtml5Audio,
2000
2318
  toneFrequency,
2001
2319
  audioStreamIndex,
2002
2320
  fallbackHtml5AudioProps,
2321
+ debugAudioScheduling,
2003
2322
  onError
2004
2323
  }) => {
2005
2324
  const schemaInput = useMemo2(() => {
2006
- if (typeof volumeProp !== "number") {
2007
- return null;
2008
- }
2009
2325
  return {
2010
2326
  volume: volumeProp,
2011
2327
  playbackRate: playbackRateProp,
2012
- trimBefore: trimBeforeProp,
2013
- trimAfter: trimAfterProp,
2014
- loop: loop ?? false
2328
+ loop: loopProp
2015
2329
  };
2016
- }, [volumeProp, playbackRateProp, trimBeforeProp, trimAfterProp, loop]);
2017
- const { controls, values } = Internals6.useSchema(schemaInput ? audioSchema : null, schemaInput);
2018
- const volume = schemaInput !== null ? values.volume : volumeProp;
2019
- const playbackRate = schemaInput !== null ? values.playbackRate : playbackRateProp;
2020
- const trimBefore = schemaInput !== null ? values.trimBefore : trimBeforeProp;
2021
- const trimAfter = schemaInput !== null ? values.trimAfter : trimAfterProp;
2022
- const effectiveLoop = schemaInput !== null ? values.loop : loop ?? false;
2330
+ }, [volumeProp, playbackRateProp, loopProp]);
2331
+ const {
2332
+ controls,
2333
+ values: { volume, playbackRate, loop }
2334
+ } = Internals10.useSchema(audioSchema, schemaInput);
2023
2335
  const preloadedSrc = usePreload(src);
2024
- const defaultLogLevel = Internals6.useLogLevel();
2336
+ const defaultLogLevel = Internals10.useLogLevel();
2025
2337
  const frame = useCurrentFrame2();
2026
2338
  const videoConfig = useVideoConfig2();
2027
2339
  const currentTime = frame / videoConfig.fps;
2028
2340
  const showShow = useMemo2(() => {
2029
2341
  return getTimeInSeconds({
2030
2342
  unloopedTimeInSeconds: currentTime,
2031
- playbackRate: playbackRate ?? 1,
2032
- loop: effectiveLoop,
2343
+ playbackRate,
2344
+ loop,
2033
2345
  trimBefore,
2034
2346
  trimAfter,
2035
2347
  mediaDurationInSeconds: Infinity,
@@ -2039,12 +2351,12 @@ var AudioForPreview = ({
2039
2351
  }) !== null;
2040
2352
  }, [
2041
2353
  currentTime,
2042
- effectiveLoop,
2043
2354
  playbackRate,
2044
2355
  src,
2045
2356
  trimAfter,
2046
2357
  trimBefore,
2047
- videoConfig.fps
2358
+ videoConfig.fps,
2359
+ loop
2048
2360
  ]);
2049
2361
  if (!showShow) {
2050
2362
  return null;
@@ -2052,12 +2364,12 @@ var AudioForPreview = ({
2052
2364
  return /* @__PURE__ */ jsx(AudioForPreviewAssertedShowing, {
2053
2365
  audioStreamIndex: audioStreamIndex ?? 0,
2054
2366
  src: preloadedSrc,
2055
- playbackRate: playbackRate ?? 1,
2367
+ playbackRate,
2056
2368
  logLevel: logLevel ?? defaultLogLevel,
2057
2369
  muted: muted ?? false,
2058
2370
  volume: volume ?? 1,
2059
2371
  loopVolumeCurveBehavior: loopVolumeCurveBehavior ?? "repeat",
2060
- loop: effectiveLoop,
2372
+ loop,
2061
2373
  trimAfter,
2062
2374
  trimBefore,
2063
2375
  name,
@@ -2065,6 +2377,7 @@ var AudioForPreview = ({
2065
2377
  stack,
2066
2378
  disallowFallbackToHtml5Audio: disallowFallbackToHtml5Audio ?? false,
2067
2379
  toneFrequency,
2380
+ debugAudioScheduling: debugAudioScheduling ?? false,
2068
2381
  onError,
2069
2382
  fallbackHtml5AudioProps,
2070
2383
  controls
@@ -2072,11 +2385,11 @@ var AudioForPreview = ({
2072
2385
  };
2073
2386
 
2074
2387
  // src/audio/audio-for-rendering.tsx
2075
- import { useContext as useContext3, useLayoutEffect as useLayoutEffect2, useMemo as useMemo3, useState as useState3 } from "react";
2388
+ import { useContext as useContext4, useLayoutEffect as useLayoutEffect2, useMemo as useMemo3, useState as useState3 } from "react";
2076
2389
  import {
2077
2390
  cancelRender as cancelRender2,
2078
2391
  Html5Audio,
2079
- Internals as Internals14,
2392
+ Internals as Internals18,
2080
2393
  random,
2081
2394
  useCurrentFrame as useCurrentFrame3,
2082
2395
  useDelayRender,
@@ -2085,13 +2398,13 @@ import {
2085
2398
 
2086
2399
  // src/caches.ts
2087
2400
  import React2 from "react";
2088
- import { cancelRender, Internals as Internals11 } from "remotion";
2401
+ import { cancelRender, Internals as Internals15 } from "remotion";
2089
2402
 
2090
2403
  // src/audio-extraction/audio-manager.ts
2091
- import { Internals as Internals8 } from "remotion";
2404
+ import { Internals as Internals12 } from "remotion";
2092
2405
 
2093
2406
  // src/audio-extraction/audio-iterator.ts
2094
- import { Internals as Internals7 } from "remotion";
2407
+ import { Internals as Internals11 } from "remotion";
2095
2408
 
2096
2409
  // src/audio-extraction/audio-cache.ts
2097
2410
  var makeAudioCache = () => {
@@ -2162,7 +2475,7 @@ var makeAudioCache = () => {
2162
2475
  };
2163
2476
 
2164
2477
  // src/audio-extraction/audio-iterator.ts
2165
- var extraThreshold = 1.5;
2478
+ var EXTRA_THRESHOLD_IN_SECONDS = 1.5;
2166
2479
  var safetyOutOfOrderThreshold = 0.2;
2167
2480
  var warned = {};
2168
2481
  var warnAboutMatroskaOnce = (src, logLevel) => {
@@ -2170,7 +2483,7 @@ var warnAboutMatroskaOnce = (src, logLevel) => {
2170
2483
  return;
2171
2484
  }
2172
2485
  warned[src] = true;
2173
- Internals7.Log.warn({ logLevel, tag: "@remotion/media" }, `Audio from ${src} will need to be read from the beginning. https://www.remotion.dev/docs/media/support#matroska-limitation`);
2486
+ Internals11.Log.warn({ logLevel, tag: "@remotion/media" }, `Audio from ${src} will need to be read from the beginning. https://www.remotion.dev/docs/media/support#matroska-limitation`);
2174
2487
  };
2175
2488
  var makeAudioIterator2 = ({
2176
2489
  audioSampleSink,
@@ -2180,7 +2493,7 @@ var makeAudioIterator2 = ({
2180
2493
  actualMatroskaTimestamps,
2181
2494
  logLevel
2182
2495
  }) => {
2183
- const sampleIterator = audioSampleSink.samples(isMatroska ? 0 : Math.max(0, startTimestamp - extraThreshold));
2496
+ const sampleIterator = audioSampleSink.samples(isMatroska ? 0 : Math.max(0, startTimestamp - EXTRA_THRESHOLD_IN_SECONDS));
2184
2497
  if (isMatroska) {
2185
2498
  warnAboutMatroskaOnce(src, logLevel);
2186
2499
  }
@@ -2238,7 +2551,7 @@ var makeAudioIterator2 = ({
2238
2551
  if (openTimestamps.length > 0) {
2239
2552
  const first = openTimestamps[0];
2240
2553
  const last = openTimestamps[openTimestamps.length - 1];
2241
- Internals7.Log.verbose({ logLevel, tag: "@remotion/media" }, "Open audio samples for src", src, `${first.toFixed(3)}...${last.toFixed(3)}`);
2554
+ Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, "Open audio samples for src", src, `${first.toFixed(3)}...${last.toFixed(3)}`);
2242
2555
  }
2243
2556
  };
2244
2557
  const getCacheStats = () => {
@@ -2335,7 +2648,7 @@ var makeAudioManager = () => {
2335
2648
  if (seenKeys.has(key)) {
2336
2649
  iterator.prepareForDeletion();
2337
2650
  iterators.splice(iterators.indexOf(iterator), 1);
2338
- Internals8.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted duplicate iterator for ${iterator.src}`);
2651
+ Internals12.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted duplicate iterator for ${iterator.src}`);
2339
2652
  }
2340
2653
  seenKeys.add(key);
2341
2654
  }
@@ -2356,7 +2669,7 @@ var makeAudioManager = () => {
2356
2669
  attempts++;
2357
2670
  }
2358
2671
  if ((await getTotalCacheStats()).totalSize > maxCacheSize && attempts >= maxAttempts) {
2359
- Internals8.Log.warn({ logLevel, tag: "@remotion/media" }, `Audio cache: Exceeded max cache size after ${maxAttempts} attempts. Still ${(await getTotalCacheStats()).totalSize} bytes used, target was ${maxCacheSize} bytes.`);
2672
+ Internals12.Log.warn({ logLevel, tag: "@remotion/media" }, `Audio cache: Exceeded max cache size after ${maxAttempts} attempts. Still ${(await getTotalCacheStats()).totalSize} bytes used, target was ${maxCacheSize} bytes.`);
2360
2673
  }
2361
2674
  for (const iterator of iterators) {
2362
2675
  if (iterator.src === src && await iterator.waitForCompletion() && iterator.canSatisfyRequestedTime(timeInSeconds)) {
@@ -2425,7 +2738,7 @@ var makeAudioManager = () => {
2425
2738
  };
2426
2739
 
2427
2740
  // src/video-extraction/keyframe-manager.ts
2428
- import { Internals as Internals10 } from "remotion";
2741
+ import { Internals as Internals14 } from "remotion";
2429
2742
 
2430
2743
  // src/render-timestamp-range.ts
2431
2744
  var renderTimestampRange = (timestamps) => {
@@ -2439,7 +2752,7 @@ var renderTimestampRange = (timestamps) => {
2439
2752
  };
2440
2753
 
2441
2754
  // src/video-extraction/keyframe-bank.ts
2442
- import { Internals as Internals9 } from "remotion";
2755
+ import { Internals as Internals13 } from "remotion";
2443
2756
 
2444
2757
  // src/video-extraction/get-allocation-size.ts
2445
2758
  var getAllocationSize = (sample) => {
@@ -2502,7 +2815,7 @@ var makeKeyframeBank = async ({
2502
2815
  }
2503
2816
  }
2504
2817
  if (deletedTimestamps.length > 0) {
2505
- Internals9.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${deletedTimestamps.length} frame${deletedTimestamps.length === 1 ? "" : "s"} ${renderTimestampRange(deletedTimestamps)} for src ${src} because it is lower than ${timestampInSeconds}. Remaining: ${renderTimestampRange(frameTimestamps)}`);
2818
+ Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${deletedTimestamps.length} frame${deletedTimestamps.length === 1 ? "" : "s"} ${renderTimestampRange(deletedTimestamps)} for src ${src} because it is lower than ${timestampInSeconds}. Remaining: ${renderTimestampRange(frameTimestamps)}`);
2506
2819
  }
2507
2820
  };
2508
2821
  const hasDecodedEnoughForTimestamp = (timestamp) => {
@@ -2525,7 +2838,7 @@ var makeKeyframeBank = async ({
2525
2838
  frameTimestamps.push(frame.timestamp);
2526
2839
  allocationSize += getAllocationSize(frame);
2527
2840
  lastUsed = Date.now();
2528
- Internals9.Log.trace({ logLevel, tag: "@remotion/media" }, `Added frame at ${frame.timestamp}sec to bank`);
2841
+ Internals13.Log.trace({ logLevel, tag: "@remotion/media" }, `Added frame at ${frame.timestamp}sec to bank`);
2529
2842
  };
2530
2843
  const ensureEnoughFramesForTimestamp = async (timestampInSeconds, logLevel, fps) => {
2531
2844
  while (!hasDecodedEnoughForTimestamp(timestampInSeconds)) {
@@ -2580,7 +2893,7 @@ var makeKeyframeBank = async ({
2580
2893
  throw new Error("No first frame found");
2581
2894
  }
2582
2895
  const startTimestampInSeconds = firstFrame.value.timestamp;
2583
- Internals9.Log.verbose({ logLevel: parentLogLevel, tag: "@remotion/media" }, `Creating keyframe bank from ${startTimestampInSeconds}sec`);
2896
+ Internals13.Log.verbose({ logLevel: parentLogLevel, tag: "@remotion/media" }, `Creating keyframe bank from ${startTimestampInSeconds}sec`);
2584
2897
  addFrame(firstFrame.value, parentLogLevel);
2585
2898
  const getRangeOfTimestamps = () => {
2586
2899
  if (frameTimestamps.length === 0) {
@@ -2598,7 +2911,7 @@ var makeKeyframeBank = async ({
2598
2911
  const prepareForDeletion = (logLevel, reason) => {
2599
2912
  const range = getRangeOfTimestamps();
2600
2913
  if (range) {
2601
- Internals9.Log.verbose({ logLevel, tag: "@remotion/media" }, `Preparing for deletion (${reason}) of keyframe bank from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec`);
2914
+ Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `Preparing for deletion (${reason}) of keyframe bank from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec`);
2602
2915
  }
2603
2916
  let framesDeleted = 0;
2604
2917
  for (const frameTimestamp of frameTimestamps.slice()) {
@@ -2671,10 +2984,10 @@ var makeKeyframeManager = () => {
2671
2984
  if (size === 0) {
2672
2985
  continue;
2673
2986
  }
2674
- Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, `Open frames for src ${src}: ${renderTimestampRange(timestamps)}`);
2987
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Open frames for src ${src}: ${renderTimestampRange(timestamps)}`);
2675
2988
  }
2676
2989
  }
2677
- Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, `Video cache stats: ${count} open frames, ${totalSize} bytes`);
2990
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Video cache stats: ${count} open frames, ${totalSize} bytes`);
2678
2991
  };
2679
2992
  const getCacheStats = () => {
2680
2993
  let count = 0;
@@ -2728,7 +3041,7 @@ var makeKeyframeManager = () => {
2728
3041
  const { framesDeleted } = mostInThePastBank.prepareForDeletion(logLevel, "deleted oldest keyframe bank to stay under max cache size");
2729
3042
  sources[mostInThePastSrc].splice(mostInThePastIndex, 1);
2730
3043
  if (range) {
2731
- Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${framesDeleted} frames for src ${mostInThePastSrc} from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec to free up memory.`);
3044
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${framesDeleted} frames for src ${mostInThePastSrc} from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec to free up memory.`);
2732
3045
  }
2733
3046
  }
2734
3047
  return { finish: false };
@@ -2742,12 +3055,12 @@ var makeKeyframeManager = () => {
2742
3055
  if (finish) {
2743
3056
  break;
2744
3057
  }
2745
- Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, "Deleted oldest keyframe bank to stay under max cache size", (cacheStats.totalSize / 1024 / 1024).toFixed(1), "out of", (maxCacheSize / 1024 / 1024).toFixed(1));
3058
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, "Deleted oldest keyframe bank to stay under max cache size", (cacheStats.totalSize / 1024 / 1024).toFixed(1), "out of", (maxCacheSize / 1024 / 1024).toFixed(1));
2746
3059
  cacheStats = getTotalCacheStats();
2747
3060
  attempts++;
2748
3061
  }
2749
3062
  if (cacheStats.totalSize > maxCacheSize && attempts >= maxAttempts) {
2750
- Internals10.Log.warn({ logLevel, tag: "@remotion/media" }, `Exceeded max cache size after ${maxAttempts} attempts. Remaining cache size: ${(cacheStats.totalSize / 1024 / 1024).toFixed(1)} MB, target was ${(maxCacheSize / 1024 / 1024).toFixed(1)} MB.`);
3063
+ Internals14.Log.warn({ logLevel, tag: "@remotion/media" }, `Exceeded max cache size after ${maxAttempts} attempts. Remaining cache size: ${(cacheStats.totalSize / 1024 / 1024).toFixed(1)} MB, target was ${(maxCacheSize / 1024 / 1024).toFixed(1)} MB.`);
2751
3064
  }
2752
3065
  };
2753
3066
  const clearKeyframeBanksBeforeTime = ({
@@ -2768,7 +3081,7 @@ var makeKeyframeManager = () => {
2768
3081
  }
2769
3082
  if (range.lastTimestamp < threshold) {
2770
3083
  bank.prepareForDeletion(logLevel, "cleared before threshold " + threshold);
2771
- Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, `[Video] Cleared frames for src ${src} from ${range.firstTimestamp}sec to ${range.lastTimestamp}sec`);
3084
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `[Video] Cleared frames for src ${src} from ${range.firstTimestamp}sec to ${range.lastTimestamp}sec`);
2772
3085
  const bankIndex = banks.indexOf(bank);
2773
3086
  delete sources[src][bankIndex];
2774
3087
  } else {
@@ -2790,7 +3103,7 @@ var makeKeyframeManager = () => {
2790
3103
  const existingBanks = sources[src] ?? [];
2791
3104
  const existingBank = existingBanks?.find((bank) => bank.canSatisfyTimestamp(timestamp));
2792
3105
  if (!existingBank) {
2793
- Internals10.Log.trace({ logLevel, tag: "@remotion/media" }, `Creating new keyframe bank for src ${src} at timestamp ${timestamp}`);
3106
+ Internals14.Log.trace({ logLevel, tag: "@remotion/media" }, `Creating new keyframe bank for src ${src} at timestamp ${timestamp}`);
2794
3107
  const newKeyframeBank = await makeKeyframeBank({
2795
3108
  videoSampleSink,
2796
3109
  logLevel,
@@ -2801,10 +3114,10 @@ var makeKeyframeManager = () => {
2801
3114
  return newKeyframeBank;
2802
3115
  }
2803
3116
  if (existingBank.canSatisfyTimestamp(timestamp)) {
2804
- Internals10.Log.trace({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists and satisfies timestamp ${timestamp}`);
3117
+ Internals14.Log.trace({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists and satisfies timestamp ${timestamp}`);
2805
3118
  return existingBank;
2806
3119
  }
2807
- Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists but frame at time ${timestamp} does not exist anymore.`);
3120
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists but frame at time ${timestamp} does not exist anymore.`);
2808
3121
  existingBank.prepareForDeletion(logLevel, "already existed but evicted");
2809
3122
  sources[src] = sources[src].filter((bank) => bank !== existingBank);
2810
3123
  const replacementKeybank = await makeKeyframeBank({
@@ -2895,20 +3208,20 @@ var getUncachedMaxCacheSize = (logLevel) => {
2895
3208
  if (window.remotion_mediaCacheSizeInBytes > 20000 * 1024 * 1024) {
2896
3209
  cancelRender(new Error(`The maximum value for the "mediaCacheSizeInBytes" prop is 20GB (${20000 * 1024 * 1024}), got: ${window.remotion_mediaCacheSizeInBytes}`));
2897
3210
  }
2898
- Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set using "mediaCacheSizeInBytes": ${(window.remotion_mediaCacheSizeInBytes / 1024 / 1024).toFixed(1)} MB`);
3211
+ Internals15.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set using "mediaCacheSizeInBytes": ${(window.remotion_mediaCacheSizeInBytes / 1024 / 1024).toFixed(1)} MB`);
2899
3212
  return window.remotion_mediaCacheSizeInBytes;
2900
3213
  }
2901
3214
  if (typeof window !== "undefined" && window.remotion_initialMemoryAvailable !== undefined && window.remotion_initialMemoryAvailable !== null) {
2902
3215
  const value = window.remotion_initialMemoryAvailable / 2;
2903
3216
  if (value < 500 * 1024 * 1024) {
2904
- Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on minimum value of 500MB (which is more than half of the available system memory!)`);
3217
+ Internals15.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on minimum value of 500MB (which is more than half of the available system memory!)`);
2905
3218
  return 500 * 1024 * 1024;
2906
3219
  }
2907
3220
  if (value > 20000 * 1024 * 1024) {
2908
- Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on maximum value of 20GB (which is less than half of the available system memory)`);
3221
+ Internals15.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on maximum value of 20GB (which is less than half of the available system memory)`);
2909
3222
  return 20000 * 1024 * 1024;
2910
3223
  }
2911
- Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on available memory (50% of available memory): ${(value / 1024 / 1024).toFixed(1)} MB`);
3224
+ Internals15.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on available memory (50% of available memory): ${(value / 1024 / 1024).toFixed(1)} MB`);
2912
3225
  return value;
2913
3226
  }
2914
3227
  return 1000 * 1000 * 1000;
@@ -2922,7 +3235,7 @@ var getMaxVideoCacheSize = (logLevel) => {
2922
3235
  return cachedMaxCacheSize;
2923
3236
  };
2924
3237
  var useMaxMediaCacheSize = (logLevel) => {
2925
- const context = React2.useContext(Internals11.MaxMediaCacheSizeContext);
3238
+ const context = React2.useContext(Internals15.MaxMediaCacheSizeContext);
2926
3239
  if (context === null) {
2927
3240
  return getMaxVideoCacheSize(logLevel);
2928
3241
  }
@@ -3171,7 +3484,7 @@ var combineAudioDataAndClosePrevious = (audioDataArray) => {
3171
3484
  };
3172
3485
 
3173
3486
  // src/get-sink.ts
3174
- import { Internals as Internals12 } from "remotion";
3487
+ import { Internals as Internals16 } from "remotion";
3175
3488
 
3176
3489
  // src/video-extraction/get-frames-since-keyframe.ts
3177
3490
  import {
@@ -3324,7 +3637,7 @@ var sinkPromises = {};
3324
3637
  var getSink = (src, logLevel) => {
3325
3638
  let promise = sinkPromises[src];
3326
3639
  if (!promise) {
3327
- Internals12.Log.verbose({
3640
+ Internals16.Log.verbose({
3328
3641
  logLevel,
3329
3642
  tag: "@remotion/media"
3330
3643
  }, `Sink for ${src} was not found, creating new sink`);
@@ -3464,7 +3777,7 @@ var extractAudio = (params) => {
3464
3777
  };
3465
3778
 
3466
3779
  // src/video-extraction/extract-frame.ts
3467
- import { Internals as Internals13 } from "remotion";
3780
+ import { Internals as Internals17 } from "remotion";
3468
3781
  var extractFrameInternal = async ({
3469
3782
  src,
3470
3783
  timeInSeconds: unloopedTimeInSeconds,
@@ -3545,7 +3858,7 @@ var extractFrameInternal = async ({
3545
3858
  durationInSeconds: await sink.getDuration()
3546
3859
  };
3547
3860
  } catch (err) {
3548
- Internals13.Log.info({ logLevel, tag: "@remotion/media" }, `Error decoding ${src} at time ${timeInSeconds}: ${err}`, err);
3861
+ Internals17.Log.info({ logLevel, tag: "@remotion/media" }, `Error decoding ${src} at time ${timeInSeconds}: ${err}`, err);
3549
3862
  return { type: "cannot-decode", durationInSeconds: mediaDurationInSeconds };
3550
3863
  }
3551
3864
  };
@@ -3941,13 +4254,13 @@ var AudioForRendering = ({
3941
4254
  trimBefore,
3942
4255
  onError
3943
4256
  }) => {
3944
- const defaultLogLevel = Internals14.useLogLevel();
4257
+ const defaultLogLevel = Internals18.useLogLevel();
3945
4258
  const logLevel = overriddenLogLevel ?? defaultLogLevel;
3946
4259
  const frame = useCurrentFrame3();
3947
- const absoluteFrame = Internals14.useTimelinePosition();
3948
- const videoConfig = Internals14.useUnsafeVideoConfig();
3949
- const { registerRenderAsset, unregisterRenderAsset } = useContext3(Internals14.RenderAssetManager);
3950
- const startsAt = Internals14.useMediaStartsAt();
4260
+ const absoluteFrame = Internals18.useTimelinePosition();
4261
+ const videoConfig = Internals18.useUnsafeVideoConfig();
4262
+ const { registerRenderAsset, unregisterRenderAsset } = useContext4(Internals18.RenderAssetManager);
4263
+ const startsAt = Internals18.useMediaStartsAt();
3951
4264
  const environment = useRemotionEnvironment();
3952
4265
  if (!videoConfig) {
3953
4266
  throw new Error("No video config found");
@@ -3958,7 +4271,7 @@ var AudioForRendering = ({
3958
4271
  const { fps } = videoConfig;
3959
4272
  const { delayRender, continueRender } = useDelayRender();
3960
4273
  const [replaceWithHtml5Audio, setReplaceWithHtml5Audio] = useState3(false);
3961
- const sequenceContext = useContext3(Internals14.SequenceContext);
4274
+ const sequenceContext = useContext4(Internals18.SequenceContext);
3962
4275
  const id = useMemo3(() => `media-audio-${random(src)}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.relativeFrom}-${sequenceContext?.durationInFrames}`, [
3963
4276
  src,
3964
4277
  sequenceContext?.cumulatedFrom,
@@ -3966,7 +4279,7 @@ var AudioForRendering = ({
3966
4279
  sequenceContext?.durationInFrames
3967
4280
  ]);
3968
4281
  const maxCacheSize = useMaxMediaCacheSize(logLevel);
3969
- const audioEnabled = Internals14.useAudioEnabled();
4282
+ const audioEnabled = Internals18.useAudioEnabled();
3970
4283
  useLayoutEffect2(() => {
3971
4284
  const timestamp = frame / fps;
3972
4285
  const durationInSeconds = 1 / fps;
@@ -4016,7 +4329,7 @@ var AudioForRendering = ({
4016
4329
  if (action === "fail") {
4017
4330
  cancelRender2(errorToUse);
4018
4331
  }
4019
- Internals14.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
4332
+ Internals18.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
4020
4333
  setReplaceWithHtml5Audio(true);
4021
4334
  };
4022
4335
  if (result.type === "unknown-container-format") {
@@ -4043,12 +4356,12 @@ var AudioForRendering = ({
4043
4356
  frame,
4044
4357
  startsAt
4045
4358
  });
4046
- const volume = Internals14.evaluateVolume({
4359
+ const volume = Internals18.evaluateVolume({
4047
4360
  volume: volumeProp,
4048
4361
  frame: volumePropsFrame,
4049
4362
  mediaVolume: 1
4050
4363
  });
4051
- Internals14.warnAboutTooHighVolume(volume);
4364
+ Internals18.warnAboutTooHighVolume(volume);
4052
4365
  if (audio && volume > 0) {
4053
4366
  applyVolume(audio.data, volume);
4054
4367
  registerRenderAsset({
@@ -4124,7 +4437,7 @@ var AudioForRendering = ({
4124
4437
 
4125
4438
  // src/audio/audio.tsx
4126
4439
  import { jsx as jsx3 } from "react/jsx-runtime";
4127
- var { validateMediaProps } = Internals15;
4440
+ var { validateMediaProps } = Internals19;
4128
4441
  var Audio = (props) => {
4129
4442
  const { name, stack, showInTimeline, ...otherProps } = props;
4130
4443
  const environment = useRemotionEnvironment2();
@@ -4143,14 +4456,14 @@ var Audio = (props) => {
4143
4456
  stack: stack ?? null
4144
4457
  });
4145
4458
  };
4146
- Internals15.addSequenceStackTraces(Audio);
4459
+ Internals19.addSequenceStackTraces(Audio);
4147
4460
 
4148
4461
  // src/video/video.tsx
4149
- import { Internals as Internals18, useRemotionEnvironment as useRemotionEnvironment4 } from "remotion";
4462
+ import { Internals as Internals22, useRemotionEnvironment as useRemotionEnvironment4 } from "remotion";
4150
4463
 
4151
4464
  // src/video/video-for-preview.tsx
4152
4465
  import {
4153
- useContext as useContext4,
4466
+ useContext as useContext5,
4154
4467
  useEffect as useEffect3,
4155
4468
  useLayoutEffect as useLayoutEffect3,
4156
4469
  useMemo as useMemo4,
@@ -4159,7 +4472,7 @@ import {
4159
4472
  } from "react";
4160
4473
  import {
4161
4474
  Html5Video,
4162
- Internals as Internals16,
4475
+ Internals as Internals20,
4163
4476
  useBufferState as useBufferState2,
4164
4477
  useCurrentFrame as useCurrentFrame4,
4165
4478
  useVideoConfig as useVideoConfig3
@@ -4177,7 +4490,7 @@ var {
4177
4490
  usePreload: usePreload2,
4178
4491
  SequenceContext: SequenceContext2,
4179
4492
  SequenceVisibilityToggleContext
4180
- } = Internals16;
4493
+ } = Internals20;
4181
4494
  var VideoForPreviewAssertedShowing = ({
4182
4495
  src: unpreloadedSrc,
4183
4496
  style,
@@ -4198,6 +4511,7 @@ var VideoForPreviewAssertedShowing = ({
4198
4511
  fallbackOffthreadVideoProps,
4199
4512
  audioStreamIndex,
4200
4513
  debugOverlay,
4514
+ debugAudioScheduling,
4201
4515
  headless,
4202
4516
  onError,
4203
4517
  controls
@@ -4213,26 +4527,28 @@ var VideoForPreviewAssertedShowing = ({
4213
4527
  const [mediaPlayerReady, setMediaPlayerReady] = useState4(false);
4214
4528
  const [shouldFallbackToNativeVideo, setShouldFallbackToNativeVideo] = useState4(false);
4215
4529
  const [playing] = Timeline2.usePlayingState();
4216
- const timelineContext = useContext4(Internals16.TimelineContext);
4530
+ const timelineContext = useContext5(Internals20.TimelineContext);
4217
4531
  const globalPlaybackRate = timelineContext.playbackRate;
4218
- const sharedAudioContext = useContext4(SharedAudioContext2);
4532
+ const sharedAudioContext = useContext5(SharedAudioContext2);
4219
4533
  const buffer = useBufferState2();
4220
4534
  const [mediaMuted] = useMediaMutedState2();
4221
4535
  const [mediaVolume] = useMediaVolumeState2();
4222
4536
  const [mediaDurationInSeconds, setMediaDurationInSeconds] = useState4(null);
4223
- const { hidden } = useContext4(SequenceVisibilityToggleContext);
4537
+ const { hidden } = useContext5(SequenceVisibilityToggleContext);
4224
4538
  const volumePropFrame = useFrameForVolumeProp2(loopVolumeCurveBehavior);
4225
4539
  const userPreferredVolume = evaluateVolume2({
4226
4540
  frame: volumePropFrame,
4227
4541
  volume,
4228
4542
  mediaVolume
4229
4543
  });
4544
+ if (!videoConfig) {
4545
+ throw new Error("No video config found");
4546
+ }
4230
4547
  warnAboutTooHighVolume2(userPreferredVolume);
4231
- const parentSequence = useContext4(SequenceContext2);
4548
+ const parentSequence = useContext5(SequenceContext2);
4232
4549
  const isPremounting = Boolean(parentSequence?.premounting);
4233
4550
  const isPostmounting = Boolean(parentSequence?.postmounting);
4234
- const { premountFramesRemaining, playing: playingWhilePremounting } = useContext4(Internals16.PremountContext);
4235
- const isNextFrameGoingToPlay = playingWhilePremounting && premountFramesRemaining > 0 && premountFramesRemaining <= 1.000000001;
4551
+ const sequenceOffset = ((parentSequence?.cumulatedFrom ?? 0) + (parentSequence?.relativeFrom ?? 0)) / videoConfig.fps;
4236
4552
  const loopDisplay = useLoopDisplay({
4237
4553
  loop,
4238
4554
  mediaDurationInSeconds,
@@ -4257,34 +4573,35 @@ var VideoForPreviewAssertedShowing = ({
4257
4573
  controls
4258
4574
  });
4259
4575
  const isSequenceHidden = hidden[timelineId] ?? false;
4260
- if (!videoConfig) {
4261
- throw new Error("No video config found");
4262
- }
4263
4576
  const currentTime = frame / videoConfig.fps;
4264
4577
  const currentTimeRef = useRef2(currentTime);
4265
4578
  currentTimeRef.current = currentTime;
4266
4579
  const preloadedSrc = usePreload2(src);
4267
- const buffering = useContext4(Internals16.BufferingContextReact);
4580
+ const buffering = useContext5(Internals20.BufferingContextReact);
4268
4581
  if (!buffering) {
4269
4582
  throw new Error("useMediaPlayback must be used inside a <BufferingContext>");
4270
4583
  }
4271
4584
  const effectiveMuted = isSequenceHidden || muted || mediaMuted || userPreferredVolume <= 0;
4272
- const isPlayerBuffering = Internals16.useIsPlayerBuffering(buffering);
4585
+ const isPlayerBuffering = Internals20.useIsPlayerBuffering(buffering);
4273
4586
  const initialPlaying = useRef2(playing && !isPlayerBuffering);
4274
4587
  const initialIsPremounting = useRef2(isPremounting);
4275
4588
  const initialIsPostmounting = useRef2(isPostmounting);
4276
4589
  const initialGlobalPlaybackRate = useRef2(globalPlaybackRate);
4277
4590
  const initialPlaybackRate = useRef2(playbackRate);
4278
4591
  const initialMuted = useRef2(effectiveMuted);
4592
+ const initialSequenceOffset = useRef2(sequenceOffset);
4279
4593
  useEffect3(() => {
4280
4594
  if (!sharedAudioContext)
4281
4595
  return;
4596
+ if (!sharedAudioContext.audioContext)
4597
+ return;
4598
+ const { audioContext, audioSyncAnchor, scheduleAudioNode } = sharedAudioContext;
4282
4599
  try {
4283
4600
  const player = new MediaPlayer({
4284
4601
  canvas: canvasRef.current,
4285
4602
  src: preloadedSrc,
4286
4603
  logLevel,
4287
- sharedAudioContext: sharedAudioContext.audioContext,
4604
+ sharedAudioContext: { audioContext, audioSyncAnchor, scheduleAudioNode },
4288
4605
  loop,
4289
4606
  trimAfter: initialTrimAfterRef.current,
4290
4607
  trimBefore: initialTrimBeforeRef.current,
@@ -4292,13 +4609,15 @@ var VideoForPreviewAssertedShowing = ({
4292
4609
  playbackRate: initialPlaybackRate.current,
4293
4610
  audioStreamIndex,
4294
4611
  debugOverlay,
4612
+ debugAudioScheduling,
4295
4613
  bufferState: buffer,
4296
4614
  isPremounting: initialIsPremounting.current,
4297
4615
  isPostmounting: initialIsPostmounting.current,
4298
4616
  globalPlaybackRate: initialGlobalPlaybackRate.current,
4299
4617
  durationInFrames: videoConfig.durationInFrames,
4300
4618
  onVideoFrameCallback: initialOnVideoFrameRef.current ?? null,
4301
- playing: initialPlaying.current
4619
+ playing: initialPlaying.current,
4620
+ sequenceOffset: initialSequenceOffset.current
4302
4621
  });
4303
4622
  mediaPlayerRef.current = player;
4304
4623
  player.initialize(currentTimeRef.current, initialMuted.current).then((result) => {
@@ -4316,7 +4635,7 @@ var VideoForPreviewAssertedShowing = ({
4316
4635
  if (action === "fail") {
4317
4636
  throw errorToUse;
4318
4637
  }
4319
- Internals16.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
4638
+ Internals20.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
4320
4639
  setShouldFallbackToNativeVideo(true);
4321
4640
  };
4322
4641
  if (result.type === "unknown-container-format") {
@@ -4350,7 +4669,7 @@ var VideoForPreviewAssertedShowing = ({
4350
4669
  if (action === "fail") {
4351
4670
  throw errorToUse;
4352
4671
  }
4353
- Internals16.Log.error({ logLevel, tag: "@remotion/media" }, "[VideoForPreview] Failed to initialize MediaPlayer", errorToUse);
4672
+ Internals20.Log.error({ logLevel, tag: "@remotion/media" }, "[VideoForPreview] Failed to initialize MediaPlayer", errorToUse);
4354
4673
  setShouldFallbackToNativeVideo(true);
4355
4674
  });
4356
4675
  } catch (error) {
@@ -4364,12 +4683,12 @@ var VideoForPreviewAssertedShowing = ({
4364
4683
  if (action === "fail") {
4365
4684
  throw errorToUse;
4366
4685
  }
4367
- Internals16.Log.error({ logLevel, tag: "@remotion/media" }, "[VideoForPreview] MediaPlayer initialization failed", errorToUse);
4686
+ Internals20.Log.error({ logLevel, tag: "@remotion/media" }, "[VideoForPreview] MediaPlayer initialization failed", errorToUse);
4368
4687
  setShouldFallbackToNativeVideo(true);
4369
4688
  }
4370
4689
  return () => {
4371
4690
  if (mediaPlayerRef.current) {
4372
- Internals16.Log.trace({ logLevel, tag: "@remotion/media" }, `[VideoForPreview] Disposing MediaPlayer`);
4691
+ Internals20.Log.trace({ logLevel, tag: "@remotion/media" }, `[VideoForPreview] Disposing MediaPlayer`);
4373
4692
  mediaPlayerRef.current.dispose();
4374
4693
  mediaPlayerRef.current = null;
4375
4694
  }
@@ -4380,6 +4699,7 @@ var VideoForPreviewAssertedShowing = ({
4380
4699
  audioStreamIndex,
4381
4700
  buffer,
4382
4701
  debugOverlay,
4702
+ debugAudioScheduling,
4383
4703
  disallowFallbackToOffthreadVideo,
4384
4704
  logLevel,
4385
4705
  loop,
@@ -4390,65 +4710,33 @@ var VideoForPreviewAssertedShowing = ({
4390
4710
  videoConfig.durationInFrames
4391
4711
  ]);
4392
4712
  const classNameValue = useMemo4(() => {
4393
- return [Internals16.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals16.truthy).join(" ");
4713
+ return [Internals20.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals20.truthy).join(" ");
4394
4714
  }, [className]);
4395
- useEffect3(() => {
4396
- const mediaPlayer = mediaPlayerRef.current;
4397
- if (!mediaPlayer)
4398
- return;
4399
- if (isNextFrameGoingToPlay) {
4400
- const currentTimeUntilZero = premountFramesRemaining / videoConfig.fps / globalPlaybackRate;
4401
- mediaPlayer.playAudio(currentTimeRef.current - currentTimeUntilZero);
4402
- }
4403
- }, [
4404
- isNextFrameGoingToPlay,
4405
- premountFramesRemaining,
4406
- videoConfig.fps,
4407
- globalPlaybackRate
4408
- ]);
4409
- useEffect3(() => {
4410
- const mediaPlayer = mediaPlayerRef.current;
4411
- if (!mediaPlayer)
4412
- return;
4413
- if (playing && !isPlayerBuffering && !isNextFrameGoingToPlay) {
4414
- mediaPlayer.play(currentTimeRef.current);
4415
- } else {
4416
- mediaPlayer.pause();
4417
- }
4418
- }, [
4419
- isPlayerBuffering,
4715
+ useCommonEffects({
4716
+ mediaPlayerRef,
4717
+ mediaPlayerReady,
4718
+ currentTimeRef,
4420
4719
  playing,
4720
+ isPlayerBuffering,
4721
+ frame,
4722
+ trimBefore,
4723
+ trimAfter,
4724
+ effectiveMuted,
4725
+ userPreferredVolume,
4726
+ playbackRate,
4727
+ globalPlaybackRate,
4728
+ fps: videoConfig.fps,
4729
+ sequenceOffset,
4730
+ loop,
4731
+ debugAudioScheduling,
4732
+ durationInFrames: videoConfig.durationInFrames,
4733
+ isPremounting,
4734
+ isPostmounting,
4735
+ currentTime,
4421
4736
  logLevel,
4422
- mediaPlayerReady,
4423
- isNextFrameGoingToPlay
4424
- ]);
4425
- useEffect3(() => {
4426
- const mediaPlayer = mediaPlayerRef.current;
4427
- if (!mediaPlayer || !mediaPlayerReady) {
4428
- return;
4429
- }
4430
- mediaPlayer.setTrimBefore(trimBefore, currentTimeRef.current);
4431
- }, [trimBefore, mediaPlayerReady]);
4432
- useEffect3(() => {
4433
- const mediaPlayer = mediaPlayerRef.current;
4434
- if (!mediaPlayer || !mediaPlayerReady) {
4435
- return;
4436
- }
4437
- mediaPlayer.setTrimAfter(trimAfter, currentTimeRef.current);
4438
- }, [trimAfter, mediaPlayerReady]);
4439
- useLayoutEffect3(() => {
4440
- const mediaPlayer = mediaPlayerRef.current;
4441
- if (!mediaPlayer || !mediaPlayerReady)
4442
- return;
4443
- mediaPlayer.setMuted(effectiveMuted);
4444
- }, [effectiveMuted, mediaPlayerReady]);
4445
- useLayoutEffect3(() => {
4446
- const mediaPlayer = mediaPlayerRef.current;
4447
- if (!mediaPlayer || !mediaPlayerReady) {
4448
- return;
4449
- }
4450
- mediaPlayer.setVolume(userPreferredVolume);
4451
- }, [userPreferredVolume, mediaPlayerReady]);
4737
+ sharedAudioContext,
4738
+ label: "VideoForPreview"
4739
+ });
4452
4740
  useLayoutEffect3(() => {
4453
4741
  const mediaPlayer = mediaPlayerRef.current;
4454
4742
  if (!mediaPlayer || !mediaPlayerReady) {
@@ -4456,55 +4744,6 @@ var VideoForPreviewAssertedShowing = ({
4456
4744
  }
4457
4745
  mediaPlayer.setDebugOverlay(debugOverlay);
4458
4746
  }, [debugOverlay, mediaPlayerReady]);
4459
- useLayoutEffect3(() => {
4460
- const mediaPlayer = mediaPlayerRef.current;
4461
- if (!mediaPlayer || !mediaPlayerReady) {
4462
- return;
4463
- }
4464
- mediaPlayer.setPlaybackRate(playbackRate, currentTimeRef.current);
4465
- }, [playbackRate, mediaPlayerReady]);
4466
- useLayoutEffect3(() => {
4467
- const mediaPlayer = mediaPlayerRef.current;
4468
- if (!mediaPlayer || !mediaPlayerReady) {
4469
- return;
4470
- }
4471
- mediaPlayer.setGlobalPlaybackRate(globalPlaybackRate);
4472
- }, [globalPlaybackRate, mediaPlayerReady]);
4473
- useLayoutEffect3(() => {
4474
- const mediaPlayer = mediaPlayerRef.current;
4475
- if (!mediaPlayer || !mediaPlayerReady) {
4476
- return;
4477
- }
4478
- mediaPlayer.setLoop(loop);
4479
- }, [loop, mediaPlayerReady]);
4480
- useLayoutEffect3(() => {
4481
- const mediaPlayer = mediaPlayerRef.current;
4482
- if (!mediaPlayer || !mediaPlayerReady) {
4483
- return;
4484
- }
4485
- mediaPlayer.setDurationInFrames(videoConfig.durationInFrames);
4486
- }, [videoConfig.durationInFrames, mediaPlayerReady]);
4487
- useLayoutEffect3(() => {
4488
- const mediaPlayer = mediaPlayerRef.current;
4489
- if (!mediaPlayer || !mediaPlayerReady) {
4490
- return;
4491
- }
4492
- mediaPlayer.setIsPremounting(isPremounting);
4493
- }, [isPremounting, mediaPlayerReady]);
4494
- useLayoutEffect3(() => {
4495
- const mediaPlayer = mediaPlayerRef.current;
4496
- if (!mediaPlayer || !mediaPlayerReady) {
4497
- return;
4498
- }
4499
- mediaPlayer.setIsPostmounting(isPostmounting);
4500
- }, [isPostmounting, mediaPlayerReady]);
4501
- useLayoutEffect3(() => {
4502
- const mediaPlayer = mediaPlayerRef.current;
4503
- if (!mediaPlayer || !mediaPlayerReady) {
4504
- return;
4505
- }
4506
- mediaPlayer.setFps(videoConfig.fps);
4507
- }, [videoConfig.fps, mediaPlayerReady]);
4508
4747
  useLayoutEffect3(() => {
4509
4748
  const mediaPlayer = mediaPlayerRef.current;
4510
4749
  if (!mediaPlayer || !mediaPlayerReady) {
@@ -4512,13 +4751,6 @@ var VideoForPreviewAssertedShowing = ({
4512
4751
  }
4513
4752
  mediaPlayer.setVideoFrameCallback(onVideoFrame ?? null);
4514
4753
  }, [onVideoFrame, mediaPlayerReady]);
4515
- useLayoutEffect3(() => {
4516
- const mediaPlayer = mediaPlayerRef.current;
4517
- if (!mediaPlayer || !mediaPlayerReady)
4518
- return;
4519
- mediaPlayer.seekTo(currentTime).catch(() => {});
4520
- Internals16.Log.trace({ logLevel, tag: "@remotion/media" }, `[VideoForPreview] Updating target time to ${currentTime.toFixed(3)}s`);
4521
- }, [currentTime, logLevel, mediaPlayerReady]);
4522
4754
  const actualStyle = useMemo4(() => {
4523
4755
  return {
4524
4756
  ...style,
@@ -4548,8 +4780,6 @@ var VideoForPreviewAssertedShowing = ({
4548
4780
  }
4549
4781
  return /* @__PURE__ */ jsx4("canvas", {
4550
4782
  ref: canvasRef,
4551
- width: videoConfig.width,
4552
- height: videoConfig.height,
4553
4783
  style: actualStyle,
4554
4784
  className: classNameValue
4555
4785
  });
@@ -4565,39 +4795,25 @@ var videoSchema = {
4565
4795
  },
4566
4796
  playbackRate: {
4567
4797
  type: "number",
4568
- min: 0,
4798
+ min: 0.1,
4569
4799
  step: 0.01,
4570
4800
  default: 1,
4571
4801
  description: "Playback Rate"
4572
4802
  },
4573
- trimBefore: { type: "number", min: 0, default: 0 },
4574
- trimAfter: { type: "number", min: 0, default: 0 }
4803
+ loop: { type: "boolean", default: false, description: "Loop" }
4575
4804
  };
4576
4805
  var VideoForPreview = (props) => {
4577
4806
  const schemaInput = useMemo4(() => {
4578
- if (typeof props.volume !== "number") {
4579
- return null;
4580
- }
4581
4807
  return {
4582
4808
  volume: props.volume,
4583
4809
  playbackRate: props.playbackRate,
4584
- trimBefore: props.trimBefore,
4585
- trimAfter: props.trimAfter,
4586
4810
  loop: props.loop
4587
4811
  };
4588
- }, [
4589
- props.volume,
4590
- props.playbackRate,
4591
- props.trimBefore,
4592
- props.trimAfter,
4593
- props.loop
4594
- ]);
4595
- const { controls, values } = Internals16.useSchema(schemaInput ? videoSchema : null, schemaInput);
4596
- const volume = schemaInput !== null ? values.volume : props.volume;
4597
- const playbackRate = schemaInput !== null ? values.playbackRate : props.playbackRate;
4598
- const trimBefore = schemaInput !== null ? values.trimBefore : props.trimBefore;
4599
- const trimAfter = schemaInput !== null ? values.trimAfter : props.trimAfter;
4600
- const effectiveLoop = schemaInput !== null ? values.loop : props.loop;
4812
+ }, [props.volume, props.playbackRate, props.loop]);
4813
+ const {
4814
+ controls,
4815
+ values: { loop, playbackRate, volume }
4816
+ } = Internals20.useSchema(videoSchema, schemaInput);
4601
4817
  const frame = useCurrentFrame4();
4602
4818
  const videoConfig = useVideoConfig3();
4603
4819
  const currentTime = frame / videoConfig.fps;
@@ -4605,9 +4821,9 @@ var VideoForPreview = (props) => {
4605
4821
  return getTimeInSeconds({
4606
4822
  unloopedTimeInSeconds: currentTime,
4607
4823
  playbackRate,
4608
- loop: effectiveLoop,
4609
- trimBefore,
4610
- trimAfter,
4824
+ loop,
4825
+ trimBefore: props.trimBefore,
4826
+ trimAfter: props.trimAfter,
4611
4827
  mediaDurationInSeconds: Infinity,
4612
4828
  fps: videoConfig.fps,
4613
4829
  ifNoMediaDuration: "infinity",
@@ -4615,37 +4831,35 @@ var VideoForPreview = (props) => {
4615
4831
  }) !== null;
4616
4832
  }, [
4617
4833
  currentTime,
4618
- effectiveLoop,
4834
+ loop,
4619
4835
  playbackRate,
4620
4836
  props.src,
4621
- trimAfter,
4622
- trimBefore,
4623
- videoConfig.fps
4837
+ videoConfig.fps,
4838
+ props.trimBefore,
4839
+ props.trimAfter
4624
4840
  ]);
4625
4841
  if (!showShow) {
4626
4842
  return null;
4627
4843
  }
4628
4844
  return /* @__PURE__ */ jsx4(VideoForPreviewAssertedShowing, {
4629
4845
  ...props,
4630
- volume,
4846
+ volume: volume ?? 1,
4631
4847
  playbackRate,
4632
- loop: effectiveLoop,
4633
- trimBefore,
4634
- trimAfter,
4848
+ loop,
4635
4849
  controls
4636
4850
  });
4637
4851
  };
4638
4852
 
4639
4853
  // src/video/video-for-rendering.tsx
4640
4854
  import {
4641
- useContext as useContext5,
4855
+ useContext as useContext6,
4642
4856
  useLayoutEffect as useLayoutEffect4,
4643
4857
  useMemo as useMemo5,
4644
4858
  useRef as useRef3,
4645
4859
  useState as useState5
4646
4860
  } from "react";
4647
4861
  import {
4648
- Internals as Internals17,
4862
+ Internals as Internals21,
4649
4863
  Loop,
4650
4864
  random as random2,
4651
4865
  useCurrentFrame as useCurrentFrame5,
@@ -4682,11 +4896,11 @@ var VideoForRendering = ({
4682
4896
  throw new TypeError("No `src` was passed to <Video>.");
4683
4897
  }
4684
4898
  const frame = useCurrentFrame5();
4685
- const absoluteFrame = Internals17.useTimelinePosition();
4899
+ const absoluteFrame = Internals21.useTimelinePosition();
4686
4900
  const { fps } = useVideoConfig4();
4687
- const { registerRenderAsset, unregisterRenderAsset } = useContext5(Internals17.RenderAssetManager);
4688
- const startsAt = Internals17.useMediaStartsAt();
4689
- const sequenceContext = useContext5(Internals17.SequenceContext);
4901
+ const { registerRenderAsset, unregisterRenderAsset } = useContext6(Internals21.RenderAssetManager);
4902
+ const startsAt = Internals21.useMediaStartsAt();
4903
+ const sequenceContext = useContext6(Internals21.SequenceContext);
4690
4904
  const id = useMemo5(() => `media-video-${random2(src)}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.relativeFrom}-${sequenceContext?.durationInFrames}`, [
4691
4905
  src,
4692
4906
  sequenceContext?.cumulatedFrom,
@@ -4697,8 +4911,8 @@ var VideoForRendering = ({
4697
4911
  const { delayRender, continueRender, cancelRender: cancelRender3 } = useDelayRender2();
4698
4912
  const canvasRef = useRef3(null);
4699
4913
  const [replaceWithOffthreadVideo, setReplaceWithOffthreadVideo] = useState5(false);
4700
- const audioEnabled = Internals17.useAudioEnabled();
4701
- const videoEnabled = Internals17.useVideoEnabled();
4914
+ const audioEnabled = Internals21.useAudioEnabled();
4915
+ const videoEnabled = Internals21.useVideoEnabled();
4702
4916
  const maxCacheSize = useMaxMediaCacheSize(logLevel);
4703
4917
  const [error, setError] = useState5(null);
4704
4918
  if (error) {
@@ -4762,7 +4976,7 @@ var VideoForRendering = ({
4762
4976
  return;
4763
4977
  }
4764
4978
  if (window.remotion_isMainTab) {
4765
- Internals17.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
4979
+ Internals21.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
4766
4980
  }
4767
4981
  setReplaceWithOffthreadVideo({
4768
4982
  durationInSeconds: mediaDurationInSeconds
@@ -4817,12 +5031,12 @@ var VideoForRendering = ({
4817
5031
  frame,
4818
5032
  startsAt
4819
5033
  });
4820
- const volume = Internals17.evaluateVolume({
5034
+ const volume = Internals21.evaluateVolume({
4821
5035
  volume: volumeProp,
4822
5036
  frame: volumePropsFrame,
4823
5037
  mediaVolume: 1
4824
5038
  });
4825
- Internals17.warnAboutTooHighVolume(volume);
5039
+ Internals21.warnAboutTooHighVolume(volume);
4826
5040
  if (audio && volume > 0) {
4827
5041
  applyVolume(audio.data, volume);
4828
5042
  registerRenderAsset({
@@ -4878,10 +5092,10 @@ var VideoForRendering = ({
4878
5092
  onError
4879
5093
  ]);
4880
5094
  const classNameValue = useMemo5(() => {
4881
- return [Internals17.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals17.truthy).join(" ");
5095
+ return [Internals21.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals21.truthy).join(" ");
4882
5096
  }, [className]);
4883
5097
  if (replaceWithOffthreadVideo) {
4884
- const fallback = /* @__PURE__ */ jsx5(Internals17.InnerOffthreadVideo, {
5098
+ const fallback = /* @__PURE__ */ jsx5(Internals21.InnerOffthreadVideo, {
4885
5099
  src,
4886
5100
  playbackRate: playbackRate ?? 1,
4887
5101
  muted: muted ?? false,
@@ -4921,7 +5135,7 @@ var VideoForRendering = ({
4921
5135
  }
4922
5136
  return /* @__PURE__ */ jsx5(Loop, {
4923
5137
  layout: "none",
4924
- durationInFrames: Internals17.calculateMediaDuration({
5138
+ durationInFrames: Internals21.calculateMediaDuration({
4925
5139
  trimAfter: trimAfterValue,
4926
5140
  mediaDurationInFrames: replaceWithOffthreadVideo.durationInSeconds * fps,
4927
5141
  playbackRate,
@@ -4944,7 +5158,7 @@ var VideoForRendering = ({
4944
5158
 
4945
5159
  // src/video/video.tsx
4946
5160
  import { jsx as jsx6 } from "react/jsx-runtime";
4947
- var { validateMediaTrimProps, resolveTrimProps, validateMediaProps: validateMediaProps2 } = Internals18;
5161
+ var { validateMediaTrimProps, resolveTrimProps, validateMediaProps: validateMediaProps2 } = Internals22;
4948
5162
  var InnerVideo = ({
4949
5163
  src,
4950
5164
  audioStreamIndex,
@@ -4968,6 +5182,7 @@ var InnerVideo = ({
4968
5182
  toneFrequency,
4969
5183
  showInTimeline,
4970
5184
  debugOverlay,
5185
+ debugAudioScheduling,
4971
5186
  headless,
4972
5187
  onError
4973
5188
  }) => {
@@ -5034,6 +5249,7 @@ var InnerVideo = ({
5034
5249
  disallowFallbackToOffthreadVideo,
5035
5250
  fallbackOffthreadVideoProps,
5036
5251
  debugOverlay: debugOverlay ?? false,
5252
+ debugAudioScheduling: debugAudioScheduling ?? false,
5037
5253
  headless: headless ?? false,
5038
5254
  onError
5039
5255
  });
@@ -5061,10 +5277,11 @@ var Video = ({
5061
5277
  stack,
5062
5278
  toneFrequency,
5063
5279
  debugOverlay,
5280
+ debugAudioScheduling,
5064
5281
  headless,
5065
5282
  onError
5066
5283
  }) => {
5067
- const fallbackLogLevel = Internals18.useLogLevel();
5284
+ const fallbackLogLevel = Internals22.useLogLevel();
5068
5285
  return /* @__PURE__ */ jsx6(InnerVideo, {
5069
5286
  audioStreamIndex: audioStreamIndex ?? 0,
5070
5287
  className,
@@ -5088,11 +5305,12 @@ var Video = ({
5088
5305
  toneFrequency: toneFrequency ?? 1,
5089
5306
  stack,
5090
5307
  debugOverlay: debugOverlay ?? false,
5308
+ debugAudioScheduling: debugAudioScheduling ?? false,
5091
5309
  headless: headless ?? false,
5092
5310
  onError
5093
5311
  });
5094
5312
  };
5095
- Internals18.addSequenceStackTraces(Video);
5313
+ Internals22.addSequenceStackTraces(Video);
5096
5314
 
5097
5315
  // src/index.ts
5098
5316
  var experimental_Audio = Audio;