Config Page
This commit is contained in:
@@ -77,13 +77,14 @@ class MpjpegParser {
|
||||
//
|
||||
// Events: 'frame' (Buffer) – je ein Live-JPEG
|
||||
class CameraSwitch extends EventEmitter {
|
||||
constructor({ id, device, liveSize = '640x480', liveFps = 30, hiresSize = '1280x960', hiresFps = 15, encode = 'copybsf', hiresEncode, onDemand = true, idleGraceMs = 15000 }) {
|
||||
constructor({ id, device, liveSize = '640x480', liveFps = 30, hiresSize = '1280x960', hiresFps = 15, encode = 'copybsf', hiresEncode, onDemand = true, idleGraceMs = 15000, stream = true }) {
|
||||
super();
|
||||
this.setMaxListeners(0); // beliebig viele Stream-Clients
|
||||
this.id = id;
|
||||
this.device = device;
|
||||
this.liveSize = liveSize;
|
||||
this.liveFps = liveFps;
|
||||
this.streamEnabled = stream; // UI "Aus": Kamera darf NICHT live gehen (gated _spawnLive)
|
||||
this.hiresSize = hiresSize;
|
||||
this.hiresFps = hiresFps;
|
||||
this.encode = encode; // für Live: 'copybsf' (Default) | 'mjpeg' (Re-Encode)
|
||||
@@ -104,14 +105,14 @@ class CameraSwitch extends EventEmitter {
|
||||
start() {
|
||||
// On-Demand: lazy – Live startet erst beim ersten Verbraucher (acquire()).
|
||||
if (this.onDemand) return;
|
||||
if (this.state === 'stopped' && !this.proc) this._spawnLive();
|
||||
if (this.streamEnabled && this.state === 'stopped' && !this.proc) this._spawnLive();
|
||||
}
|
||||
|
||||
// ── Verbraucher-Zählung / On-Demand ────────────────────────────────────────
|
||||
acquire() {
|
||||
this.subscribers++;
|
||||
if (this.idleTimer) { clearTimeout(this.idleTimer); this.idleTimer = null; }
|
||||
if (this.onDemand && this.state === 'stopped' && !this.lock && !this.proc) this._spawnLive();
|
||||
if (this.onDemand && this.streamEnabled && this.state === 'stopped' && !this.lock && !this.proc) this._spawnLive();
|
||||
}
|
||||
|
||||
release() {
|
||||
@@ -149,6 +150,7 @@ class CameraSwitch extends EventEmitter {
|
||||
|
||||
// ── Live-Producer (Dauerbetrieb, Auto-Restart bei Crash) ───────────────────
|
||||
_spawnLive() {
|
||||
if (!this.streamEnabled) return; // UI "Aus" → Kamera bleibt dunkel
|
||||
this.stopping = false;
|
||||
const args = [
|
||||
'-hide_banner', '-loglevel', 'warning',
|
||||
@@ -193,14 +195,49 @@ class CameraSwitch extends EventEmitter {
|
||||
}
|
||||
|
||||
_scheduleRestart() {
|
||||
if (!this.streamEnabled) return; // UI "Aus" → kein Auto-Restart
|
||||
if (this.onDemand && this.subscribers === 0) return; // niemand schaut → nicht neu starten
|
||||
if (this.restartTimer) return;
|
||||
this.restartTimer = setTimeout(() => {
|
||||
this.restartTimer = null;
|
||||
if (this.state === 'stopped' && !this.lock && (!this.onDemand || this.subscribers > 0)) this._spawnLive();
|
||||
if (this.streamEnabled && this.state === 'stopped' && !this.lock && (!this.onDemand || this.subscribers > 0)) this._spawnLive();
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
// ── Hot-Reload (config.html / POST /api/config) ────────────────────────────
|
||||
// Wendet eine neue Live-Auflösung bzw. Stream-An/Aus zur Laufzeit an, OHNE
|
||||
// Container-Restart. Nutzt die vorhandenen Bausteine (_killCurrentAndWait /
|
||||
// _spawnLive) und respektiert Lock (HD-Grab) sowie On-Demand.
|
||||
async reconfigure({ liveSize, stream } = {}) {
|
||||
if (typeof stream === 'boolean') this.streamEnabled = stream;
|
||||
|
||||
// Während eines HD-Grabs nicht eingreifen – die neue liveSize gilt nach dem
|
||||
// Grab (grabHires startet Live über _spawnLive neu, das this.liveSize liest).
|
||||
if (this.lock) { if (liveSize) this.liveSize = liveSize; return; }
|
||||
|
||||
const sizeChanged = !!liveSize && liveSize !== this.liveSize;
|
||||
if (liveSize) this.liveSize = liveSize;
|
||||
|
||||
// Stream deaktiviert → laufenden Live-Prozess stoppen, NICHT neu starten.
|
||||
if (!this.streamEnabled) {
|
||||
if (this.proc && this.state === 'live') await this._killCurrentAndWait();
|
||||
this.state = 'stopped';
|
||||
return;
|
||||
}
|
||||
|
||||
// Auflösung geändert → laufenden Prozess beenden (FD frei via close-Event).
|
||||
if (sizeChanged && this.proc && this.state === 'live') {
|
||||
await this._killCurrentAndWait();
|
||||
this.state = 'stopped';
|
||||
}
|
||||
|
||||
// (Neu) starten, wenn nichts läuft und Verbraucher da sind (On-Demand) bzw.
|
||||
// Dauerbetrieb. _spawnLive ist zusätzlich durch streamEnabled gegated.
|
||||
if (this.state === 'stopped' && !this.proc && (!this.onDemand || this.subscribers > 0)) {
|
||||
this._spawnLive();
|
||||
}
|
||||
}
|
||||
|
||||
// ── HD-Grab ────────────────────────────────────────────────────────────────
|
||||
// Wenn liveSize == hiresSize: kein Format-Wechsel nötig. Live-Frame direkt
|
||||
// zurückgeben (on-demand startet den Stream bei Bedarf). Schnell, kein Gerät-
|
||||
|
||||
Reference in New Issue
Block a user