remotion 4.0.404 → 4.0.406

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.
@@ -1,8 +1,41 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.AudioForPreview = void 0;
4
37
  const jsx_runtime_1 = require("react/jsx-runtime");
5
- const react_1 = require("react");
38
+ const react_1 = __importStar(require("react"));
6
39
  const SequenceContext_js_1 = require("../SequenceContext.js");
7
40
  const SequenceManager_js_1 = require("../SequenceManager.js");
8
41
  const get_cross_origin_value_js_1 = require("../get-cross-origin-value.js");
@@ -19,7 +52,7 @@ const volume_safeguard_js_1 = require("../volume-safeguard.js");
19
52
  const shared_audio_tags_js_1 = require("./shared-audio-tags.js");
20
53
  const use_audio_frame_js_1 = require("./use-audio-frame.js");
21
54
  const AudioForDevelopmentForwardRefFunction = (props, ref) => {
22
- var _a, _b, _c;
55
+ var _a, _b, _c, _d;
23
56
  const [initialShouldPreMountAudioElements] = (0, react_1.useState)(props.shouldPreMountAudioTags);
24
57
  if (props.shouldPreMountAudioTags !== initialShouldPreMountAudioElements) {
25
58
  throw new Error('Cannot change the behavior for pre-mounting audio tags dynamically.');
@@ -82,7 +115,7 @@ const AudioForDevelopmentForwardRefFunction = (props, ref) => {
82
115
  props.muted,
83
116
  props.loop,
84
117
  ]);
85
- const { el: audioRef, mediaElementSourceNode } = (0, shared_audio_tags_js_1.useSharedAudio)({
118
+ const { el: audioRef, mediaElementSourceNode, cleanupOnMediaTagUnmount, } = (0, shared_audio_tags_js_1.useSharedAudio)({
86
119
  aud: propsToPass,
87
120
  audioId: id,
88
121
  premounting: Boolean(sequenceContext === null || sequenceContext === void 0 ? void 0 : sequenceContext.premounting),
@@ -131,6 +164,25 @@ const AudioForDevelopmentForwardRefFunction = (props, ref) => {
131
164
  volume: userPreferredVolume,
132
165
  shouldUseWebAudioApi: useWebAudioApi !== null && useWebAudioApi !== void 0 ? useWebAudioApi : false,
133
166
  });
167
+ /**
168
+ * Effects in React 18 fire twice, and we are looking for a way to only fire it once.
169
+ * - useInsertionEffect only fires once. If it's available we are in React 18.
170
+ * - useLayoutEffect only fires once in React 17.
171
+ *
172
+ * Need to import it from React to fix React 17 ESM support.
173
+ */
174
+ const effectToUse = (_d = react_1.default.useInsertionEffect) !== null && _d !== void 0 ? _d : react_1.default.useLayoutEffect;
175
+ // Disconnecting the SharedElementSourceNodes if the Audio tag unmounts to prevent leak.
176
+ // https://github.com/remotion-dev/remotion/issues/6285
177
+ // But useInsertionEffect will fire before other effects, meaning the
178
+ // nodes might still be used. Using rAF to ensure it's after other effects.
179
+ effectToUse(() => {
180
+ return () => {
181
+ requestAnimationFrame(() => {
182
+ cleanupOnMediaTagUnmount();
183
+ });
184
+ };
185
+ }, [cleanupOnMediaTagUnmount]);
134
186
  (0, react_1.useImperativeHandle)(ref, () => {
135
187
  return audioRef.current;
136
188
  }, [audioRef]);
@@ -21,6 +21,7 @@ type AudioElem = {
21
21
  premounting: boolean;
22
22
  postmounting: boolean;
23
23
  audioMounted: boolean;
24
+ cleanupOnMediaTagUnmount: () => void;
24
25
  };
25
26
  type SharedContext = {
26
27
  registerAudio: (options: {
@@ -75,6 +75,7 @@ const didPropChange = (key, newProp, prevProp) => {
75
75
  };
76
76
  exports.SharedAudioContext = (0, react_1.createContext)(null);
77
77
  const SharedAudioContextProvider = ({ children, numberOfAudioTags, audioLatencyHint, audioEnabled }) => {
78
+ var _a;
78
79
  const audios = (0, react_1.useRef)([]);
79
80
  const [initialNumberOfAudioTags] = (0, react_1.useState)(numberOfAudioTags);
80
81
  if (numberOfAudioTags !== initialNumberOfAudioTags) {
@@ -101,6 +102,27 @@ const SharedAudioContextProvider = ({ children, numberOfAudioTags, audioLatencyH
101
102
  };
102
103
  });
103
104
  }, [audioContext, numberOfAudioTags]);
105
+ /**
106
+ * Effects in React 18 fire twice, and we are looking for a way to only fire it once.
107
+ * - useInsertionEffect only fires once. If it's available we are in React 18.
108
+ * - useLayoutEffect only fires once in React 17.
109
+ *
110
+ * Need to import it from React to fix React 17 ESM support.
111
+ */
112
+ const effectToUse = (_a = react_1.default.useInsertionEffect) !== null && _a !== void 0 ? _a : react_1.default.useLayoutEffect;
113
+ // Disconnecting the SharedElementSourceNodes if the Player unmounts to prevent leak.
114
+ // https://github.com/remotion-dev/remotion/issues/6285
115
+ // But useInsertionEffect will fire before other effects, meaning the
116
+ // nodes might still be used. Using rAF to ensure it's after other effects.
117
+ effectToUse(() => {
118
+ return () => {
119
+ requestAnimationFrame(() => {
120
+ refs.forEach(({ mediaElementSourceNode }) => {
121
+ mediaElementSourceNode === null || mediaElementSourceNode === void 0 ? void 0 : mediaElementSourceNode.cleanup();
122
+ });
123
+ });
124
+ };
125
+ }, [refs]);
104
126
  const takenAudios = (0, react_1.useRef)(new Array(numberOfAudioTags).fill(false));
105
127
  const rerenderAudios = (0, react_1.useCallback)(() => {
106
128
  refs.forEach(({ ref, id }) => {
@@ -152,6 +174,9 @@ const SharedAudioContextProvider = ({ children, numberOfAudioTags, audioLatencyH
152
174
  premounting,
153
175
  audioMounted: Boolean(ref.current),
154
176
  postmounting,
177
+ cleanupOnMediaTagUnmount: () => {
178
+ // Don't disconnect here, only when the Player unmounts.
179
+ },
155
180
  };
156
181
  (_b = audios.current) === null || _b === void 0 ? void 0 : _b.push(newElem);
157
182
  rerenderAudios();
@@ -256,6 +281,7 @@ const useSharedAudio = ({ aud, audioId, premounting, postmounting, }) => {
256
281
  if (ctx && ctx.numberOfAudioTags > 0) {
257
282
  return ctx.registerAudio({ aud, audioId, premounting, postmounting });
258
283
  }
284
+ // numberOfSharedAudioTags is 0
259
285
  const el = react_1.default.createRef();
260
286
  const mediaElementSourceNode = (ctx === null || ctx === void 0 ? void 0 : ctx.audioContext)
261
287
  ? (0, shared_element_source_node_js_1.makeSharedElementSourceNode)({
@@ -272,6 +298,9 @@ const useSharedAudio = ({ aud, audioId, premounting, postmounting, }) => {
272
298
  premounting,
273
299
  audioMounted: Boolean(el.current),
274
300
  postmounting,
301
+ cleanupOnMediaTagUnmount: () => {
302
+ mediaElementSourceNode === null || mediaElementSourceNode === void 0 ? void 0 : mediaElementSourceNode.cleanup();
303
+ },
275
304
  };
276
305
  });
277
306
  /**
@@ -4,5 +4,6 @@ export declare const makeSharedElementSourceNode: ({ audioContext, ref, }: {
4
4
  }) => {
5
5
  attemptToConnect: () => void;
6
6
  get: () => MediaElementAudioSourceNode;
7
+ cleanup: () => void;
7
8
  };
8
9
  export type SharedElementSourceNode = ReturnType<typeof makeSharedElementSourceNode>;
@@ -3,8 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeSharedElementSourceNode = void 0;
4
4
  const makeSharedElementSourceNode = ({ audioContext, ref, }) => {
5
5
  let connected = null;
6
+ let disposed = false;
7
+ // We must allow this to cleanup and create a new one due to strict mode.
6
8
  return {
7
9
  attemptToConnect: () => {
10
+ if (disposed) {
11
+ throw new Error('SharedElementSourceNode has been disposed');
12
+ }
8
13
  if (!connected && ref.current) {
9
14
  const mediaElementSourceNode = audioContext.createMediaElementSource(ref.current);
10
15
  connected = mediaElementSourceNode;
@@ -16,6 +21,13 @@ const makeSharedElementSourceNode = ({ audioContext, ref, }) => {
16
21
  }
17
22
  return connected;
18
23
  },
24
+ cleanup: () => {
25
+ if (connected) {
26
+ connected.disconnect();
27
+ connected = null;
28
+ }
29
+ disposed = true;
30
+ },
19
31
  };
20
32
  };
21
33
  exports.makeSharedElementSourceNode = makeSharedElementSourceNode;
@@ -1,4 +1,5 @@
1
1
  import type { DelayRenderScope } from './delay-render.js';
2
+ export declare const getErrorStackWithMessage: (error: Error) => string;
2
3
  /**
3
4
  * Internal function that accepts scope as parameter.
4
5
  * This allows useDelayRender to control its own scope source.
@@ -1,7 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getErrorStackWithMessage = void 0;
3
4
  exports.cancelRenderInternal = cancelRenderInternal;
4
5
  exports.cancelRender = cancelRender;
6
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack
7
+ const getErrorStackWithMessage = (error) => {
8
+ var _a;
9
+ const stack = (_a = error.stack) !== null && _a !== void 0 ? _a : '';
10
+ return stack.startsWith('Error:') ? stack : `${error.message}\n${stack}`;
11
+ };
12
+ exports.getErrorStackWithMessage = getErrorStackWithMessage;
5
13
  const isErrorLike = (err) => {
6
14
  if (err instanceof Error) {
7
15
  return true;
@@ -50,7 +58,7 @@ function cancelRenderInternal(scope, err) {
50
58
  error = Error('Rendering was cancelled');
51
59
  }
52
60
  if (scope) {
53
- scope.remotion_cancelledError = error.stack;
61
+ scope.remotion_cancelledError = (0, exports.getErrorStackWithMessage)(error);
54
62
  }
55
63
  throw error;
56
64
  }
@@ -49,7 +49,13 @@ const delayRenderInternal = ({ scope, environment, label, options, }) => {
49
49
  ]
50
50
  .filter(truthy_js_1.truthy)
51
51
  .join(' ');
52
- (0, cancel_render_js_1.cancelRenderInternal)(scope, Error(message));
52
+ // in client-side rendering, don't throw (would be uncaught from setTimeout)
53
+ if (environment.isClientSideRendering) {
54
+ scope.remotion_cancelledError = (0, cancel_render_js_1.getErrorStackWithMessage)(Error(message));
55
+ }
56
+ else {
57
+ (0, cancel_render_js_1.cancelRenderInternal)(scope, Error(message));
58
+ }
53
59
  }, timeoutToUse),
54
60
  };
55
61
  }
@@ -139,6 +139,7 @@ export declare const Internals: {
139
139
  premounting: boolean;
140
140
  postmounting: boolean;
141
141
  audioMounted: boolean;
142
+ cleanupOnMediaTagUnmount: () => void;
142
143
  };
143
144
  unregisterAudio: (id: number) => void;
144
145
  updateAudio: (options: {
@@ -3,4 +3,4 @@
3
3
  * @see [Documentation](https://remotion.dev/docs/version)
4
4
  * @returns {string} The current version of the remotion package
5
5
  */
6
- export declare const VERSION = "4.0.404";
6
+ export declare const VERSION = "4.0.406";
@@ -7,4 +7,4 @@ exports.VERSION = void 0;
7
7
  * @see [Documentation](https://remotion.dev/docs/version)
8
8
  * @returns {string} The current version of the remotion package
9
9
  */
10
- exports.VERSION = '4.0.404';
10
+ exports.VERSION = '4.0.406';
@@ -1,8 +1,41 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.VideoForPreview = void 0;
4
37
  const jsx_runtime_1 = require("react/jsx-runtime");
5
- const react_1 = require("react");
38
+ const react_1 = __importStar(require("react"));
6
39
  const SequenceContext_js_1 = require("../SequenceContext.js");
7
40
  const SequenceManager_js_1 = require("../SequenceManager.js");
8
41
  const shared_audio_tags_js_1 = require("../audio/shared-audio-tags.js");
@@ -24,7 +57,7 @@ const volume_safeguard_js_1 = require("../volume-safeguard.js");
24
57
  const emit_video_frame_js_1 = require("./emit-video-frame.js");
25
58
  const video_fragment_js_1 = require("./video-fragment.js");
26
59
  const VideoForDevelopmentRefForwardingFunction = (props, ref) => {
27
- var _a, _b, _c, _d, _e;
60
+ var _a, _b, _c, _d, _e, _f;
28
61
  const context = (0, react_1.useContext)(shared_audio_tags_js_1.SharedAudioContext);
29
62
  if (!context) {
30
63
  throw new Error('SharedAudioContext not found');
@@ -39,6 +72,25 @@ const VideoForDevelopmentRefForwardingFunction = (props, ref) => {
39
72
  ref: videoRef,
40
73
  });
41
74
  }, [context.audioContext]);
75
+ /**
76
+ * Effects in React 18 fire twice, and we are looking for a way to only fire it once.
77
+ * - useInsertionEffect only fires once. If it's available we are in React 18.
78
+ * - useLayoutEffect only fires once in React 17.
79
+ *
80
+ * Need to import it from React to fix React 17 ESM support.
81
+ */
82
+ const effectToUse = (_a = react_1.default.useInsertionEffect) !== null && _a !== void 0 ? _a : react_1.default.useLayoutEffect;
83
+ // Disconnecting the SharedElementSourceNodes if the tag unmounts to prevent leak.
84
+ // https://github.com/remotion-dev/remotion/issues/6285
85
+ // But useInsertionEffect will fire before other effects, meaning the
86
+ // nodes might still be used. Using rAF to ensure it's after other effects.
87
+ effectToUse(() => {
88
+ return () => {
89
+ requestAnimationFrame(() => {
90
+ sharedSource === null || sharedSource === void 0 ? void 0 : sharedSource.cleanup();
91
+ });
92
+ };
93
+ }, [sharedSource]);
42
94
  const { volume, muted, playbackRate, onlyWarnForMediaSeekingError, src, onDuration,
43
95
  // @ts-expect-error
44
96
  acceptableTimeShift, acceptableTimeShiftInSeconds, toneFrequency, name, _remotionInternalNativeLoopPassed, _remotionInternalStack, style, pauseWhenBuffering, showInTimeline, loopVolumeCurveBehavior, onError, onAutoPlayError, onVideoFrame, crossOrigin, delayRenderRetries, delayRenderTimeoutInMilliseconds, allowAmplificationDuringRender, useWebAudioApi, audioStreamIndex, ...nativeProps } = props;
@@ -53,7 +105,7 @@ const VideoForDevelopmentRefForwardingFunction = (props, ref) => {
53
105
  const logLevel = (0, log_level_context_js_1.useLogLevel)();
54
106
  const mountTime = (0, log_level_context_js_1.useMountTime)();
55
107
  const [timelineId] = (0, react_1.useState)(() => String(Math.random()));
56
- const isSequenceHidden = (_a = hidden[timelineId]) !== null && _a !== void 0 ? _a : false;
108
+ const isSequenceHidden = (_b = hidden[timelineId]) !== null && _b !== void 0 ? _b : false;
57
109
  if (typeof acceptableTimeShift !== 'undefined') {
58
110
  throw new Error('acceptableTimeShift has been removed. Use acceptableTimeShiftInSeconds instead.');
59
111
  }
@@ -70,13 +122,13 @@ const VideoForDevelopmentRefForwardingFunction = (props, ref) => {
70
122
  mediaVolume,
71
123
  mediaType: 'video',
72
124
  src,
73
- playbackRate: (_b = props.playbackRate) !== null && _b !== void 0 ? _b : 1,
125
+ playbackRate: (_c = props.playbackRate) !== null && _c !== void 0 ? _c : 1,
74
126
  displayName: name !== null && name !== void 0 ? name : null,
75
127
  id: timelineId,
76
128
  stack: _remotionInternalStack,
77
129
  showInTimeline,
78
- premountDisplay: (_c = parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.premountDisplay) !== null && _c !== void 0 ? _c : null,
79
- postmountDisplay: (_d = parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.postmountDisplay) !== null && _d !== void 0 ? _d : null,
130
+ premountDisplay: (_d = parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.premountDisplay) !== null && _d !== void 0 ? _d : null,
131
+ postmountDisplay: (_e = parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.postmountDisplay) !== null && _e !== void 0 ? _e : null,
80
132
  loopDisplay: undefined,
81
133
  });
82
134
  // putting playback before useVolume
@@ -85,7 +137,7 @@ const VideoForDevelopmentRefForwardingFunction = (props, ref) => {
85
137
  mediaRef: videoRef,
86
138
  src,
87
139
  mediaType: 'video',
88
- playbackRate: (_e = props.playbackRate) !== null && _e !== void 0 ? _e : 1,
140
+ playbackRate: (_f = props.playbackRate) !== null && _f !== void 0 ? _f : 1,
89
141
  onlyWarnForMediaSeekingError,
90
142
  acceptableTimeshift: acceptableTimeShiftInSeconds !== null && acceptableTimeShiftInSeconds !== void 0 ? acceptableTimeShiftInSeconds : null,
91
143
  isPremounting: Boolean(parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.premounting),
@@ -110,7 +110,7 @@ function truthy(value) {
110
110
  }
111
111
 
112
112
  // src/version.ts
113
- var VERSION = "4.0.404";
113
+ var VERSION = "4.0.406";
114
114
 
115
115
  // src/multiple-versions-warning.ts
116
116
  var checkMultipleRemotionVersions = () => {
@@ -1257,6 +1257,11 @@ var usePlayingState = () => {
1257
1257
  import { createContext as createContext9, useCallback as useCallback4, useContext as useContext8 } from "react";
1258
1258
 
1259
1259
  // src/cancel-render.ts
1260
+ var getErrorStackWithMessage = (error) => {
1261
+ const stack = error.stack ?? "";
1262
+ return stack.startsWith("Error:") ? stack : `${error.message}
1263
+ ${stack}`;
1264
+ };
1260
1265
  var isErrorLike = (err) => {
1261
1266
  if (err instanceof Error) {
1262
1267
  return true;
@@ -1294,7 +1299,7 @@ function cancelRenderInternal(scope, err) {
1294
1299
  error = Error("Rendering was cancelled");
1295
1300
  }
1296
1301
  if (scope) {
1297
- scope.remotion_cancelledError = error.stack;
1302
+ scope.remotion_cancelledError = getErrorStackWithMessage(error);
1298
1303
  }
1299
1304
  throw error;
1300
1305
  }
@@ -1396,7 +1401,11 @@ var delayRenderInternal = ({
1396
1401
  DELAY_RENDER_CALLSTACK_TOKEN,
1397
1402
  called
1398
1403
  ].filter(truthy).join(" ");
1399
- cancelRenderInternal(scope, Error(message));
1404
+ if (environment.isClientSideRendering) {
1405
+ scope.remotion_cancelledError = getErrorStackWithMessage(Error(message));
1406
+ } else {
1407
+ cancelRenderInternal(scope, Error(message));
1408
+ }
1400
1409
  }, timeoutToUse)
1401
1410
  };
1402
1411
  }
@@ -2979,7 +2988,7 @@ var DurationsContextProvider = ({ children }) => {
2979
2988
  };
2980
2989
 
2981
2990
  // src/audio/AudioForPreview.tsx
2982
- import {
2991
+ import React18, {
2983
2992
  forwardRef as forwardRef4,
2984
2993
  useContext as useContext25,
2985
2994
  useEffect as useEffect12,
@@ -3089,8 +3098,12 @@ var makeSharedElementSourceNode = ({
3089
3098
  ref
3090
3099
  }) => {
3091
3100
  let connected = null;
3101
+ let disposed = false;
3092
3102
  return {
3093
3103
  attemptToConnect: () => {
3104
+ if (disposed) {
3105
+ throw new Error("SharedElementSourceNode has been disposed");
3106
+ }
3094
3107
  if (!connected && ref.current) {
3095
3108
  const mediaElementSourceNode = audioContext.createMediaElementSource(ref.current);
3096
3109
  connected = mediaElementSourceNode;
@@ -3101,6 +3114,13 @@ var makeSharedElementSourceNode = ({
3101
3114
  throw new Error("Audio element not connected");
3102
3115
  }
3103
3116
  return connected;
3117
+ },
3118
+ cleanup: () => {
3119
+ if (connected) {
3120
+ connected.disconnect();
3121
+ connected = null;
3122
+ }
3123
+ disposed = true;
3104
3124
  }
3105
3125
  };
3106
3126
  };
@@ -3196,6 +3216,16 @@ var SharedAudioContextProvider = ({ children, numberOfAudioTags, audioLatencyHin
3196
3216
  };
3197
3217
  });
3198
3218
  }, [audioContext, numberOfAudioTags]);
3219
+ const effectToUse = React15.useInsertionEffect ?? React15.useLayoutEffect;
3220
+ effectToUse(() => {
3221
+ return () => {
3222
+ requestAnimationFrame(() => {
3223
+ refs.forEach(({ mediaElementSourceNode }) => {
3224
+ mediaElementSourceNode?.cleanup();
3225
+ });
3226
+ });
3227
+ };
3228
+ }, [refs]);
3199
3229
  const takenAudios = useRef6(new Array(numberOfAudioTags).fill(false));
3200
3230
  const rerenderAudios = useCallback7(() => {
3201
3231
  refs.forEach(({ ref, id }) => {
@@ -3240,7 +3270,8 @@ var SharedAudioContextProvider = ({ children, numberOfAudioTags, audioLatencyHin
3240
3270
  mediaElementSourceNode,
3241
3271
  premounting,
3242
3272
  audioMounted: Boolean(ref.current),
3243
- postmounting
3273
+ postmounting,
3274
+ cleanupOnMediaTagUnmount: () => {}
3244
3275
  };
3245
3276
  audios.current?.push(newElem);
3246
3277
  rerenderAudios();
@@ -3366,7 +3397,10 @@ var useSharedAudio = ({
3366
3397
  mediaElementSourceNode,
3367
3398
  premounting,
3368
3399
  audioMounted: Boolean(el.current),
3369
- postmounting
3400
+ postmounting,
3401
+ cleanupOnMediaTagUnmount: () => {
3402
+ mediaElementSourceNode?.cleanup();
3403
+ }
3370
3404
  };
3371
3405
  });
3372
3406
  const effectToUse = React15.useInsertionEffect ?? React15.useLayoutEffect;
@@ -4856,7 +4890,11 @@ var AudioForDevelopmentForwardRefFunction = (props, ref) => {
4856
4890
  props.muted,
4857
4891
  props.loop
4858
4892
  ]);
4859
- const { el: audioRef, mediaElementSourceNode } = useSharedAudio({
4893
+ const {
4894
+ el: audioRef,
4895
+ mediaElementSourceNode,
4896
+ cleanupOnMediaTagUnmount
4897
+ } = useSharedAudio({
4860
4898
  aud: propsToPass,
4861
4899
  audioId: id,
4862
4900
  premounting: Boolean(sequenceContext?.premounting),
@@ -4903,6 +4941,14 @@ var AudioForDevelopmentForwardRefFunction = (props, ref) => {
4903
4941
  volume: userPreferredVolume,
4904
4942
  shouldUseWebAudioApi: useWebAudioApi ?? false
4905
4943
  });
4944
+ const effectToUse = React18.useInsertionEffect ?? React18.useLayoutEffect;
4945
+ effectToUse(() => {
4946
+ return () => {
4947
+ requestAnimationFrame(() => {
4948
+ cleanupOnMediaTagUnmount();
4949
+ });
4950
+ };
4951
+ }, [cleanupOnMediaTagUnmount]);
4906
4952
  useImperativeHandle6(ref, () => {
4907
4953
  return audioRef.current;
4908
4954
  }, [audioRef]);
@@ -6571,7 +6617,7 @@ var OffthreadVideoForRendering = ({
6571
6617
  };
6572
6618
 
6573
6619
  // src/video/VideoForPreview.tsx
6574
- import {
6620
+ import React30, {
6575
6621
  forwardRef as forwardRef9,
6576
6622
  useContext as useContext33,
6577
6623
  useEffect as useEffect19,
@@ -6627,6 +6673,14 @@ var VideoForDevelopmentRefForwardingFunction = (props2, ref) => {
6627
6673
  ref: videoRef
6628
6674
  });
6629
6675
  }, [context.audioContext]);
6676
+ const effectToUse = React30.useInsertionEffect ?? React30.useLayoutEffect;
6677
+ effectToUse(() => {
6678
+ return () => {
6679
+ requestAnimationFrame(() => {
6680
+ sharedSource?.cleanup();
6681
+ });
6682
+ };
6683
+ }, [sharedSource]);
6630
6684
  const {
6631
6685
  volume,
6632
6686
  muted,
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var VERSION = "4.0.404";
2
+ var VERSION = "4.0.406";
3
3
  export {
4
4
  VERSION
5
5
  };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/core"
4
4
  },
5
5
  "name": "remotion",
6
- "version": "4.0.404",
6
+ "version": "4.0.406",
7
7
  "description": "Make videos programmatically",
8
8
  "main": "dist/cjs/index.js",
9
9
  "types": "dist/cjs/index.d.ts",
@@ -34,7 +34,7 @@
34
34
  "react-dom": "19.2.3",
35
35
  "webpack": "5.96.1",
36
36
  "zod": "3.22.3",
37
- "@remotion/eslint-config-internal": "4.0.404",
37
+ "@remotion/eslint-config-internal": "4.0.406",
38
38
  "eslint": "9.19.0"
39
39
  },
40
40
  "keywords": [