[feat](trx-rs): receive SSTV pictures end to end
CI / lint (pull_request) Successful in 2m16s
CI / frontend (pull_request) Successful in 4m12s
CI / reuse (pull_request) Successful in 2s
CI / lint (push) Successful in 2m15s
CI / test (pull_request) Successful in 9m37s
CI / test (push) Successful in 7m36s
CI / frontend (push) Failing after 31s
CI / reuse (push) Successful in 3s
CI / lint (pull_request) Successful in 2m16s
CI / frontend (pull_request) Successful in 4m12s
CI / reuse (pull_request) Successful in 2s
CI / lint (push) Successful in 2m15s
CI / test (pull_request) Successful in 9m37s
CI / test (push) Successful in 7m36s
CI / frontend (push) Failing after 31s
CI / reuse (push) Successful in 3s
Wires the SSTV decoder into the stack, from the audio the server already has to a panel in the browser that shows the picture arriving. Server: a decoder task alongside the WEFAX one, running whenever the decoder is enabled and the rig is in a mode SSTV is sent in. A finished picture is written to the cache as a PNG and sent on as a message; the rows are sent as they decode, so a client can watch two minutes of Martin M1 fill in rather than waiting for it. Pictures join the decode history, are replayed to a client that connects later, and survive a restart. Protocol: SetSstvDecodeEnabled and ResetSstvDecoder, a sstv_decode _enabled flag in the rig state, two audio message types, and Sstv and SstvProgress on DecodedMessage. The history stores the message without its base64 payload -- the picture is already on disk, and a megabyte per entry is not what a history is for. Client: pictures land in their own history, and the PNG the server sent is written to the local cache so /sstv-images/ can serve it back. That endpoint and the WEFAX one now share their filename checks rather than each carrying a copy: no separators, no parent references, .png only. Web UI: an SSTV sub-tab beside WEFAX, with a live canvas the rows paint into at the line number they carry, a card for the last picture, and a filterable history with links to the files. Rows below the one arriving are grey rather than black -- not yet received is a different thing from received as black. A picture is not a spot, so neither pictures nor their progress updates reach the decode statistics; that exclusion list had grown by hand for LRPT and WEFAX and is now one named set. The decoder crate gains what the server needed to hand a picture on: to_png, to_png_base64 and save_png, with file names stamped in UTC so they sort. Panel behaviour is tested with the plugin runtime: rows painting at their own line numbers rather than in arrival order, a completed picture linked by file name alone with no server path in the page, a cut-off picture reported as partial, clearing, and the toggle following the rig state. Signed-off-by: Stan Grams <sjg@haxx.space>
This commit was merged in pull request #44.
This commit is contained in:
@@ -932,7 +932,7 @@ function elementById(id) {
|
||||
["Overview", ["overview"]],
|
||||
["Marine & packet", ["ais", "vdes", "aprs", "hf-aprs"]],
|
||||
["Weak signal", ["cw", "ft8", "ft4", "ft2", "wspr"]],
|
||||
["Broadcast & images", ["rds", "sat", "wefax"]]
|
||||
["Broadcast & images", ["rds", "sat", "wefax", "sstv"]]
|
||||
];
|
||||
groups.forEach(([label, ids]) => {
|
||||
const group = document.createElement("optgroup");
|
||||
@@ -1748,6 +1748,7 @@ var pluginGroups = {
|
||||
"/background-decode.js",
|
||||
"/sat.js",
|
||||
"/wefax.js",
|
||||
"/sstv.js",
|
||||
"/ais.js",
|
||||
"/vdes.js",
|
||||
"/aprs.js",
|
||||
@@ -2240,7 +2241,7 @@ function currentDecodeHistoryRetentionMs() {
|
||||
}
|
||||
window.getDecodeHistoryRetentionMs = currentDecodeHistoryRetentionMs;
|
||||
window.applyDecodeHistoryRetention = function() {
|
||||
for (const decoder of ["aprs", "hf_aprs", "ais", "vdes", "ft8", "ft4", "ft2", "wspr", "wefax"]) {
|
||||
for (const decoder of ["aprs", "hf_aprs", "ais", "vdes", "ft8", "ft4", "ft2", "wspr", "wefax", "sstv"]) {
|
||||
window.trxPluginRuntime.prune(decoder);
|
||||
}
|
||||
};
|
||||
@@ -4820,6 +4821,9 @@ function render(update) {
|
||||
for (const [key, entry] of Object.entries(_decoderToggles)) {
|
||||
syncDecoderToggle(entry, !!update[key], entry.label);
|
||||
}
|
||||
if (typeof update.sstv_decode_enabled === "boolean" && window.syncSstvToggle) {
|
||||
window.syncSstvToggle(update.sstv_decode_enabled);
|
||||
}
|
||||
if (typeof update.wefax_decode_enabled === "boolean" && window.syncWefaxToggle) {
|
||||
window.syncWefaxToggle(update.wefax_decode_enabled);
|
||||
}
|
||||
@@ -7594,9 +7598,17 @@ function updateDecodeStatus(text) {
|
||||
if (el && el.textContent !== "Receiving") el.textContent = text;
|
||||
}
|
||||
}
|
||||
var IMAGE_DECODE_KINDS = /* @__PURE__ */ new Set([
|
||||
"lrpt_image",
|
||||
"lrpt_progress",
|
||||
"wefax",
|
||||
"wefax_progress",
|
||||
"sstv",
|
||||
"sstv_progress"
|
||||
]);
|
||||
function dispatchDecodeMessage(msg, skipStats = false) {
|
||||
if (msg.type) window.trxPluginRuntime.dispatch(msg.type, msg);
|
||||
if (!skipStats && msg.type && msg.type !== "lrpt_image" && msg.type !== "lrpt_progress" && msg.type !== "wefax" && msg.type !== "wefax_progress") {
|
||||
if (!skipStats && msg.type && !IMAGE_DECODE_KINDS.has(msg.type)) {
|
||||
window.trx.modules.map?.statsRecordDecode(msg.type, msg.rig_id || msg.remote || null);
|
||||
window.trx.modules.map?.scheduleStatsRender();
|
||||
}
|
||||
@@ -7642,7 +7654,7 @@ function loadDecodeHistoryOnMainThread(onReady, onError) {
|
||||
}
|
||||
function restoreDecodeHistoryGroup(kind, messages) {
|
||||
if (!Array.isArray(messages) || messages.length === 0) return;
|
||||
if (kind !== "lrpt_image" && kind !== "lrpt_progress" && kind !== "wefax" && kind !== "wefax_progress") {
|
||||
if (!IMAGE_DECODE_KINDS.has(kind)) {
|
||||
for (const msg of messages) {
|
||||
window.trx.modules.map?.statsRecordDecode(kind, msg.rig_id || msg.remote || null, msg.ts_ms || void 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user