Rust LXST telephony and media streaming for Reticulum.
rsLXST is a Rust implementation of LXST, the Lightweight Extensible Signal Transport used for real-time voice calls and other media streams over Reticulum. This is not a fork of LXST; it is LXST written in a different language with interoperability as the primary focus. Python LXST remains the source-of-truth implementation, do not treat this repository as one.
The current rsLXST is experimental and incomplete. It provides LXST wire codecs, Reticulum link media packet boundaries, a telephony runtime, and Opus stream integration for applications (such as Ratspeak).
The first public target is interoperable Opus telephony, not complete feature parity with the reference implementation LXST.
The experimental release is to cover basic voice calls, with several features still unsupported:
rnphoneparity andrnphone-rsusage.- Full Codec2 support.
- Deeper audio support: microphone/source backends, filters, AGC, etc.
- Broadcast, stream, and non-telephony LXST primitives.
Those are expected future work. They should not be implied by the first public Opus telephony release.
The current development layout requires rsReticulum as a sibling checkout
because rsLXST uses the Rust Reticulum crates directly:
ratspeak-src/
|-- rsReticulum/
`-- rsLXST/
If you're starting fresh:
mkdir ratspeak-src
cd ratspeak-src
git clone https://github.com/ratspeak/rsReticulum
git clone https://github.com/ratspeak/rsLXST
cd rsLXSTInstall Rust with rustup, then install Apple's command-line build tools:
xcode-select --installBuild the workspace:
cd rsLXST
cargo build --releaseInstall Rust with rustup, then install the usual build packages.
Debian, Ubuntu, and Raspberry Pi OS:
sudo apt update
sudo apt install -y build-essential pkg-configFedora:
sudo dnf install gcc make pkgconf-pkg-configArch:
sudo pacman -S --needed base-devel pkgconfBuild the workspace:
cd rsLXST
cargo build --releaseInstall Rust with the MSVC toolchain. If Rust or Cargo asks for Visual Studio Build Tools, install the "Desktop development with C++" workload.
Build from PowerShell:
cd rsLXST
cargo build --releaseRun the workspace test gate:
cargo test --workspaceRun the local CI gate:
cargo fmt --all -- --check
cargo clippy --workspace -- -D warnings
cargo test --workspaceThe test gate covers wire codecs, telephony state, profile metadata, Opus
stream boundaries, malformed-input handling, the local service runtime, Python
LXST wire parity, Reticulum destination parity, and live headless LXST
Telephone interop. The Python tests expect upstream LXST at ../upstream/LXST
or LXST_UPSTREAM_DIR, and upstream Reticulum at ../upstream/Reticulum,
RETICULUM_UPSTREAM_DIR, or sibling ../rsReticulum.
For full Python Opus media interop, install a native Opus runtime as well as the Python reference dependencies:
python -m pip install numpy cryptography pyserial cffi| Crate | Purpose |
|---|---|
lxst-core |
LXST constants, telephony profiles, signalling values, codec IDs, MessagePack packets, Raw audio frames, Opus encode/decode state, stream packetization, synthetic sources, and jitter buffers. This crate has no Reticulum runtime dependency. |
lxst-rns |
The Reticulum link-packet boundary for no-receipt LXST signalling and media over active links. It packs outbound LXST packets and decodes inbound link plaintext into typed LXST packet/frame events. |
lxst-telephony |
The telephony runtime and service layer. It owns call state, caller policy, Reticulum destination registration, announce discovery, outgoing link establishment, typed control/event channels, Opus transmit/receive stream boundaries, timeout handling, and shutdown teardown. |
Applications normally use lxst-telephony through TelephonyService, not by
manually translating Reticulum events. The service registers the local
lxst.telephony destination, emits startup/periodic announces, owns the call
runtime, and exposes typed control and event channels.
use lxst_core::Profile;
use lxst_telephony::{TelephonyControl, TelephonyService};
use tokio::time::Duration;
let parts = TelephonyService::registered(transport_tx, &identity)?;
let control_tx = parts.control_tx.clone();
let mut event_rx = parts.event_rx;
tokio::spawn(parts.service.run());
control_tx
.send(TelephonyControl::Call {
remote_identity,
profile: Some(Profile::QualityMedium),
discovery_timeout: Duration::from_secs(8),
})
.await?;The service event stream is the app-facing state source. Use
TelephonyServiceEvent::Snapshot, IncomingCall, OutgoingCallPending,
OutgoingCallStarted, OutgoingCallFailed, CallTerminated, stream lifecycle
events, and media events instead of inferring call state from raw Reticulum
traffic. Outgoing announce/path discovery runs asynchronously inside the
service, so an unreachable or non-LXST peer does not block hangup, announce,
media, or shutdown controls while discovery times out.
For Opus calls, applications supply and receive RawAudioFrame values through
StartOpusStream and StartOpusReceiveStream. rsLXST enforces the negotiated
LXST profile and reports profile changes, source/sink closure, frame drops, and
call-end stream shutdown explicitly.
Applications still own platform integration:
- contact or peer lookup
- UI and call controls
- microphone/camera/speaker permissions
- device selection
- audio session lifecycle
- capture/playback and resampling into
RawAudioFrame - settings persistence
- mobile foreground/background behavior
Ratspeak uses this boundary for its native voice-call feature.
If the issue or contribution belongs upstream as well, start there. Python LXST and Reticulum remain the reference implementations.
PRs are closed for now until I have time to catch up on everything.
Licensed under the GNU Affero General Public License v3.0 or later. See LICENSE.