remotion
Version:
Make videos programmatically
161 lines (160 loc) • 6.71 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.useMediaBuffering = void 0;
const react_1 = require("react");
const playback_logging_1 = require("./playback-logging");
const use_buffer_state_1 = require("./use-buffer-state");
const useMediaBuffering = ({ element, shouldBuffer, isPremounting, isPostmounting, logLevel, mountTime, src, }) => {
const buffer = (0, use_buffer_state_1.useBufferState)();
const [isBuffering, setIsBuffering] = (0, react_1.useState)(false);
// Buffer state based on `waiting` and `canplay`
(0, react_1.useEffect)(() => {
let cleanupFns = [];
const { current } = element;
if (!current) {
return;
}
if (!shouldBuffer) {
return;
}
if (isPremounting || isPostmounting) {
// Needed by iOS Safari which will not load by default
// and therefore not fire the canplay event.
// Be cautious about using `current.load()` as it will
// reset if a video is already playing.
// Therefore only calling it after checking if the video
// has no future data.
// Breaks on Firefox though: https://github.com/remotion-dev/remotion/issues/3915
if ((isPremounting || isPostmounting) &&
current.readyState < current.HAVE_FUTURE_DATA) {
if (!navigator.userAgent.includes('Firefox/')) {
(0, playback_logging_1.playbackLogging)({
logLevel,
message: `Calling .load() on ${current.src} because readyState is ${current.readyState} and it is not Firefox. Element is premounted ${current.playbackRate}`,
tag: 'load',
mountTime,
});
const previousPlaybackRate = current.playbackRate;
current.load();
current.playbackRate = previousPlaybackRate;
}
}
// Don't trigger buffering during premount or postmount
return;
}
const cleanup = (reason) => {
let didDoSomething = false;
cleanupFns.forEach((fn) => {
fn(reason);
didDoSomething = true;
});
cleanupFns = [];
setIsBuffering((previous) => {
if (previous) {
didDoSomething = true;
}
return false;
});
if (didDoSomething) {
(0, playback_logging_1.playbackLogging)({
logLevel,
message: `Unmarking as buffering: ${current.src}. Reason: ${reason}`,
tag: 'buffer',
mountTime,
});
}
};
const blockMedia = (reason) => {
setIsBuffering(true);
(0, playback_logging_1.playbackLogging)({
logLevel,
message: `Marking as buffering: ${current.src}. Reason: ${reason}`,
tag: 'buffer',
mountTime,
});
const { unblock } = buffer.delayPlayback();
const onCanPlay = () => {
cleanup('"canplay" was fired');
// eslint-disable-next-line @typescript-eslint/no-use-before-define
init();
};
const onError = () => {
cleanup('"error" event was occurred');
// eslint-disable-next-line @typescript-eslint/no-use-before-define
init();
};
current.addEventListener('canplay', onCanPlay, {
once: true,
});
cleanupFns.push(() => {
current.removeEventListener('canplay', onCanPlay);
});
current.addEventListener('error', onError, {
once: true,
});
cleanupFns.push(() => {
current.removeEventListener('error', onError);
});
cleanupFns.push((cleanupReason) => {
(0, playback_logging_1.playbackLogging)({
logLevel,
message: `Unblocking ${current.src} from buffer. Reason: ${cleanupReason}`,
tag: 'buffer',
mountTime,
});
unblock();
});
};
const init = () => {
if (current.readyState < current.HAVE_FUTURE_DATA) {
blockMedia(`readyState is ${current.readyState}, which is less than HAVE_FUTURE_DATA`);
// Needed by iOS Safari which will not load by default
// and therefore not fire the canplay event.
// Be cautious about using `current.load()` as it will
// reset if a video is already playing.
// Therefore only calling it after checking if the video
// has no future data.
// Breaks on Firefox though: https://github.com/remotion-dev/remotion/issues/3915
if (!navigator.userAgent.includes('Firefox/')) {
(0, playback_logging_1.playbackLogging)({
logLevel,
message: `Calling .load() on ${src} because readyState is ${current.readyState} and it is not Firefox. ${current.playbackRate}`,
tag: 'load',
mountTime,
});
const previousPlaybackRate = current.playbackRate;
current.load();
current.playbackRate = previousPlaybackRate;
}
}
else {
const onWaiting = () => {
blockMedia('"waiting" event was fired');
};
current.addEventListener('waiting', onWaiting);
cleanupFns.push(() => {
current.removeEventListener('waiting', onWaiting);
});
}
};
init();
return () => {
cleanup('element was unmounted or prop changed');
};
// dependencies array:
// `src` should be in it, because if changing the source and pausing at the same time,
// it gives the chance to load the new source.
// https://github.com/remotion-dev/remotion/issues/5218
}, [
buffer,
src,
element,
isPremounting,
isPostmounting,
logLevel,
shouldBuffer,
mountTime,
]);
return isBuffering;
};
exports.useMediaBuffering = useMediaBuffering;