@remotion/player 4.0.450 → 4.0.452

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.
@@ -23,7 +23,7 @@ const componentOrNullIfLazy = (props) => {
23
23
  return null;
24
24
  };
25
25
  exports.componentOrNullIfLazy = componentOrNullIfLazy;
26
- const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps, inputProps, style, controls = false, loop = false, autoPlay = false, showVolumeControls = true, allowFullscreen = true, clickToPlay, doubleClickToFullscreen = false, spaceKeyToPlayOrPause = true, moveToBeginningWhenEnded = true, numberOfSharedAudioTags = 5, errorFallback = () => '⚠️', playbackRate = 1, renderLoading, className, showPosterWhenUnplayed, showPosterWhenEnded, showPosterWhenPaused, showPosterWhenBuffering, showPosterWhenBufferingAndPaused, initialFrame, renderPoster, inFrame, outFrame, initiallyShowControls, renderFullscreenButton, renderPlayPauseButton, renderVolumeSlider, renderCustomControls, alwaysShowControls = false, initiallyMuted = false, showPlaybackRateControl = false, posterFillMode = 'player-size', bufferStateDelayInMilliseconds, hideControlsWhenPointerDoesntMove = true, overflowVisible = false, renderMuteButton, browserMediaControlsBehavior: passedBrowserMediaControlsBehavior, overrideInternalClassName, logLevel = 'info', noSuspense, acknowledgeRemotionLicense, audioLatencyHint = 'interactive', volumePersistenceKey, ...componentProps }, ref) => {
26
+ const PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps, inputProps, style, controls = false, loop = false, autoPlay = false, showVolumeControls = true, allowFullscreen = true, clickToPlay, doubleClickToFullscreen = false, spaceKeyToPlayOrPause = true, moveToBeginningWhenEnded = true, numberOfSharedAudioTags = 5, errorFallback = () => '⚠️', playbackRate = 1, renderLoading, className, showPosterWhenUnplayed, showPosterWhenEnded, showPosterWhenPaused, showPosterWhenBuffering, showPosterWhenBufferingAndPaused, initialFrame, renderPoster, inFrame, outFrame, initiallyShowControls, renderFullscreenButton, renderPlayPauseButton, renderVolumeSlider, renderCustomControls, alwaysShowControls = false, initiallyMuted = false, showPlaybackRateControl = false, posterFillMode = 'player-size', bufferStateDelayInMilliseconds, hideControlsWhenPointerDoesntMove = true, overflowVisible = false, renderMuteButton, browserMediaControlsBehavior: passedBrowserMediaControlsBehavior, overrideInternalClassName, logLevel = 'info', noSuspense, acknowledgeRemotionLicense, audioLatencyHint = 'playback', volumePersistenceKey, ...componentProps }, ref) => {
27
27
  if (typeof window !== 'undefined') {
28
28
  window.remotion_isPlayer = true;
29
29
  }
@@ -83,6 +83,6 @@ const SharedPlayerContexts = ({ children, timelineContext, fps, compositionHeigh
83
83
  isReadOnlyStudio: false,
84
84
  };
85
85
  }, []);
86
- return (jsx_runtime_1.jsx(remotion_1.Internals.RemotionEnvironmentContext.Provider, { value: env, children: jsx_runtime_1.jsx(remotion_1.Internals.LogLevelContext.Provider, { value: logLevelContext, children: jsx_runtime_1.jsx(remotion_1.Internals.CanUseRemotionHooksProvider, { children: jsx_runtime_1.jsx(remotion_1.Internals.AbsoluteTimeContext.Provider, { value: timelineContext, children: jsx_runtime_1.jsx(remotion_1.Internals.TimelineContext.Provider, { value: timelineContext, children: jsx_runtime_1.jsx(remotion_1.Internals.CompositionManager.Provider, { value: compositionManagerContext, children: jsx_runtime_1.jsx(remotion_1.Internals.PrefetchProvider, { children: jsx_runtime_1.jsx(remotion_1.Internals.DurationsContextProvider, { children: jsx_runtime_1.jsx(remotion_1.Internals.MediaVolumeContext.Provider, { value: mediaVolumeContextValue, children: jsx_runtime_1.jsx(remotion_1.Internals.SetMediaVolumeContext.Provider, { value: setMediaVolumeContextValue, children: jsx_runtime_1.jsx(remotion_1.Internals.SharedAudioContextProvider, { numberOfAudioTags: numberOfSharedAudioTags, audioLatencyHint: audioLatencyHint, audioEnabled: audioEnabled, children: jsx_runtime_1.jsx(remotion_1.Internals.BufferingProvider, { children: children }) }) }) }) }) }) }) }) }) }) }) }));
86
+ return (jsx_runtime_1.jsx(remotion_1.Internals.RemotionEnvironmentContext.Provider, { value: env, children: jsx_runtime_1.jsx(remotion_1.Internals.LogLevelContext.Provider, { value: logLevelContext, children: jsx_runtime_1.jsx(remotion_1.Internals.CanUseRemotionHooksProvider, { children: jsx_runtime_1.jsx(remotion_1.Internals.AbsoluteTimeContext.Provider, { value: timelineContext, children: jsx_runtime_1.jsx(remotion_1.Internals.TimelineContext.Provider, { value: timelineContext, children: jsx_runtime_1.jsx(remotion_1.Internals.CompositionManager.Provider, { value: compositionManagerContext, children: jsx_runtime_1.jsx(remotion_1.Internals.PrefetchProvider, { children: jsx_runtime_1.jsx(remotion_1.Internals.DurationsContextProvider, { children: jsx_runtime_1.jsx(remotion_1.Internals.MediaVolumeContext.Provider, { value: mediaVolumeContextValue, children: jsx_runtime_1.jsx(remotion_1.Internals.SetMediaVolumeContext.Provider, { value: setMediaVolumeContextValue, children: jsx_runtime_1.jsx(remotion_1.Internals.BufferingProvider, { children: jsx_runtime_1.jsx(remotion_1.Internals.SharedAudioContextProvider, { audioLatencyHint: audioLatencyHint, audioEnabled: audioEnabled, children: jsx_runtime_1.jsx(remotion_1.Internals.SharedAudioTagsContextProvider, { numberOfAudioTags: numberOfSharedAudioTags, children: children }) }) }) }) }) }) }) }) }) }) }) }) }));
87
87
  };
88
88
  exports.SharedPlayerContexts = SharedPlayerContexts;
