107 lines
3.7 KiB
JavaScript
107 lines
3.7 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.makeIoSynchronizer = void 0;
|
|
const event_emitter_1 = require("../create/event-emitter");
|
|
const with_resolvers_1 = require("../create/with-resolvers");
|
|
const log_1 = require("../log");
|
|
const make_timeout_promise_1 = require("./make-timeout-promise");
|
|
const makeIoSynchronizer = ({ logLevel, label, controller, }) => {
|
|
const eventEmitter = new event_emitter_1.IoEventEmitter();
|
|
let lastInput = 0;
|
|
let lastOutput = 0;
|
|
let inputsSinceLastOutput = 0;
|
|
let inputs = [];
|
|
let resolvers = [];
|
|
const getQueuedItems = () => {
|
|
inputs = inputs.filter(
|
|
// In chrome, the last output sometimes shifts the timestamp by 1 macrosecond - allowing this to happen
|
|
(input) => Math.floor(input) > Math.floor(lastOutput) + 1);
|
|
return inputs.length;
|
|
};
|
|
const printState = (prefix) => {
|
|
log_1.Log.trace(logLevel, `[${label}] ${prefix}, state: Last input = ${lastInput} Last output = ${lastOutput} Inputs since last output = ${inputsSinceLastOutput}, Queue = ${getQueuedItems()}`);
|
|
};
|
|
const inputItem = (timestamp) => {
|
|
lastInput = timestamp;
|
|
inputsSinceLastOutput++;
|
|
inputs.push(timestamp);
|
|
eventEmitter.dispatchEvent('input', {
|
|
timestamp,
|
|
});
|
|
printState('Input item');
|
|
};
|
|
const onOutput = (timestamp) => {
|
|
lastOutput = timestamp;
|
|
inputsSinceLastOutput = 0;
|
|
eventEmitter.dispatchEvent('output', {
|
|
timestamp,
|
|
});
|
|
printState('Got output');
|
|
};
|
|
const waitForOutput = () => {
|
|
const { promise, resolve } = (0, with_resolvers_1.withResolvers)();
|
|
const on = () => {
|
|
eventEmitter.removeEventListener('output', on);
|
|
resolve();
|
|
resolvers = resolvers.filter((resolver) => resolver !== resolve);
|
|
};
|
|
eventEmitter.addEventListener('output', on);
|
|
resolvers.push(resolve);
|
|
return promise;
|
|
};
|
|
const makeErrorBanner = () => {
|
|
return [
|
|
`Waited too long for ${label} to finish:`,
|
|
`${getQueuedItems()} queued items`,
|
|
`inputs: ${JSON.stringify(inputs)}`,
|
|
`last output: ${lastOutput}`,
|
|
];
|
|
};
|
|
const waitForQueueSize = async (queueSize) => {
|
|
if (getQueuedItems() <= queueSize) {
|
|
return Promise.resolve();
|
|
}
|
|
const { timeoutPromise, clear } = (0, make_timeout_promise_1.makeTimeoutPromise)({
|
|
label: () => [
|
|
...makeErrorBanner(),
|
|
`wanted: <${queueSize} queued items`,
|
|
`Report this at https://remotion.dev/report`,
|
|
].join('\n'),
|
|
ms: 10000,
|
|
controller,
|
|
});
|
|
if (controller) {
|
|
controller._internals._mediaParserController._internals.signal.addEventListener('abort', clear);
|
|
}
|
|
await Promise.race([
|
|
timeoutPromise,
|
|
(async () => {
|
|
while (getQueuedItems() > queueSize) {
|
|
await waitForOutput();
|
|
}
|
|
})(),
|
|
]).finally(() => clear());
|
|
if (controller) {
|
|
controller._internals._mediaParserController._internals.signal.removeEventListener('abort', clear);
|
|
}
|
|
};
|
|
const clearQueue = () => {
|
|
inputs.length = 0;
|
|
lastInput = 0;
|
|
lastOutput = 0;
|
|
inputsSinceLastOutput = 0;
|
|
resolvers.forEach((resolver) => {
|
|
return resolver();
|
|
});
|
|
resolvers.length = 0;
|
|
inputs.length = 0;
|
|
};
|
|
return {
|
|
inputItem,
|
|
onOutput,
|
|
waitForQueueSize,
|
|
clearQueue,
|
|
};
|
|
};
|
|
exports.makeIoSynchronizer = makeIoSynchronizer;
|