mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-15 17:12:59 -04:00
ffmpreg
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -78,8 +78,8 @@
|
||||
<script defer src="https://analytics.otter.land/script.js" data-website-id="82dd56a5-db44-4279-bd1e-a4d9fee39af7" data-domains="rover.otter.land"></script>
|
||||
<script defer src="https://analytics.otter.land/recorder.js" data-website-id="82dd56a5-db44-4279-bd1e-a4d9fee39af7" data-domains="rover.otter.land" data-sample-rate="0.15" data-mask-level="moderate" data-max-duration="300000"></script>
|
||||
<title>Roomba Rover</title>
|
||||
<script type="module" crossorigin src="/assets/index-BnruAIv2.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-s_YS9lA-.css">
|
||||
<script type="module" crossorigin src="/assets/index-DF69h8i3.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-MAURNhur.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -52,6 +52,18 @@ const state = {
|
||||
status: null,
|
||||
light: null,
|
||||
ir: null,
|
||||
publisher: {
|
||||
running: false,
|
||||
pid: null,
|
||||
startedAt: null,
|
||||
restartAt: null,
|
||||
restartCount: 0,
|
||||
exitCode: null,
|
||||
exitSignal: null,
|
||||
exitedAt: null,
|
||||
lastStderr: '',
|
||||
lastEvent: 'idle',
|
||||
},
|
||||
};
|
||||
|
||||
let onvifCam = null;
|
||||
@@ -61,6 +73,7 @@ let turnTimer = null;
|
||||
let blockedTimer = null;
|
||||
let publisherProcess = null;
|
||||
let publisherRestartTimer = null;
|
||||
let publisherStderrSyncTimer = null;
|
||||
let snapshotTimer = null;
|
||||
let spotlightVerifyTimer = null;
|
||||
let vendorStatePromise = Promise.resolve();
|
||||
@@ -73,6 +86,27 @@ function emitChange(reason = 'change') {
|
||||
events.emit('change', { reason, state: getPublicState() });
|
||||
}
|
||||
|
||||
function schedulePublisherStateSync(reason = 'publisher') {
|
||||
/*
|
||||
ffmpeg can print many warning/progress lines in bursts. Keep the latest text
|
||||
in state immediately, but debounce session sync so one noisy transcoder does
|
||||
not force every connected client to resync for each stderr chunk.
|
||||
*/
|
||||
if (publisherStderrSyncTimer) return;
|
||||
publisherStderrSyncTimer = setTimeout(() => {
|
||||
publisherStderrSyncTimer = null;
|
||||
emitChange(reason);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function updatePublisherState(patch = {}, reason = 'publisher') {
|
||||
state.publisher = {
|
||||
...(state.publisher || {}),
|
||||
...patch,
|
||||
};
|
||||
emitChange(reason);
|
||||
}
|
||||
|
||||
function clampUnit(value) {
|
||||
const number = Number(value) || 0;
|
||||
return Math.max(-1, Math.min(1, number));
|
||||
@@ -186,6 +220,7 @@ function getPublicState(socket = null) {
|
||||
status: state.status,
|
||||
light: state.light,
|
||||
ir: state.ir,
|
||||
publisher: state.publisher,
|
||||
isOperator: Boolean(socketId && state.operatorSocketId === socketId),
|
||||
queuedPosition: socketId ? state.queue.indexOf(socketId) + 1 || null : null,
|
||||
canUse: socket ? canUsePtzFeature(socket) : false,
|
||||
@@ -249,6 +284,12 @@ function stopPublisher() {
|
||||
} catch {}
|
||||
publisherProcess = null;
|
||||
}
|
||||
updatePublisherState({
|
||||
running: false,
|
||||
pid: null,
|
||||
restartAt: null,
|
||||
lastEvent: 'stopped',
|
||||
}, 'publisher-stop');
|
||||
}
|
||||
|
||||
function startPublisher() {
|
||||
@@ -337,13 +378,42 @@ function startPublisher() {
|
||||
output,
|
||||
], { stdio: ['ignore', 'ignore', 'pipe'] });
|
||||
publisherProcess = proc;
|
||||
updatePublisherState({
|
||||
running: true,
|
||||
pid: proc.pid || null,
|
||||
startedAt: Date.now(),
|
||||
restartAt: null,
|
||||
exitCode: null,
|
||||
exitSignal: null,
|
||||
exitedAt: null,
|
||||
lastEvent: 'started',
|
||||
}, 'publisher-start');
|
||||
proc.stderr.on('data', (chunk) => {
|
||||
const text = String(chunk || '').trim();
|
||||
if (text) logger.warn('publisher stderr', { text: text.slice(0, 500) });
|
||||
if (!text) return;
|
||||
const lastStderr = text.slice(-1000);
|
||||
state.publisher = {
|
||||
...(state.publisher || {}),
|
||||
lastStderr,
|
||||
lastEvent: 'stderr',
|
||||
};
|
||||
logger.warn('publisher stderr', { text: text.slice(0, 500) });
|
||||
schedulePublisherStateSync('publisher-stderr');
|
||||
});
|
||||
proc.on('exit', (code, signal) => {
|
||||
if (publisherProcess === proc) publisherProcess = null;
|
||||
logger.warn('publisher exited', { code, signal });
|
||||
const restartAt = enabled && state.rtspUri ? Date.now() + 1500 : null;
|
||||
updatePublisherState({
|
||||
running: false,
|
||||
pid: null,
|
||||
restartAt,
|
||||
restartCount: Number(state.publisher?.restartCount || 0) + (restartAt ? 1 : 0),
|
||||
exitCode: code,
|
||||
exitSignal: signal,
|
||||
exitedAt: Date.now(),
|
||||
lastEvent: restartAt ? 'restarting' : 'exited',
|
||||
}, 'publisher-exit');
|
||||
if (enabled && state.rtspUri) {
|
||||
publisherRestartTimer = setTimeout(() => {
|
||||
publisherRestartTimer = null;
|
||||
|
||||
@@ -107,6 +107,12 @@ function PtzQueueList({ queue = [], operatorLabel = '' }) {
|
||||
function PtzStatePanel({ ptz, onClose, onRelease, releaseDisabled = false }) {
|
||||
const spotlightOn = isSpotlightOn(ptz?.light);
|
||||
const irMode = normalizeIrMode(ptz?.ir?.state);
|
||||
const publisher = ptz?.publisher || {};
|
||||
const publisherStatus = publisher.running
|
||||
? `running${publisher.pid ? ` ${publisher.pid}` : ''}`
|
||||
: publisher.restartAt
|
||||
? 'restarting'
|
||||
: publisher.lastEvent || 'stopped';
|
||||
const statusTone = ptz?.error ? 'text-amber-300' : ptz?.isOperator ? 'text-emerald-300' : 'text-slate-100';
|
||||
|
||||
return (
|
||||
@@ -121,6 +127,12 @@ function PtzStatePanel({ ptz, onClose, onRelease, releaseDisabled = false }) {
|
||||
<StatusRow label="Spotlight" value={spotlightOn ? 'On' : 'Off'} tone={spotlightOn ? 'text-emerald-300' : 'text-slate-200'} />
|
||||
<StatusRow label="Infrared mode" value={irMode} />
|
||||
<StatusRow label="Stream" value={ptz?.status || ptz?.error || 'idle'} tone={ptz?.error ? 'text-amber-300' : ''} />
|
||||
<StatusRow label="Transcoder" value={publisherStatus} tone={publisher.running ? 'text-emerald-300' : 'text-amber-300'} />
|
||||
{publisher.lastStderr ? (
|
||||
<div className="surface max-h-24 overflow-y-auto whitespace-pre-wrap break-words font-mono text-[0.68rem] leading-tight text-slate-200">
|
||||
{publisher.lastStderr}
|
||||
</div>
|
||||
) : null}
|
||||
{ptz?.blocked?.message ? (
|
||||
<div className="rounded border border-amber-500/50 bg-amber-950/40 p-1 text-xs text-amber-100">
|
||||
{ptz.blocked.message}
|
||||
|
||||
Reference in New Issue
Block a user