@@ -0,0 +1,10 @@
1
+ export declare const ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT = 0.1;
2
+ export declare const setGlobalTimeAnchor: ({ audioContext, audioSyncAnchor, absoluteTimeInSeconds, globalPlaybackRate, logLevel, }: {
3
+ audioContext: AudioContext;
4
+ audioSyncAnchor: {
5
+ value: number;
6
+ };
7
+ absoluteTimeInSeconds: number;
8
+ globalPlaybackRate: number;
9
+ logLevel: "error" | "info" | "trace" | "verbose" | "warn";
10
+ }) => boolean;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setGlobalTimeAnchor = exports.ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT = void 0;
4
+ const remotion_1 = require("remotion");
5
+ exports.ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT = 0.1;
6
+ const setGlobalTimeAnchor = ({ audioContext, audioSyncAnchor, absoluteTimeInSeconds, globalPlaybackRate, logLevel, }) => {
7
+ const newAnchor = audioContext.currentTime - absoluteTimeInSeconds / globalPlaybackRate;
8
+ const shift = (newAnchor - audioSyncAnchor.value) * globalPlaybackRate;
9
+ const { outputLatency } = audioContext;
10
+ const safeOutputLatency = outputLatency === 0 ? 0.3 : outputLatency;
11
+ const latency = audioContext.baseLatency + safeOutputLatency;
12
+ // Skip small shifts to avoid audio glitches from frame-quantized re-anchoring
13
+ if (Math.abs(shift) < exports.ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT + latency) {
14
+ return false;
15
+ }
16
+ remotion_1.Internals.Log.verbose({ logLevel, tag: 'audio-scheduling' }, 'Anchor changed from %s to %s with shift %s', audioSyncAnchor.value, newAnchor, shift);
17
+ audioSyncAnchor.value = newAnchor;
18
+ return true;
19
+ };
20
+ exports.setGlobalTimeAnchor = setGlobalTimeAnchor;
@@ -1,24 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.usePlayback = void 0;
4
- /* eslint-disable @typescript-eslint/no-use-before-define */
5
4
  const react_1 = require("react");
5
+ /* eslint-disable @typescript-eslint/no-use-before-define */
6
+ const react_2 = require("react");
6
7
  const remotion_1 = require("remotion");
7
8
  const browser_mediasession_js_1 = require("./browser-mediasession.js");
8
9
  const calculate_next_frame_js_1 = require("./calculate-next-frame.js");
9
10
  const is_backgrounded_js_1 = require("./is-backgrounded.js");
11
+ const set_global_time_anchor_js_1 = require("./set-global-time-anchor.js");
10
12
  const use_player_js_1 = require("./use-player.js");
11
13
  const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, outFrame, browserMediaControlsBehavior, getCurrentFrame, }) => {
12
14
  const config = remotion_1.Internals.useUnsafeVideoConfig();
13
15
  const frame = remotion_1.Internals.Timeline.useTimelinePosition();
14
16
  const { playing, pause, emitter, isPlaying } = (0, use_player_js_1.usePlayer)();
15
17
  const setFrame = remotion_1.Internals.Timeline.useTimelineSetFrame();
18
+ const sharedAudioContext = (0, react_2.useContext)(remotion_1.Internals.SharedAudioContext);
19
+ const logLevel = remotion_1.Internals.useLogLevel();
20
+ const timelineContext = remotion_1.Internals.useTimelineContext();
16
21
  // requestAnimationFrame() does not work if the tab is not active.
17
22
  // This means that audio will keep playing even if it has ended.
18
23
  // In that case, we use setTimeout() instead.
19
24
  const isBackgroundedRef = (0, is_backgrounded_js_1.useIsBackgrounded)();
20
- const lastTimeUpdateEvent = (0, react_1.useRef)(null);
21
- const context = (0, react_1.useContext)(remotion_1.Internals.BufferingContextReact);
25
+ const lastTimeUpdateTimestamp = (0, react_2.useRef)(0);
26
+ const context = (0, react_2.useContext)(remotion_1.Internals.BufferingContextReact);
22
27
  if (!context) {
23
28
  throw new Error('Missing the buffering context. Most likely you have a Remotion version mismatch.');
24
29
  }
@@ -27,12 +32,40 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
27
32
  playbackRate,
28
33
  videoConfig: config,
29
34
  });
