[feat](trx-rs): make spectrum affordable over a slow link
CI / lint (pull_request) Successful in 2m22s
CI / test (pull_request) Successful in 8m36s
CI / frontend (push) Successful in 3m38s
CI / reuse (push) Successful in 6s
CI / frontend (pull_request) Successful in 4m27s
CI / reuse (pull_request) Successful in 6s
CI / lint (push) Successful in 2m21s
CI / test (push) Successful in 7m48s
CI / lint (pull_request) Successful in 2m22s
CI / test (pull_request) Successful in 8m36s
CI / frontend (push) Successful in 3m38s
CI / reuse (push) Successful in 6s
CI / frontend (pull_request) Successful in 4m27s
CI / reuse (pull_request) Successful in 6s
CI / lint (push) Successful in 2m21s
CI / test (push) Successful in 7m48s
Spectrum dominates the server↔client connection, and all three things that govern its cost were working against a poor link. **It was polled, one round trip per frame.** The client asked for a frame every 50 ms on a dedicated connection and waited for the reply, so the frame rate was capped at 1/RTT — on a 200 ms link, five frames a second no matter what was configured. Add SubscribeSpectrum alongside the existing SubscribeMeter: the server pushes frames from a per-rig broadcast that rig_task fills only while somebody is subscribed. A server too old to know the command answers with an error and leaves the connection usable, so the client falls back to polling on the same connection without reconnecting. **Bins were JSON floats.** 1024 bins spelled out as decimal text is around 10 KB a frame, ~200 KB/s at full rate — while the very next hop, client to browser, already sends the same information as base64 i8 in about 1.4 KB. Bins now travel base64-encoded whole dBFS, the resolution the display draws at anyway. Decoding still accepts the old array form. **Nothing was tunable.** [sdr].spectrum_fft_size and [sdr].spectrum_interval_ms replace the compile-time FFT size and cadence; [[remotes]].spectrum_interval_ms lets the client ask for less. 512 bins at 5 frames/s is roughly 3.5 KB/s against roughly 200 KB/s before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SyX26FCpMQxiBoC7r5K1A7 Signed-off-by: Stan Grams <sjg@haxx.space>
This commit was merged in pull request #51.
This commit is contained in:
@@ -18,4 +18,6 @@ pub use auth::{NoAuthValidator, SimpleTokenValidator, TokenValidator};
|
||||
pub use codec::{mode_to_string, parse_envelope, parse_mode};
|
||||
pub use decoders::{DecoderActivation, DecoderDescriptor, DECODER_REGISTRY};
|
||||
pub use mapping::{client_command_to_rig, rig_command_to_client};
|
||||
pub use types::{ClientCommand, ClientEnvelope, ClientResponse, MeterUpdate, RigEntry};
|
||||
pub use types::{
|
||||
ClientCommand, ClientEnvelope, ClientResponse, MeterUpdate, RigEntry, SpectrumFrame,
|
||||
};
|
||||
|
||||
@@ -102,7 +102,7 @@ macro_rules! define_command_mapping {
|
||||
|
||||
define_command_mapping! {
|
||||
// ── Client-only variants (no RigCommand counterpart) ─────────────
|
||||
client_only: GetRigs, GetSatPasses, SubscribeMeter;
|
||||
client_only: GetRigs, GetSatPasses, SubscribeMeter, SubscribeSpectrum;
|
||||
|
||||
// ── Unit variants (no payload) ───────────────────────────────────
|
||||
unit:
|
||||
|
||||
@@ -130,6 +130,28 @@ pub enum ClientCommand {
|
||||
/// newline-delimited `MeterUpdate` JSON frames and no further commands or
|
||||
/// regular responses are sent. Intended for a dedicated TCP connection.
|
||||
SubscribeMeter,
|
||||
/// Subscribe to a per-rig spectrum stream on this connection. Like
|
||||
/// `SubscribeMeter`, the connection becomes a one-way flow of
|
||||
/// newline-delimited `SpectrumFrame` JSON and no further commands or
|
||||
/// regular responses are sent.
|
||||
///
|
||||
/// Polling `GetSpectrum` costs a round trip per frame, which caps the frame
|
||||
/// rate at 1/RTT no matter how often the client asks; the server pushes at
|
||||
/// its own cadence instead. Clients fall back to polling when the server
|
||||
/// rejects this command.
|
||||
SubscribeSpectrum,
|
||||
}
|
||||
|
||||
/// One spectrum frame pushed by the server on a dedicated spectrum stream.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct SpectrumFrame {
|
||||
/// Rig identifier this frame belongs to.
|
||||
pub rig_id: String,
|
||||
/// The frame itself; bins travel base64-encoded (see `spectrum_wire`).
|
||||
pub spectrum: trx_core::rig::state::SpectrumData,
|
||||
/// Virtual-channel RDS state, mirroring what `GetSpectrum` returned.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub vchan_rds: Option<Vec<trx_core::rig::state::VchanRdsEntry>>,
|
||||
}
|
||||
|
||||
/// Fast meter sample pushed by the server on a dedicated meter stream.
|
||||
|
||||
Reference in New Issue
Block a user