@remotion/player 4.0.458 → 4.0.460
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,5 +1,5 @@
|
|
|
1
1
|
export declare const ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT = 0.1;
|
|
2
|
-
export declare const setGlobalTimeAnchor: ({ audioContext, audioSyncAnchor, absoluteTimeInSeconds, globalPlaybackRate, logLevel, }: {
|
|
2
|
+
export declare const setGlobalTimeAnchor: ({ audioContext, audioSyncAnchor, absoluteTimeInSeconds, globalPlaybackRate, logLevel, force, }: {
|
|
3
3
|
audioContext: AudioContext;
|
|
4
4
|
audioSyncAnchor: {
|
|
5
5
|
value: number;
|
|
@@ -7,4 +7,5 @@ export declare const setGlobalTimeAnchor: ({ audioContext, audioSyncAnchor, abso
|
|
|
7
7
|
absoluteTimeInSeconds: number;
|
|
8
8
|
globalPlaybackRate: number;
|
|
9
9
|
logLevel: "error" | "info" | "trace" | "verbose" | "warn";
|
|
10
|
+
force: boolean;
|
|
10
11
|
}) => boolean;
|
|
@@ -3,17 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.setGlobalTimeAnchor = exports.ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT = void 0;
|
|
4
4
|
const remotion_1 = require("remotion");
|
|
5
5
|
exports.ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT = 0.1;
|
|
6
|
-
const setGlobalTimeAnchor = ({ audioContext, audioSyncAnchor, absoluteTimeInSeconds, globalPlaybackRate, logLevel, }) => {
|
|
6
|
+
const setGlobalTimeAnchor = ({ audioContext, audioSyncAnchor, absoluteTimeInSeconds, globalPlaybackRate, logLevel, force, }) => {
|
|
7
7
|
const newAnchor = audioContext.currentTime - absoluteTimeInSeconds / globalPlaybackRate;
|
|
8
8
|
const shift = (newAnchor - audioSyncAnchor.value) * globalPlaybackRate;
|
|
9
9
|
const { outputLatency } = audioContext;
|
|
10
10
|
const safeOutputLatency = outputLatency === 0 ? 0.3 : outputLatency;
|
|
11
11
|
const latency = audioContext.baseLatency + safeOutputLatency;
|
|
12
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) {
|
|
13
|
+
if (Math.abs(shift) < exports.ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT + latency && !force) {
|
|
14
14
|
return false;
|
|
15
15
|
}
|
|
16
|
-
remotion_1.Internals.Log.verbose({ logLevel, tag: 'audio-scheduling' }, 'Anchor
|
|
16
|
+
remotion_1.Internals.Log.verbose({ logLevel, tag: 'audio-scheduling' }, 'Anchor ' +
|
|
17
|
+
(force ? 'forcibly ' : '') +
|
|
18
|
+
'changed from %s to %s with shift %s', audioSyncAnchor.value, newAnchor, shift);
|
|
17
19
|
audioSyncAnchor.value = newAnchor;
|
|
18
20
|
return true;
|
|
19
21
|
};
|
package/dist/cjs/use-playback.js
CHANGED
|
@@ -31,6 +31,8 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
|
|
|
31
31
|
playbackRate,
|
|
32
32
|
videoConfig: config,
|
|
33
33
|
});
|
|
34
|
+
// Update time anchor when seeking:
|
|
35
|
+
// If the user clicked on a different time in the timeline, we need to re-sync the anchor
|
|
34
36
|
(0, react_1.useLayoutEffect)(() => {
|
|
35
37
|
if (!sharedAudioContext) {
|
|
36
38
|
return;
|
|
@@ -41,17 +43,58 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
|
|
|
41
43
|
if (!config) {
|
|
42
44
|
return;
|
|
43
45
|
}
|
|
46
|
+
if (muted) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
44
49
|
const changed = (0, set_global_time_anchor_js_1.setGlobalTimeAnchor)({
|
|
45
50
|
audioContext: sharedAudioContext.audioContext,
|
|
46
51
|
audioSyncAnchor: sharedAudioContext.audioSyncAnchor,
|
|
47
52
|
absoluteTimeInSeconds: frame / config.fps,
|
|
48
53
|
globalPlaybackRate: playbackRate,
|
|
49
54
|
logLevel,
|
|
55
|
+
force: false,
|
|
50
56
|
});
|
|
51
57
|
if (changed) {
|
|
52
58
|
sharedAudioContext.audioSyncAnchorEmitter.dispatch('changed');
|
|
53
59
|
}
|
|
54
|
-
}, [config, frame, logLevel, playbackRate, sharedAudioContext]);
|
|
60
|
+
}, [config, frame, logLevel, playbackRate, sharedAudioContext, muted]);
|
|
61
|
+
// When the audio context is suspended, we use the opportunity to
|
|
62
|
+
// re-anchor the time to be exact.
|
|
63
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
64
|
+
const audioContext = sharedAudioContext === null || sharedAudioContext === void 0 ? void 0 : sharedAudioContext.audioContext;
|
|
65
|
+
if (!audioContext) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (!config) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (muted) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const callback = () => {
|
|
75
|
+
if (audioContext.state !== 'running') {
|
|
76
|
+
(0, set_global_time_anchor_js_1.setGlobalTimeAnchor)({
|
|
77
|
+
audioContext,
|
|
78
|
+
audioSyncAnchor: sharedAudioContext.audioSyncAnchor,
|
|
79
|
+
absoluteTimeInSeconds: getCurrentFrame() / config.fps,
|
|
80
|
+
globalPlaybackRate: playbackRate,
|
|
81
|
+
logLevel,
|
|
82
|
+
force: true,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
audioContext === null || audioContext === void 0 ? void 0 : audioContext.addEventListener('statechange', callback);
|
|
87
|
+
return () => {
|
|
88
|
+
audioContext === null || audioContext === void 0 ? void 0 : audioContext.removeEventListener('statechange', callback);
|
|
89
|
+
};
|
|
90
|
+
}, [
|
|
91
|
+
config,
|
|
92
|
+
getCurrentFrame,
|
|
93
|
+
logLevel,
|
|
94
|
+
muted,
|
|
95
|
+
playbackRate,
|
|
96
|
+
sharedAudioContext,
|
|
97
|
+
]);
|
|
55
98
|
(0, react_2.useEffect)(() => {
|
|
56
99
|
var _a;
|
|
57
100
|
if (!config) {
|
|
@@ -88,7 +131,7 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
|
|
|
88
131
|
(_a = sharedAudioContext === null || sharedAudioContext === void 0 ? void 0 : sharedAudioContext.suspend) === null || _a === void 0 ? void 0 : _a.call(sharedAudioContext);
|
|
89
132
|
return;
|
|
90
133
|
}
|
|
91
|
-
if (!muted) {
|
|
134
|
+
if (!muted && !context.buffering.current) {
|
|
92
135
|
(_b = sharedAudioContext === null || sharedAudioContext === void 0 ? void 0 : sharedAudioContext.resume) === null || _b === void 0 ? void 0 : _b.call(sharedAudioContext);
|
|
93
136
|
}
|
|
94
137
|
const time = performance.now() - startedTime;
|
|
@@ -107,7 +150,8 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
|
|
|
107
150
|
});
|
|
108
151
|
framesAdvanced += framesToAdvance;
|
|
109
152
|
if (nextFrame !== getCurrentFrame() &&
|
|
110
|
-
(!hasEnded || moveToBeginningWhenEnded)
|
|
153
|
+
(!hasEnded || moveToBeginningWhenEnded) &&
|
|
154
|
+
!context.buffering.current) {
|
|
111
155
|
setFrame((c) => ({ ...c, [config.id]: nextFrame }));
|
|
112
156
|
}
|
|
113
157
|
if (hasEnded) {
|
|
@@ -124,31 +168,16 @@ const usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, ou
|
|
|
124
168
|
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;
|
|
125
169
|
if (getIsResumingAudioContext !== null && !muted) {
|
|
126
170
|
getIsResumingAudioContext.then(() => {
|
|
127
|
-
if (!(sharedAudioContext === null || sharedAudioContext === void 0 ? void 0 : sharedAudioContext.audioContext)) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
if (!sharedAudioContext.audioSyncAnchor) {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
// set it here and DON'T propagate an event
|
|
134
|
-
// the useLayoutEffect above is supposed to handle a user seek,
|
|
135
|
-
// this is a natural wait for the audio playback to start.
|
|
136
|
-
// we don't wanna destroy the iterators.
|
|
137
|
-
(0, set_global_time_anchor_js_1.setGlobalTimeAnchor)({
|
|
138
|
-
audioContext: sharedAudioContext.audioContext,
|
|
139
|
-
audioSyncAnchor: sharedAudioContext.audioSyncAnchor,
|
|
140
|
-
absoluteTimeInSeconds: getCurrentFrame() / config.fps,
|
|
141
|
-
globalPlaybackRate: playbackRate,
|
|
142
|
-
logLevel,
|
|
143
|
-
});
|
|
144
171
|
startedTime = performance.now();
|
|
145
172
|
framesAdvanced = 0;
|
|
146
173
|
queueNextFrame();
|
|
147
174
|
});
|
|
148
175
|
return;
|
|
149
176
|
}
|
|
150
|
-
if (context.buffering.current
|
|
151
|
-
(
|
|
177
|
+
if (context.buffering.current) {
|
|
178
|
+
if (!muted) {
|
|
179
|
+
(_b = sharedAudioContext === null || sharedAudioContext === void 0 ? void 0 : sharedAudioContext.suspend) === null || _b === void 0 ? void 0 : _b.call(sharedAudioContext);
|
|
180
|
+
}
|
|
152
181
|
const stopListening = context.listenForResume(() => {
|
|
153
182
|
stopListening.remove();
|
|
154
183
|
startedTime = performance.now();
|
package/dist/esm/index.mjs
CHANGED
|
@@ -912,17 +912,18 @@ var setGlobalTimeAnchor = ({
|
|
|
912
912
|
audioSyncAnchor,
|
|
913
913
|
absoluteTimeInSeconds,
|
|
914
914
|
globalPlaybackRate,
|
|
915
|
-
logLevel
|
|
915
|
+
logLevel,
|
|
916
|
+
force
|
|
916
917
|
}) => {
|
|
917
918
|
const newAnchor = audioContext.currentTime - absoluteTimeInSeconds / globalPlaybackRate;
|
|
918
919
|
const shift = (newAnchor - audioSyncAnchor.value) * globalPlaybackRate;
|
|
919
920
|
const { outputLatency } = audioContext;
|
|
920
921
|
const safeOutputLatency = outputLatency === 0 ? 0.3 : outputLatency;
|
|
921
922
|
const latency = audioContext.baseLatency + safeOutputLatency;
|
|
922
|
-
if (Math.abs(shift) < ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT + latency) {
|
|
923
|
+
if (Math.abs(shift) < ALLOWED_GLOBAL_TIME_ANCHOR_SHIFT + latency && !force) {
|
|
923
924
|
return false;
|
|
924
925
|
}
|
|
925
|
-
Internals6.Log.verbose({ logLevel, tag: "audio-scheduling" }, "Anchor changed from %s to %s with shift %s", audioSyncAnchor.value, newAnchor, shift);
|
|
926
|
+
Internals6.Log.verbose({ logLevel, tag: "audio-scheduling" }, "Anchor " + (force ? "forcibly " : "") + "changed from %s to %s with shift %s", audioSyncAnchor.value, newAnchor, shift);
|
|
926
927
|
audioSyncAnchor.value = newAnchor;
|
|
927
928
|
return true;
|
|
928
929
|
};
|
|
@@ -965,17 +966,56 @@ var usePlayback = ({
|
|
|
965
966
|
if (!config) {
|
|
966
967
|
return;
|
|
967
968
|
}
|
|
969
|
+
if (muted) {
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
968
972
|
const changed = setGlobalTimeAnchor({
|
|
969
973
|
audioContext: sharedAudioContext.audioContext,
|
|
970
974
|
audioSyncAnchor: sharedAudioContext.audioSyncAnchor,
|
|
971
975
|
absoluteTimeInSeconds: frame / config.fps,
|
|
972
976
|
globalPlaybackRate: playbackRate,
|
|
973
|
-
logLevel
|
|
977
|
+
logLevel,
|
|
978
|
+
force: false
|
|
974
979
|
});
|
|
975
980
|
if (changed) {
|
|
976
981
|
sharedAudioContext.audioSyncAnchorEmitter.dispatch("changed");
|
|
977
982
|
}
|
|
978
|
-
}, [config, frame, logLevel, playbackRate, sharedAudioContext]);
|
|
983
|
+
}, [config, frame, logLevel, playbackRate, sharedAudioContext, muted]);
|
|
984
|
+
useLayoutEffect2(() => {
|
|
985
|
+
const audioContext = sharedAudioContext?.audioContext;
|
|
986
|
+
if (!audioContext) {
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
if (!config) {
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
if (muted) {
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
const callback = () => {
|
|
996
|
+
if (audioContext.state !== "running") {
|
|
997
|
+
setGlobalTimeAnchor({
|
|
998
|
+
audioContext,
|
|
999
|
+
audioSyncAnchor: sharedAudioContext.audioSyncAnchor,
|
|
1000
|
+
absoluteTimeInSeconds: getCurrentFrame() / config.fps,
|
|
1001
|
+
globalPlaybackRate: playbackRate,
|
|
1002
|
+
logLevel,
|
|
1003
|
+
force: true
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
};
|
|
1007
|
+
audioContext?.addEventListener("statechange", callback);
|
|
1008
|
+
return () => {
|
|
1009
|
+
audioContext?.removeEventListener("statechange", callback);
|
|
1010
|
+
};
|
|
1011
|
+
}, [
|
|
1012
|
+
config,
|
|
1013
|
+
getCurrentFrame,
|
|
1014
|
+
logLevel,
|
|
1015
|
+
muted,
|
|
1016
|
+
playbackRate,
|
|
1017
|
+
sharedAudioContext
|
|
1018
|
+
]);
|
|
979
1019
|
useEffect5(() => {
|
|
980
1020
|
if (!config) {
|
|
981
1021
|
return;
|
|
@@ -1009,7 +1049,7 @@ var usePlayback = ({
|
|
|
1009
1049
|
sharedAudioContext?.suspend?.();
|
|
1010
1050
|
return;
|
|
1011
1051
|
}
|
|
1012
|
-
if (!muted) {
|
|
1052
|
+
if (!muted && !context.buffering.current) {
|
|
1013
1053
|
sharedAudioContext?.resume?.();
|
|
1014
1054
|
}
|
|
1015
1055
|
const time = performance.now() - startedTime;
|
|
@@ -1027,7 +1067,7 @@ var usePlayback = ({
|
|
|
1027
1067
|
shouldLoop: loop
|
|
1028
1068
|
});
|
|
1029
1069
|
framesAdvanced += framesToAdvance;
|
|
1030
|
-
if (nextFrame !== getCurrentFrame() && (!hasEnded || moveToBeginningWhenEnded)) {
|
|
1070
|
+
if (nextFrame !== getCurrentFrame() && (!hasEnded || moveToBeginningWhenEnded) && !context.buffering.current) {
|
|
1031
1071
|
setFrame((c) => ({ ...c, [config.id]: nextFrame }));
|
|
1032
1072
|
}
|
|
1033
1073
|
if (hasEnded) {
|
|
@@ -1042,27 +1082,16 @@ var usePlayback = ({
|
|
|
1042
1082
|
const getIsResumingAudioContext = sharedAudioContext?.getIsResumingAudioContext?.() ?? null;
|
|
1043
1083
|
if (getIsResumingAudioContext !== null && !muted) {
|
|
1044
1084
|
getIsResumingAudioContext.then(() => {
|
|
1045
|
-
if (!sharedAudioContext?.audioContext) {
|
|
1046
|
-
return;
|
|
1047
|
-
}
|
|
1048
|
-
if (!sharedAudioContext.audioSyncAnchor) {
|
|
1049
|
-
return;
|
|
1050
|
-
}
|
|
1051
|
-
setGlobalTimeAnchor({
|
|
1052
|
-
audioContext: sharedAudioContext.audioContext,
|
|
1053
|
-
audioSyncAnchor: sharedAudioContext.audioSyncAnchor,
|
|
1054
|
-
absoluteTimeInSeconds: getCurrentFrame() / config.fps,
|
|
1055
|
-
globalPlaybackRate: playbackRate,
|
|
1056
|
-
logLevel
|
|
1057
|
-
});
|
|
1058
1085
|
startedTime = performance.now();
|
|
1059
1086
|
framesAdvanced = 0;
|
|
1060
1087
|
queueNextFrame();
|
|
1061
1088
|
});
|
|
1062
1089
|
return;
|
|
1063
1090
|
}
|
|
1064
|
-
if (context.buffering.current
|
|
1065
|
-
|
|
1091
|
+
if (context.buffering.current) {
|
|
1092
|
+
if (!muted) {
|
|
1093
|
+
sharedAudioContext?.suspend?.();
|
|
1094
|
+
}
|
|
1066
1095
|
const stopListening = context.listenForResume(() => {
|
|
1067
1096
|
stopListening.remove();
|
|
1068
1097
|
startedTime = performance.now();
|
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.
|
|
6
|
+
"version": "4.0.460",
|
|
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.
|
|
39
|
+
"remotion": "4.0.460"
|
|
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.
|
|
53
|
+
"@remotion/eslint-config-internal": "4.0.460",
|
|
54
54
|
"eslint": "9.19.0",
|
|
55
55
|
"@typescript/native-preview": "7.0.0-dev.20260217.1"
|
|
56
56
|
},
|