@homebridge/camera-utils
Version:
Utilities to simplify homebridge camera plugin development
80 lines • 2.62 kB
JavaScript
import { spawn } from 'node:child_process';
import process from 'node:process';
import { Subject } from 'rxjs';
import { defaultFfmpegPath } from './ffmpeg.js';
const noop = () => null;
const onGlobalProcessStopped = new Subject();
// Register a single event listener, rather than listener per ffmpeg process
// This helps avoid a warning for hitting too many listeners
process.on('exit', () => onGlobalProcessStopped.next(null));
export class FfmpegProcess {
options;
ff;
processSubscription = onGlobalProcessStopped.subscribe(() => {
this.stop();
});
started = false;
stopped = false;
exited = false;
constructor(options) {
this.options = options;
this.ff = spawn(this.options.ffmpegPath || defaultFfmpegPath, this.options.ffmpegArgs.map(x => x.toString()));
const { logger, logLabel } = options;
const logError = logger?.error || noop;
const logInfo = logger?.info || noop;
const logPrefix = logLabel ? `${logLabel}: ` : '';
if (options.stdoutCallback && this.ff.stdout) {
const { stdoutCallback } = options;
this.ff.stdout.on('data', (data) => {
stdoutCallback(data);
});
}
this.ff.stderr?.on('data', (data) => {
if (!this.started) {
this.started = true;
options.startedCallback?.();
}
logInfo(logPrefix + data);
});
this.ff.stdin?.on('error', (error) => {
if (!error.message.includes('EPIPE')) {
logError(logPrefix + error.message);
}
});
this.ff.on('exit', (code, signal) => {
this.exited = true;
this.options.exitCallback?.(code, signal);
if (!code || code === 255) {
logInfo(`${logPrefix}stopped gracefully`);
}
else {
logError(`${logPrefix}exited with code ${code} and signal ${signal}`);
}
this.stop();
});
}
stop() {
if (this.stopped) {
return;
}
this.stopped = true;
this.processSubscription.unsubscribe();
this.ff.stderr?.pause();
this.ff.stdout?.pause();
if (!this.exited) {
this.ff.kill();
}
}
writeStdin(input) {
if (this.stopped) {
return;
}
if (this.ff.stdin) {
this.ff.stdin.write(input);
}
if (this.ff.stdin) {
this.ff.stdin.end();
}
}
}
//# sourceMappingURL=ffmpeg-process.js.map