30
- // complete code for media session API
31
- (0, react_1.useEffect)(() => {
35
+ (0, react_1.useLayoutEffect)(() => {
36
+ if (!sharedAudioContext) {
37
+ return;
38
+ }
39
+ if (!sharedAudioContext.audioContext) {
40
+ return;
41
+ }
42
+ if (!config) {
43
+ return;
44
+ }
45
+ const changed = (0, set_global_time_anchor_js_1.setGlobalTimeAnchor)({
46
+ audioContext: sharedAudioContext.audioContext,
47
+ audioSyncAnchor: sharedAudioContext.audioSyncAnchor,
48
+ absoluteTimeInSeconds: frame / config.fps,
49
+ globalPlaybackRate: timelineContext.playbackRate,
50
+ logLevel,
51
+ });
52
+ if (changed) {
53
+ sharedAudioContext.audioSyncAnchorEmitter.dispatch('changed');
54
+ }
55
+ }, [
56
+ config,
57
+ frame,
58
+ logLevel,
59
+ sharedAudioContext,
60
+ timelineContext.playbackRate,
61
+ ]);
62
+ (0, react_2.useEffect)(() => {
63
+ var _a;
32
64
  if (!config) {
33
65
  return;
34
66
  }
35
67
  if (!playing) {
68
+ (_a = sharedAudioContext === null || sharedAudioContext === void 0 ? void 0 : sharedAudioContext.suspend) === null || _a === void 0 ? void 0 : _a.call(sharedAudioContext);
36
69
  return;
37
70
  }
38
71
  let hasBeenStopped = false;
@@ -54,12 +87,15 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
54
87
  cancelQueuedFrame();
55
88
  };
56
89
  const callback = () => {
90
+ var _a, _b;
57
91
  if (hasBeenStopped) {
58
92
  return;
59
93
  }
60
94
  if (!isPlaying()) {
95
+ (_a = sharedAudioContext === null || sharedAudioContext === void 0 ? void 0 : sharedAudioContext.suspend) === null || _a === void 0 ? void 0 : _a.call(sharedAudioContext);
61
96
  return;
62
97
  }
98
+ (_b = sharedAudioContext === null || sharedAudioContext === void 0 ? void 0 : sharedAudioContext.resume) === null || _b === void 0 ? void 0 : _b.call(sharedAudioContext);
63
99
  const time = performance.now() - startedTime;
64
100
  const actualLastFrame = outFrame !== null && outFrame !== void 0 ? outFrame : config.durationInFrames - 1;
65
101
  const actualFirstFrame = inFrame !== null && inFrame !== void 0 ? inFrame : 0;
@@ -88,7 +124,36 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
88
124
  queueNextFrame();
89
125
  };
90
126
  const queueNextFrame = () => {
127
+ var _a, _b;
128
+ var _c;
129
+ const getIsResumingAudioContext = (_c = (_a = sharedAudioContext === null || sharedAudioContext === void 0 ? void 0 : sharedAudioContext.getIsResumingAudioContext) === null || _a === void 0 ? void 0 : _a.call(sharedAudioContext)) !== null && _c !== void 0 ? _c : null;
130
+ if (getIsResumingAudioContext !== null) {
131
+ getIsResumingAudioContext.then(() => {
132
+ if (!(sharedAudioContext === null || sharedAudioContext === void 0 ? void 0 : sharedAudioContext.audioContext)) {
133
+ return;
134
+ }
135
+ if (!sharedAudioContext.audioSyncAnchor) {
136
+ return;
137
+ }
138
+ // set it here and DON'T propagate an event
139
+ // the useLayoutEffect above is supposed to handle a user seek,
140
+ // this is a natural wait for the audio playback to start.
141
+ // we don't wanna destroy the iterators.
142
+ (0, set_global_time_anchor_js_1.setGlobalTimeAnchor)({
143
+ audioContext: sharedAudioContext.audioContext,
144
+ audioSyncAnchor: sharedAudioContext.audioSyncAnchor,
145
+ absoluteTimeInSeconds: getCurrentFrame() / config.fps,
146
+ globalPlaybackRate: timelineContext.playbackRate,
147
+ logLevel,
148
+ });
149
+ startedTime = performance.now();
150
+ framesAdvanced = 0;
151
+ queueNextFrame();
152
+ });
153
+ return;
154
+ }
91
155
  if (context.buffering.current) {
156
+ (_b = sharedAudioContext === null || sharedAudioContext === void 0 ? void 0 : sharedAudioContext.suspend) === null || _b === void 0 ? void 0 : _b.call(sharedAudioContext);
92
157
  const stopListening = context.listenForResume(() => {
93
158
  stopListening.remove();
94
159
  startedTime = performance.now();
@@ -137,18 +202,25 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
137
202
  getCurrentFrame,
138
203
  context,
139
204
  isPlaying,
205
+ sharedAudioContext,
206
+ timelineContext.playbackRate,
207
+ logLevel,
140
208
  ]);
141
- (0, react_1.useEffect)(() => {
142
- const interval = setInterval(() => {
143
- if (lastTimeUpdateEvent.current === getCurrentFrame()) {
144
- return;
145
- }
146
- emitter.dispatchTimeUpdate({ frame: getCurrentFrame() });
147
- lastTimeUpdateEvent.current = getCurrentFrame();
148
- }, 250);
149
- return () => clearInterval(interval);
150
- }, [emitter, getCurrentFrame]);
151
- (0, react_1.useEffect)(() => {
209
+ (0, react_2.useEffect)(() => {
210
+ const now = performance.now();
211
+ const timeSinceLastUpdate = now - lastTimeUpdateTimestamp.current;
212
+ if (timeSinceLastUpdate >= 250) {
213
+ emitter.dispatchTimeUpdate({ frame });
214
+ lastTimeUpdateTimestamp.current = now;
215
+ return;
216
+ }
217
+ const timeoutId = setTimeout(() => {
218
+ emitter.dispatchTimeUpdate({ frame });
219
+ lastTimeUpdateTimestamp.current = performance.now();
220
+ }, 250 - timeSinceLastUpdate);
221
+ return () => clearTimeout(timeoutId);
222
+ }, [emitter, frame]);
223
+ (0, react_2.useEffect)(() => {
152
224
  emitter.dispatchFrameUpdate({ frame });
153
225
  }, [emitter, frame]);
154
226
  };
@@ -13,6 +13,7 @@ const usePlayer = () => {
13
13
  const setFrame = remotion_1.Internals.Timeline.useTimelineSetFrame();
14
14
  const setTimelinePosition = remotion_1.Internals.Timeline.useTimelineSetFrame();
15
15
  const audioContext = (0, react_1.useContext)(remotion_1.Internals.SharedAudioContext);
16
+ const audioTagsContext = (0, react_1.useContext)(remotion_1.Internals.SharedAudioTagsContext);
16
17
  const { audioAndVideoTags } = remotion_1.Internals.useTimelineContext();
17
18
  const frameRef = (0, react_1.useRef)(frame);
18
19
  frameRef.current = frame;
@@ -38,7 +39,6 @@ const usePlayer = () => {
38
39
  emitter.dispatchSeek(newFrame);
39
40
  }, [emitter, setTimelinePosition, video === null || video === void 0 ? void 0 : video.id]);
40
41
  const play = (0, react_1.useCallback)((e) => {
41
- var _a;
42
42
  if (imperativePlaying.current) {
43
43
  return;
44
44
  }
@@ -46,12 +46,12 @@ const usePlayer = () => {
46
46
  if (isLastFrame) {
47
47
  seek(0);
48
48
  }
49
- (_a = audioContext === null || audioContext === void 0 ? void 0 : audioContext.audioContext) === null || _a === void 0 ? void 0 : _a.resume();
49
+ audioContext === null || audioContext === void 0 ? void 0 : audioContext.resume();
50
50
  /**
51
51
  * Play silent audio tags to warm them up for autoplay
52
52
  */
53
- if (audioContext && audioContext.numberOfAudioTags > 0 && e) {
54
- audioContext.playAllAudios();
53
+ if (audioTagsContext && audioTagsContext.numberOfAudioTags > 0 && e) {
54
+ audioTagsContext.playAllAudios();
55
55
  }
56
56
  /**
57
57
  * Play audios and videos directly here so they can benefit from
@@ -66,18 +66,18 @@ const usePlayer = () => {
66
66
  imperativePlaying,
67
67
  isLastFrame,
68
68
  audioContext,
69
+ audioTagsContext,
69
70
  setPlaying,
70
71
  emitter,
71
72
  seek,
72
73
  audioAndVideoTags,
73
74
  ]);
74
75
  const pause = (0, react_1.useCallback)(() => {
75
- var _a;
76
76
  if (imperativePlaying.current) {
77
77
  imperativePlaying.current = false;
78
78
  setPlaying(false);
79
79
  emitter.dispatchPause();
80
- (_a = audioContext === null || audioContext === void 0 ? void 0 : audioContext.audioContext) === null || _a === void 0 ? void 0 : _a.suspend();
80
+ audioContext === null || audioContext === void 0 ? void 0 : audioContext.suspend();
81
81
  }
82
82
  }, [emitter, imperativePlaying, setPlaying, audioContext]);
83
83
  const pauseAndReturnToPlayStart = (0, react_1.useCallback)(() => {
@@ -5,11 +5,11 @@ const validatePlaybackRate = (playbackRate) => {
5
5
  if (playbackRate === undefined) {
6
6
  return;
7
7
  }
8
- if (playbackRate > 4) {
9
- throw new Error(`The highest possible playback rate is 4. You passed: ${playbackRate}`);
8
+ if (playbackRate > 10) {
9
+ throw new Error(`The highest possible playback rate is 10. You passed: ${playbackRate}`);
10
10
  }
11
- if (playbackRate < -4) {
12
- throw new Error(`The lowest possible playback rate is -4. You passed: ${playbackRate}`);
11
+ if (playbackRate < -10) {
12
+ throw new Error(`The lowest possible playback rate is -10. You passed: ${playbackRate}`);
13
13
  }
14
14
  if (playbackRate === 0) {
15
15
  throw new Error(`A playback rate of 0 is not supported.`);
@@ -552,8 +552,9 @@ var useHoverState = (ref, hideControlsWhenPointerDoesntMove) => {
552
552
  };
553
553
 
554
554
  // src/use-playback.ts
555
+ import { useLayoutEffect as useLayoutEffect2 } from "react";
555
556
  import { useContext as useContext4, useEffect as useEffect5, useRef as useRef5 } from "react";
556
- import { Internals as Internals6 } from "remotion";
557
+ import { Internals as Internals7 } from "remotion";
557
558
 
558
559
  // src/browser-mediasession.ts
559
560
  import { useEffect as useEffect3, useRef as useRef3 } from "react";
@@ -569,6 +570,7 @@ var usePlayer = () => {
569
570
  const setFrame = Internals5.Timeline.useTimelineSetFrame();
570
571
  const setTimelinePosition = Internals5.Timeline.useTimelineSetFrame();
571
572
  const audioContext = useContext3(Internals5.SharedAudioContext);
573
+ const audioTagsContext = useContext3(Internals5.SharedAudioTagsContext);
572
574
  const { audioAndVideoTags } = Internals5.useTimelineContext();
573
575
  const frameRef = useRef2(frame);
574
576
  frameRef.current = frame;
@@ -601,9 +603,9 @@ var usePlayer = () => {
601
603
  if (isLastFrame) {
602
604
  seek(0);
603
605
  }
604
- audioContext?.audioContext?.resume();
605
- if (audioContext && audioContext.numberOfAudioTags > 0 && e) {
606
- audioContext.playAllAudios();
606
+ audioContext?.resume();
607
+ if (audioTagsContext && audioTagsContext.numberOfAudioTags > 0 && e) {
608
+ audioTagsContext.playAllAudios();
607
609
  }
608
610
  audioAndVideoTags.current.forEach((a) => a.play("player play() was called and playing audio from a click"));
609
611
  imperativePlaying.current = true;
@@ -614,6 +616,7 @@ var usePlayer = () => {
614
616
  imperativePlaying,
615
617
  isLastFrame,
616
618
  audioContext,
619
+ audioTagsContext,
617
620
  setPlaying,
618
621
  emitter,
619
622
  seek,
@@ -624,7 +627,7 @@ var usePlayer = () => {
624
627
  imperativePlaying.current = false;
625
628
  setPlaying(false);
626
629
  emitter.dispatchPause();
627
- audioContext?.audioContext?.suspend();
630
+ audioContext?.suspend();
628
631
  }
629
632
  }, [emitter, imperativePlaying, setPlaying, audioContext]);
630
633
  const pauseAndReturnToPlayStart = useCallback2(() => {
@@ -901,6 +904,29 @@ var useIsBackgrounded = () => {
901
904
  return isBackgrounded;
902
905
  };
903
906
 
907
+ // src/set-global-time-anchor.ts
908
+ import { Internals as Internals6 } from "remotion";
909
+ var ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT = 0.1;
910
+ var setGlobalTimeAnchor = ({
911
+ audioContext,
912
+ audioSyncAnchor,
913
+ absoluteTimeInSeconds,
914
+ globalPlaybackRate,
915
+ logLevel
916
+ }) => {
917
+ const newAnchor = audioContext.currentTime - absoluteTimeInSeconds / globalPlaybackRate;
918
+ const shift = (newAnchor - audioSyncAnchor.value) * globalPlaybackRate;
919
+ const { outputLatency } = audioContext;
920
+ const safeOutputLatency = outputLatency === 0 ? 0.3 : outputLatency;
921
+ const latency = audioContext.baseLatency + safeOutputLatency;
922
+ if (Math.abs(shift) < ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT + latency) {
923
+ return false;
924
+ }
925
+ Internals6.Log.verbose({ logLevel, tag: "audio-scheduling" }, "Anchor changed from %s to %s with shift %s", audioSyncAnchor.value, newAnchor, shift);
926
+ audioSyncAnchor.value = newAnchor;
927
+ return true;
928
+ };
929
+
904
930
  // src/use-playback.ts
905
931
  var usePlayback = ({
906
932
  loop,
@@ -911,13 +937,16 @@ var usePlayback = ({
911
937
  browserMediaControlsBehavior,
912
938
  getCurrentFrame
913
939
  }) => {
914
- const config = Internals6.useUnsafeVideoConfig();
915
- const frame = Internals6.Timeline.useTimelinePosition();
940
+ const config = Internals7.useUnsafeVideoConfig();
941
+ const frame = Internals7.Timeline.useTimelinePosition();
916
942
  const { playing, pause, emitter, isPlaying } = usePlayer();
917
- const setFrame = Internals6.Timeline.useTimelineSetFrame();
943
+ const setFrame = Internals7.Timeline.useTimelineSetFrame();
944
+ const sharedAudioContext = useContext4(Internals7.SharedAudioContext);
945
+ const logLevel = Internals7.useLogLevel();
946
+ const timelineContext = Internals7.useTimelineContext();
918
947
  const isBackgroundedRef = useIsBackgrounded();
919
- const lastTimeUpdateEvent = useRef5(null);
920
- const context = useContext4(Internals6.BufferingContextReact);
948
+ const lastTimeUpdateTimestamp = useRef5(0);
949
+ const context = useContext4(Internals7.BufferingContextReact);
921
950
  if (!context) {
922
951
  throw new Error("Missing the buffering context. Most likely you have a Remotion version mismatch.");
923
952
  }
@@ -926,11 +955,39 @@ var usePlayback = ({
926
955
  playbackRate,
927
956
  videoConfig: config
928
957
  });
958
+ useLayoutEffect2(() => {
959
+ if (!sharedAudioContext) {
960
+ return;
961
+ }
962
+ if (!sharedAudioContext.audioContext) {
963
+ return;
964
+ }
965
+ if (!config) {
966
+ return;
967
+ }
968
+ const changed = setGlobalTimeAnchor({
969
+ audioContext: sharedAudioContext.audioContext,
970
+ audioSyncAnchor: sharedAudioContext.audioSyncAnchor,
971
+ absoluteTimeInSeconds: frame / config.fps,
972
+ globalPlaybackRate: timelineContext.playbackRate,
973
+ logLevel
974
+ });
975
+ if (changed) {
976
+ sharedAudioContext.audioSyncAnchorEmitter.dispatch("changed");
977
+ }
978
+ }, [
979
+ config,
980
+ frame,
981
+ logLevel,
982
+ sharedAudioContext,
983
+ timelineContext.playbackRate
984
+ ]);
929
985
  useEffect5(() => {
930
986
  if (!config) {
931
987
  return;
932
988
  }
933
989
  if (!playing) {
990
+ sharedAudioContext?.suspend?.();
934
991
  return;
935
992
  }
936
993
  let hasBeenStopped = false;
@@ -955,8 +1012,10 @@ var usePlayback = ({
955
1012
  return;
956
1013
  }
957
1014
  if (!isPlaying()) {
1015
+ sharedAudioContext?.suspend?.();
958
1016
  return;
959
1017
  }
1018
+ sharedAudioContext?.resume?.();
960
1019
  const time = performance.now() - startedTime;
961
1020
  const actualLastFrame = outFrame ?? config.durationInFrames - 1;
962
1021
  const actualFirstFrame = inFrame ?? 0;
@@ -984,7 +1043,30 @@ var usePlayback = ({
984
1043
  queueNextFrame();
985
1044
  };
986
1045
  const queueNextFrame = () => {
1046
+ const getIsResumingAudioContext = sharedAudioContext?.getIsResumingAudioContext?.() ?? null;
1047
+ if (getIsResumingAudioContext !== null) {
1048
+ getIsResumingAudioContext.then(() => {
1049
+ if (!sharedAudioContext?.audioContext) {
1050
+ return;
1051
+ }
1052
+ if (!sharedAudioContext.audioSyncAnchor) {
1053
+ return;
1054
+ }
1055
+ setGlobalTimeAnchor({
1056
+ audioContext: sharedAudioContext.audioContext,
1057
+ audioSyncAnchor: sharedAudioContext.audioSyncAnchor,
1058
+ absoluteTimeInSeconds: getCurrentFrame() / config.fps,
1059
+ globalPlaybackRate: timelineContext.playbackRate,
1060
+ logLevel
1061
+ });
1062
+ startedTime = performance.now();
1063
+ framesAdvanced = 0;
1064
+ queueNextFrame();
1065
+ });
1066
+ return;
1067
+ }
987
1068
  if (context.buffering.current) {
1069
+ sharedAudioContext?.suspend?.();
988
1070
  const stopListening = context.listenForResume(() => {
989
1071
  stopListening.remove();
990
1072
  startedTime = performance.now();
@@ -1029,18 +1111,25 @@ var usePlayback = ({
1029
1111
  isBackgroundedRef,
1030
1112
  getCurrentFrame,
1031
1113
  context,
1032
- isPlaying
1114
+ isPlaying,
1115
+ sharedAudioContext,
1116
+ timelineContext.playbackRate,
1117
+ logLevel
1033
1118
  ]);
1034
1119
  useEffect5(() => {
1035
- const interval = setInterval(() => {
1036
- if (lastTimeUpdateEvent.current === getCurrentFrame()) {
1037
- return;
1038
- }
1039
- emitter.dispatchTimeUpdate({ frame: getCurrentFrame() });
1040
- lastTimeUpdateEvent.current = getCurrentFrame();
1041
- }, 250);
1042
- return () => clearInterval(interval);
1043
- }, [emitter, getCurrentFrame]);
1120
+ const now = performance.now();
1121
+ const timeSinceLastUpdate = now - lastTimeUpdateTimestamp.current;
1122
+ if (timeSinceLastUpdate >= 250) {
1123
+ emitter.dispatchTimeUpdate({ frame });
1124
+ lastTimeUpdateTimestamp.current = now;
1125
+ return;
1126
+ }
1127
+ const timeoutId = setTimeout(() => {
1128
+ emitter.dispatchTimeUpdate({ frame });
1129
+ lastTimeUpdateTimestamp.current = performance.now();
1130
+ }, 250 - timeSinceLastUpdate);
1131
+ return () => clearTimeout(timeoutId);
1132
+ }, [emitter, frame]);
1044
1133
  useEffect5(() => {
1045
1134
  emitter.dispatchFrameUpdate({ frame });
1046
1135
  }, [emitter, frame]);
@@ -1174,12 +1263,12 @@ import {
1174
1263
  forwardRef as forwardRef2,
1175
1264
  useEffect as useEffect13,
1176
1265
  useImperativeHandle as useImperativeHandle2,
1177
- useLayoutEffect as useLayoutEffect2,
1266
+ useLayoutEffect as useLayoutEffect3,
1178
1267
  useMemo as useMemo14,
1179
1268
  useRef as useRef12,
1180
1269
  useState as useState13
1181
1270
  } from "react";
1182
- import { Composition, Internals as Internals15 } from "remotion";
1271
+ import { Composition, Internals as Internals16 } from "remotion";
1183
1272
 
1184
1273
  // src/player-css-classname.ts
1185
1274
  var playerCssClassname = (override) => {
@@ -1198,7 +1287,7 @@ import React10, {
1198
1287
  useRef as useRef11,
1199
1288
  useState as useState11
1200
1289
  } from "react";
1201
- import { Internals as Internals11 } from "remotion";
1290
+ import { Internals as Internals12 } from "remotion";
1202
1291
 
1203
1292
  // src/error-boundary.tsx
1204
1293
  import React3 from "react";
@@ -1341,7 +1430,7 @@ var DefaultPlayPauseButton = ({ playing, buffering }) => {
1341
1430
 
1342
1431
  // src/MediaVolumeSlider.tsx
1343
1432
  import { useCallback as useCallback5, useMemo as useMemo4, useRef as useRef6, useState as useState6 } from "react";
1344
- import { Internals as Internals7 } from "remotion";
1433
+ import { Internals as Internals8 } from "remotion";
1345
1434
 
1346
1435
  // src/render-volume-slider.tsx
1347
1436
  import React5, { useCallback as useCallback4, useMemo as useMemo3, useState as useState5 } from "react";
@@ -1455,8 +1544,8 @@ var renderDefaultVolumeSlider = (props) => {
1455
1544
  import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
1456
1545
  var VOLUME_SLIDER_WIDTH = 100;
1457
1546
  var MediaVolumeSlider = ({ displayVerticalVolumeSlider, renderMuteButton, renderVolumeSlider }) => {
1458
- const [mediaMuted, setMediaMuted] = Internals7.useMediaMutedState();
1459
- const [mediaVolume, setMediaVolume] = Internals7.useMediaVolumeState();
1547
+ const [mediaMuted, setMediaMuted] = Internals8.useMediaMutedState();
1548
+ const [mediaVolume, setMediaVolume] = Internals8.useMediaVolumeState();
1460
1549
  const [focused, setFocused] = useState6(false);
1461
1550
  const parentDivRef = useRef6(null);
1462
1551
  const inputRef = useRef6(null);
@@ -1517,7 +1606,7 @@ var MediaVolumeSlider = ({ displayVerticalVolumeSlider, renderMuteButton, render
1517
1606
  return renderMuteButton ? renderMuteButton({ muted: mediaMuted, volume: mediaVolume }) : renderDefaultMuteButton({ muted: mediaMuted, volume: mediaVolume });
1518
1607
  }, [mediaMuted, mediaVolume, renderDefaultMuteButton, renderMuteButton]);
1519
1608
  const volumeSlider = useMemo4(() => {
1520
- return (focused || hover) && !mediaMuted && !Internals7.isIosSafari() ? (renderVolumeSlider ?? renderDefaultVolumeSlider)({
1609
+ return (focused || hover) && !mediaMuted && !Internals8.isIosSafari() ? (renderVolumeSlider ?? renderDefaultVolumeSlider)({
1521
1610
  isVertical: displayVerticalVolumeSlider,
1522
1611
  volume: mediaVolume,
1523
1612
  onBlur: () => setFocused(false),
@@ -1545,7 +1634,7 @@ var MediaVolumeSlider = ({ displayVerticalVolumeSlider, renderMuteButton, render
1545
1634
 
1546
1635
  // src/PlaybackrateControl.tsx
1547
1636
  import { useCallback as useCallback6, useEffect as useEffect9, useMemo as useMemo5, useState as useState8 } from "react";
1548
- import { Internals as Internals8 } from "remotion";
1637
+ import { Internals as Internals9 } from "remotion";
1549
1638
 
1550
1639
  // src/utils/use-component-visible.ts
1551
1640
  import { useEffect as useEffect8, useRef as useRef7, useState as useState7 } from "react";
@@ -1637,7 +1726,7 @@ var PlaybackrateOption = ({ rate, onSelect, selectedRate, keyboardSelectedRate }
1637
1726
  }, rate);
1638
1727
  };
1639
1728
  var PlaybackPopup = ({ setIsComponentVisible, playbackRates, canvasSize }) => {
1640
- const { setPlaybackRate, playbackRate } = Internals8.useTimelineContext();
1729
+ const { setPlaybackRate, playbackRate } = Internals9.useTimelineContext();
1641
1730
  const [keyboardSelectedRate, setKeyboardSelectedRate] = useState8(playbackRate);
1642
1731
  useEffect9(() => {
1643
1732
  const listener = (e) => {
@@ -1739,7 +1828,7 @@ var button = {
1739
1828
  };
1740
1829
  var PlaybackrateControl = ({ playbackRates, canvasSize }) => {
1741
1830
  const { ref, isComponentVisible, setIsComponentVisible } = useComponentVisible(false);
1742
- const { playbackRate } = Internals8.useTimelineContext();
1831
+ const { playbackRate } = Internals9.useTimelineContext();
1743
1832
  const onClick = useCallback6((e) => {
1744
1833
  e.stopPropagation();
1745
1834
  e.preventDefault();
@@ -1772,7 +1861,7 @@ var PlaybackrateControl = ({ playbackRates, canvasSize }) => {
1772
1861
 
1773
1862
  // src/PlayerSeekBar.tsx
1774
1863
  import { useCallback as useCallback7, useEffect as useEffect10, useMemo as useMemo6, useRef as useRef8, useState as useState9 } from "react";
1775
- import { Internals as Internals9, interpolate } from "remotion";
1864
+ import { Internals as Internals10, interpolate } from "remotion";
1776
1865
  import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
1777
1866
  var getFrameFromX = (clientX, durationInFrames, width) => {
1778
1867
  const pos = clientX;
@@ -1816,7 +1905,7 @@ var PlayerSeekBar = ({ durationInFrames, onSeekEnd, onSeekStart, inFrame, outFra
1816
1905
  shouldApplyCssTransforms: true
1817
1906
  });
1818
1907
  const { seek, play, pause, playing } = usePlayer();
1819
- const frame = Internals9.Timeline.useTimelinePosition();
1908
+ const frame = Internals10.Timeline.useTimelinePosition();
1820
1909
  const [dragging, setDragging] = useState9({
1821
1910
  dragging: false
1822
1911
  });
@@ -1929,7 +2018,7 @@ var PlayerSeekBar = ({ durationInFrames, onSeekEnd, onSeekStart, inFrame, outFra
1929
2018
 
1930
2019
  // src/PlayerTimeLabel.tsx
1931
2020
  import { useMemo as useMemo7 } from "react";
1932
- import { Internals as Internals10 } from "remotion";
2021
+ import { Internals as Internals11 } from "remotion";
1933
2022
 
1934
2023
  // src/format-time.ts
1935
2024
  var formatTime = (timeInSeconds) => {
@@ -1941,7 +2030,7 @@ var formatTime = (timeInSeconds) => {
1941
2030
  // src/PlayerTimeLabel.tsx
1942
2031
  import { jsxs as jsxs7 } from "react/jsx-runtime";
1943
2032
  var PlayerTimeLabel = ({ durationInFrames, maxTimeLabelWidth, fps }) => {
1944
- const frame = Internals10.Timeline.useTimelinePosition();
2033
+ const frame = Internals11.Timeline.useTimelinePosition();
1945
2034
  const timeLabel = useMemo7(() => {
1946
2035
  return {
1947
2036
  color: "white",
@@ -2429,8 +2518,8 @@ var PlayerUI = ({
2429
2518
  overrideInternalClassName,
2430
2519
  noSuspense
2431
2520
  }, ref) => {
2432
- const config = Internals11.useUnsafeVideoConfig();
2433
- const video = Internals11.useVideo();
2521
+ const config = Internals12.useUnsafeVideoConfig();
2522
+ const video = Internals12.useVideo();
2434
2523
  const container = useRef11(null);
2435
2524
  const canvasSize = useElementSize(container, {
2436
2525
  triggerOnWindowResize: false,
@@ -2550,8 +2639,8 @@ var PlayerUI = ({
2550
2639
  }
2551
2640
  player.emitter.dispatchScaleChange(scale);
2552
2641
  }, [player.emitter, scale]);
2553
- const { setMediaVolume, setMediaMuted } = useContext5(Internals11.SetMediaVolumeContext);
2554
- const { mediaMuted, mediaVolume } = useContext5(Internals11.MediaVolumeContext);
2642
+ const { setMediaVolume, setMediaMuted } = useContext5(Internals12.SetMediaVolumeContext);
2643
+ const { mediaMuted, mediaVolume } = useContext5(Internals12.MediaVolumeContext);
2555
2644
  useEffect12(() => {
2556
2645
  player.emitter.dispatchVolumeChange(mediaVolume);
2557
2646
  }, [player.emitter, mediaVolume]);
@@ -2786,7 +2875,7 @@ var PlayerUI = ({
2786
2875
  VideoComponent ? /* @__PURE__ */ jsx12(ErrorBoundary, {
2787
2876
  onError,
2788
2877
  errorFallback,
2789
- children: /* @__PURE__ */ jsx12(Internals11.CurrentScaleContext.Provider, {
2878
+ children: /* @__PURE__ */ jsx12(Internals12.CurrentScaleContext.Provider, {
2790
2879
  value: currentScale,
2791
2880
  children: /* @__PURE__ */ jsx12(VideoComponent, {
2792
2881
  ...video?.props ?? {},
@@ -2869,10 +2958,10 @@ var PlayerUI_default = forwardRef(PlayerUI);
2869
2958
 
2870
2959
  // src/SharedPlayerContext.tsx
2871
2960
  import { useCallback as useCallback12, useMemo as useMemo13, useState as useState12 } from "react";
2872
- import { Internals as Internals13 } from "remotion";
2961
+ import { Internals as Internals14 } from "remotion";
2873
2962
 
2874
2963
  // src/volume-persistence.ts
2875
- import { Internals as Internals12 } from "remotion";
2964
+ import { Internals as Internals13 } from "remotion";
2876
2965
  var DEFAULT_VOLUME_PERSISTENCE_KEY = "remotion.volumePreference";
2877
2966
  var persistVolume = (volume, logLevel, volumePersistenceKey) => {
2878
2967
  if (typeof window === "undefined") {
@@ -2881,7 +2970,7 @@ var persistVolume = (volume, logLevel, volumePersistenceKey) => {
2881
2970
  try {
2882
2971
  window.localStorage.setItem(volumePersistenceKey ?? DEFAULT_VOLUME_PERSISTENCE_KEY, String(volume));
2883
2972
  } catch (e) {
2884
- Internals12.Log.error({ logLevel, tag: null }, "Could not persist volume", e);
2973
+ Internals13.Log.error({ logLevel, tag: null }, "Could not persist volume", e);
2885
2974
  }
2886
2975
  };
2887
2976
  var getPreferredVolume = (volumePersistenceKey) => {
@@ -2991,29 +3080,31 @@ var SharedPlayerContexts = ({
2991
3080
  isReadOnlyStudio: false
2992
3081
  };
2993
3082
  }, []);
2994
- return /* @__PURE__ */ jsx13(Internals13.RemotionEnvironmentContext.Provider, {
3083
+ return /* @__PURE__ */ jsx13(Internals14.RemotionEnvironmentContext.Provider, {
2995
3084
  value: env,
2996
- children: /* @__PURE__ */ jsx13(Internals13.LogLevelContext.Provider, {
3085
+ children: /* @__PURE__ */ jsx13(Internals14.LogLevelContext.Provider, {
2997
3086
  value: logLevelContext,
2998
- children: /* @__PURE__ */ jsx13(Internals13.CanUseRemotionHooksProvider, {
2999
- children: /* @__PURE__ */ jsx13(Internals13.AbsoluteTimeContext.Provider, {
3087
+ children: /* @__PURE__ */ jsx13(Internals14.CanUseRemotionHooksProvider, {
3088
+ children: /* @__PURE__ */ jsx13(Internals14.AbsoluteTimeContext.Provider, {
3000
3089
  value: timelineContext,
3001
- children: /* @__PURE__ */ jsx13(Internals13.TimelineContext.Provider, {
3090
+ children: /* @__PURE__ */ jsx13(Internals14.TimelineContext.Provider, {
3002
3091
  value: timelineContext,
3003
- children: /* @__PURE__ */ jsx13(Internals13.CompositionManager.Provider, {
3092
+ children: /* @__PURE__ */ jsx13(Internals14.CompositionManager.Provider, {
3004
3093
  value: compositionManagerContext,
3005
- children: /* @__PURE__ */ jsx13(Internals13.PrefetchProvider, {
3006
- children: /* @__PURE__ */ jsx13(Internals13.DurationsContextProvider, {
3007
- children: /* @__PURE__ */ jsx13(Internals13.MediaVolumeContext.Provider, {
3094
+ children: /* @__PURE__ */ jsx13(Internals14.PrefetchProvider, {
3095
+ children: /* @__PURE__ */ jsx13(Internals14.DurationsContextProvider, {
3096
+ children: /* @__PURE__ */ jsx13(Internals14.MediaVolumeContext.Provider, {
3008
3097
  value: mediaVolumeContextValue,
3009
- children: /* @__PURE__ */ jsx13(Internals13.SetMediaVolumeContext.Provider, {
3098
+ children: /* @__PURE__ */ jsx13(Internals14.SetMediaVolumeContext.Provider, {
3010
3099
  value: setMediaVolumeContextValue,
3011
- children: /* @__PURE__ */ jsx13(Internals13.SharedAudioContextProvider, {
3012
- numberOfAudioTags: numberOfSharedAudioTags,
3013
- audioLatencyHint,
3014
- audioEnabled,
3015
- children: /* @__PURE__ */ jsx13(Internals13.BufferingProvider, {
3016
- children
3100
+ children: /* @__PURE__ */ jsx13(Internals14.BufferingProvider, {
3101
+ children: /* @__PURE__ */ jsx13(Internals14.SharedAudioContextProvider, {
3102
+ audioLatencyHint,
3103
+ audioEnabled,
3104
+ children: /* @__PURE__ */ jsx13(Internals14.SharedAudioTagsContextProvider, {
3105
+ numberOfAudioTags: numberOfSharedAudioTags,
3106
+ children
3107
+ })
3017
3108
  })
3018
3109
  })
3019
3110
  })
@@ -3029,7 +3120,7 @@ var SharedPlayerContexts = ({
3029
3120
  };
3030
3121
 
3031
3122
  // src/use-remotion-license-acknowledge.ts
3032
- import { Internals as Internals14 } from "remotion";
3123
+ import { Internals as Internals15 } from "remotion";
3033
3124
  var warningShown = false;
3034
3125
  var acknowledgeRemotionLicenseMessage = (acknowledge, logLevel) => {
3035
3126
  if (acknowledge) {
@@ -3039,7 +3130,7 @@ var acknowledgeRemotionLicenseMessage = (acknowledge, logLevel) => {
3039
3130
  return;
3040
3131
  }
3041
3132
  warningShown = true;
3042
- Internals14.Log.warn({ logLevel, tag: null }, "Note: Some companies are required to obtain a license to use Remotion. See: https://remotion.dev/license\nPass the `acknowledgeRemotionLicense` prop to `<Player />` function to make this message disappear.");
3133
+ Internals15.Log.warn({ logLevel, tag: null }, "Note: Some companies are required to obtain a license to use Remotion. See: https://remotion.dev/license\nPass the `acknowledgeRemotionLicense` prop to `<Player />` function to make this message disappear.");
3043
3134
  };
3044
3135
 
3045
3136
  // src/utils/validate-in-out-frame.ts
@@ -3121,11 +3212,11 @@ var validatePlaybackRate = (playbackRate) => {
3121
3212
  if (playbackRate === undefined) {
3122
3213
  return;
3123
3214
  }
3124
- if (playbackRate > 4) {
3125
- throw new Error(`The highest possible playback rate is 4. You passed: ${playbackRate}`);
3215
+ if (playbackRate > 10) {
3216
+ throw new Error(`The highest possible playback rate is 10. You passed: ${playbackRate}`);
3126
3217
  }
3127
- if (playbackRate < -4) {
3128
- throw new Error(`The lowest possible playback rate is -4. You passed: ${playbackRate}`);
3218
+ if (playbackRate < -10) {
3219
+ throw new Error(`The lowest possible playback rate is -10. You passed: ${playbackRate}`);
3129
3220
  }
3130
3221
  if (playbackRate === 0) {
3131
3222
  throw new Error(`A playback rate of 0 is not supported.`);
@@ -3195,7 +3286,7 @@ var PlayerFn = ({
3195
3286
  logLevel = "info",
3196
3287
  noSuspense,
3197
3288
  acknowledgeRemotionLicense,
3198
- audioLatencyHint = "interactive",
3289
+ audioLatencyHint = "playback",
3199
3290
  volumePersistenceKey,
3200
3291
  ...componentProps
3201
3292
  }, ref) => {
@@ -3213,7 +3304,7 @@ var PlayerFn = ({
3213
3304
  throw new TypeError(`'component' must not be the 'Composition' component. Pass your own React component directly, and set the duration, fps and dimensions as separate props. See https://www.remotion.dev/docs/player/examples for an example.`);
3214
3305
  }
3215
3306
  useState13(() => acknowledgeRemotionLicenseMessage(Boolean(acknowledgeRemotionLicense), logLevel));
3216
- const component = Internals15.useLazyComponent({
3307
+ const component = Internals16.useLazyComponent({
3217
3308
  compProps: componentProps,
3218
3309
  componentName: "Player",
3219
3310
  noSuspense: Boolean(noSuspense)
@@ -3280,7 +3371,7 @@ var PlayerFn = ({
3280
3371
  }, [playbackRate]);
3281
3372
  useImperativeHandle2(ref, () => rootRef.current, []);
3282
3373
  useState13(() => {
3283
- Internals15.playbackLogging({
3374
+ Internals16.playbackLogging({
3284
3375
  logLevel,
3285
3376
  message: `[player] Mounting <Player>. User agent = ${typeof navigator === "undefined" ? "server" : navigator.userAgent}`,
3286
3377
  tag: "player",
@@ -3307,8 +3398,8 @@ var PlayerFn = ({
3307
3398
  };
3308
3399
  }, [setFrame]);
3309
3400
  if (typeof window !== "undefined") {
3310
- useLayoutEffect2(() => {
3311
- Internals15.CSSUtils.injectCSS(Internals15.CSSUtils.makeDefaultPreviewCSS(`.${playerCssClassname(overrideInternalClassName)}`, "#fff"));
3401
+ useLayoutEffect3(() => {
3402
+ Internals16.CSSUtils.injectCSS(Internals16.CSSUtils.makeDefaultPreviewCSS(`.${playerCssClassname(overrideInternalClassName)}`, "#fff"));
3312
3403
  }, [overrideInternalClassName]);
3313
3404
  }
3314
3405
  const actualInputProps = useMemo14(() => inputProps ?? {}, [inputProps]);
@@ -3317,7 +3408,7 @@ var PlayerFn = ({
3317
3408
  mode: "prevent-media-session"
3318
3409
  };
3319
3410
  }, [passedBrowserMediaControlsBehavior]);
3320
- return /* @__PURE__ */ jsx14(Internals15.IsPlayerContextProvider, {
3411
+ return /* @__PURE__ */ jsx14(Internals16.IsPlayerContextProvider, {
3321
3412
  children: /* @__PURE__ */ jsx14(SharedPlayerContexts, {
3322
3413
  timelineContext: timelineContextValue,
3323
3414
  component,
@@ -3332,7 +3423,7 @@ var PlayerFn = ({
3332
3423
  volumePersistenceKey,
3333
3424
  inputProps: actualInputProps,
3334
3425
  audioEnabled: true,
3335
- children: /* @__PURE__ */ jsx14(Internals15.SetTimelineContext.Provider, {
3426
+ children: /* @__PURE__ */ jsx14(Internals16.SetTimelineContext.Provider, {
3336
3427
  value: setTimelineContextValue,
3337
3428
  children: /* @__PURE__ */ jsx14(PlayerEmitterProvider, {
3338
3429
  currentPlaybackRate,
@@ -3388,12 +3479,12 @@ var Player = forward(PlayerFn);
3388
3479
  import {
3389
3480
  forwardRef as forwardRef4,
3390
3481
  useImperativeHandle as useImperativeHandle4,
3391
- useLayoutEffect as useLayoutEffect3,
3482
+ useLayoutEffect as useLayoutEffect4,
3392
3483
  useMemo as useMemo17,
3393
3484
  useRef as useRef14,
3394
3485
  useState as useState14
3395
3486
  } from "react";
3396
- import { Internals as Internals17, random as random2 } from "remotion";
3487
+ import { Internals as Internals18, random as random2 } from "remotion";
3397
3488
 
3398
3489
  // src/ThumbnailUI.tsx
3399
3490
  import React13, {
@@ -3404,7 +3495,7 @@ import React13, {
3404
3495
  useMemo as useMemo16,
3405
3496
  useRef as useRef13
3406
3497
  } from "react";
3407
- import { Internals as Internals16 } from "remotion";
3498
+ import { Internals as Internals17 } from "remotion";
3408
3499
 
3409
3500
  // src/use-thumbnail.ts
3410
3501
  import { useContext as useContext6, useMemo as useMemo15 } from "react";
@@ -3438,8 +3529,8 @@ var ThumbnailUI = ({
3438
3529
  noSuspense,
3439
3530
  overrideInternalClassName
3440
3531
  }, ref) => {
3441
- const config = Internals16.useUnsafeVideoConfig();
3442
- const video = Internals16.useVideo();
3532
+ const config = Internals17.useUnsafeVideoConfig();
3533
+ const video = Internals17.useVideo();
3443
3534
  const container = useRef13(null);
3444
3535
  const canvasSize = useElementSize(container, {
3445
3536
  triggerOnWindowResize: false,
@@ -3514,7 +3605,7 @@ var ThumbnailUI = ({
3514
3605
  children: VideoComponent ? /* @__PURE__ */ jsx15(ErrorBoundary, {
3515
3606
  onError,
3516
3607
  errorFallback,
3517
- children: /* @__PURE__ */ jsx15(Internals16.CurrentScaleContext.Provider, {
3608
+ children: /* @__PURE__ */ jsx15(Internals17.CurrentScaleContext.Provider, {
3518
3609
  value: currentScaleContext,
3519
3610
  children: /* @__PURE__ */ jsx15(VideoComponent, {
3520
3611
  ...video?.props ?? {},
@@ -3564,7 +3655,7 @@ var ThumbnailFn = ({
3564
3655
  ...componentProps
3565
3656
  }, ref) => {
3566
3657
  if (typeof window !== "undefined") {
3567
- useLayoutEffect3(() => {
3658
+ useLayoutEffect4(() => {
3568
3659
  window.remotion_isPlayer = true;
3569
3660
  }, []);
3570
3661
  }
@@ -3589,7 +3680,7 @@ var ThumbnailFn = ({
3589
3680
  return value;
3590
3681
  }, [frameToDisplay, thumbnailId]);
3591
3682
  useImperativeHandle4(ref, () => rootRef.current, []);
3592
- const Component = Internals17.useLazyComponent({
3683
+ const Component = Internals18.useLazyComponent({
3593
3684
  compProps: componentProps,
3594
3685
  componentName: "Thumbnail",
3595
3686
  noSuspense: Boolean(noSuspense)
@@ -3598,7 +3689,7 @@ var ThumbnailFn = ({
3598
3689
  const passedInputProps = useMemo17(() => {
3599
3690
  return inputProps ?? {};
3600
3691
  }, [inputProps]);
3601
- return /* @__PURE__ */ jsx16(Internals17.IsPlayerContextProvider, {
3692
+ return /* @__PURE__ */ jsx16(Internals18.IsPlayerContextProvider, {
3602
3693
  children: /* @__PURE__ */ jsx16(SharedPlayerContexts, {
3603
3694
  timelineContext: timelineState,
3604
3695
  component: Component,
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/player"
4
4
  },
5
5
  "name": "@remotion/player",
6
- "version": "4.0.450",
6
+ "version": "4.0.452",
7
7
  "description": "React component for embedding a Remotion preview into your app",
8
8
  "main": "dist/cjs/index.js",
9
9
  "types": "dist/cjs/index.d.ts",
@@ -36,7 +36,7 @@
36
36
  ],
37
37
  "license": "SEE LICENSE IN LICENSE.md",
38
38
  "dependencies": {
39
- "remotion": "4.0.449"
39
+ "remotion": "4.0.452"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "react": ">=16.8.0",
@@ -50,7 +50,7 @@
50
50
  "react-dom": "19.2.3",
51
51
  "webpack": "5.105.0",
52
52
  "zod": "4.3.6",
53
- "@remotion/eslint-config-internal": "4.0.449",
53
+ "@remotion/eslint-config-internal": "4.0.452",
54
54
  "eslint": "9.19.0",
55
55
  "@typescript/native-preview": "7.0.0-dev.20260217.1"
56
56
  },