[feat](trx-rs): add client-side Opus audio recorder

Record Opus audio streams to OGG files on the client. Includes manual start/stop via HTTP API, scheduler-driven auto-recording per schedule entry, and a header REC button in the web UI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
2026-03-30 23:37:09 +02:00
parent 2296a53916
commit f2048c583c
15 changed files with 1016 additions and 5 deletions
@@ -253,7 +253,8 @@ function applyAuthRestrictions() {
"settings-clear-ft4-history",
"settings-clear-ft2-history",
"settings-clear-wspr-history",
"settings-clear-sat-history"
"settings-clear-sat-history",
"header-rec-btn"
];
pluginToggleBtns.forEach(id => {
const btn = document.getElementById(id);
@@ -3305,6 +3306,10 @@ function render(update) {
for (const [key, entry] of Object.entries(_decoderToggles)) {
syncDecoderToggle(entry, !!update[key], entry.label);
}
// Recorder state sync.
if (typeof update.recorder_enabled === "boolean" && window._syncRecorderState) {
window._syncRecorderState(update.recorder_enabled);
}
if (window.updateSatLiveState) window.updateSatLiveState(update);
const cwAutoEl = document.getElementById("cw-auto");
const cwWpmEl = document.getElementById("cw-wpm");
@@ -8852,6 +8857,31 @@ if (headerAudioToggle) {
headerAudioToggle.addEventListener("click", startRxAudio);
}
// ── Recorder button ────────────────────────────────────────────────────────
const headerRecBtn = document.getElementById("header-rec-btn");
let recorderActive = false;
function syncRecorderBtn() {
if (!headerRecBtn) return;
headerRecBtn.classList.toggle("rec-active", recorderActive);
}
if (headerRecBtn) {
headerRecBtn.addEventListener("click", async () => {
try {
if (recorderActive) {
await postPath("/api/recorder/stop");
} else {
await postPath("/api/recorder/start");
}
} catch (e) {
console.error("Recorder toggle failed", e);
}
});
}
window._syncRecorderState = function (enabled) {
recorderActive = enabled;
syncRecorderBtn();
};
const rxVolPct = document.getElementById("rx-vol-pct");
const txVolPct = document.getElementById("tx-vol-pct");