openipc-core
Shared protocol code for openipc-rs.
This crate contains the parts of the OpenIPC receive path that do not need to know whether bytes came from native USB, WebUSB, a capture file, or a test fixture. It is the right dependency when you want to parse or reconstruct OpenIPC video without taking a dependency on a specific USB frontend.
What It Does
- Parse Realtek rtl88xx USB RX aggregates and 24-byte RX descriptors.
- Filter OpenIPC/WFB 802.11 frames by channel id and radio port.
- Handle WFB session packets, optional session TLVs, data decryption, and FEC recovery.
- Expose recovered non-video WFB payload bytes from telemetry, tunnel/data, audio, or custom radio ports without parsing those application protocols.
- Parse RTP and depacketize H.264/H.265 into Annex-B access units.
- Expose RTP payload bytes for app-owned sinks such as UDP forwarding or Opus audio decoding.
- Build adaptive-link feedback payloads and WFB uplink packets.
- Build radiotap + 802.11 WFB transmit frames. Hardware crates add their own USB/driver descriptors before transmission.
Basic Receive Shape
use ;
const VIDEO_ROUTE: PayloadRouteId = new;
The returned frame data is still encoded video. Feed it to WebCodecs, a native decoder, a file writer, or an RTP/Annex-B bridge depending on your application. Long-running receivers should treat per-frame WFB errors as dropped packets and continue scanning the current USB aggregate.
Payload Routes And RTP
PayloadPipeline is the lower-level channel-recovery state machine in
openipc-core. It emits recovered bytes after channel filtering, WFB session
handling, decryption, and FEC. It does not parse RTP, MAVLink, MSP, CRSF, IP,
vendor data, or any other application protocol.
Most apps should start with ReceiverRuntime. It wraps PayloadRouteManager
and the RTP depacketizer used for the configured video route. The route manager
keeps one runtime per (channel_id, key_slot) and attaches one or more route
IDs to that runtime. This avoids decrypting and FEC-recovering the same channel
twice when you want multiple outputs, such as local video display plus RTP
forwarding.
For OpenIPC video, configure one video route. Recovered payloads on that route
are treated as RTP and are turned into Annex-B H.264/H.265 frames. If you also
want RTP forwarding, ask ReceiverRuntime to tap the same route as raw payload
bytes:
use ;
const VIDEO_ROUTE: PayloadRouteId = new;
Add another route for a non-video WFB channel when you want recovered telemetry, IP/VPN, or custom bytes:
use ;
const TELEMETRY_ROUTE: PayloadRouteId = new;
RadioPort::TelemetryRx is OpenIPC's observed telemetry downlink port. That
stream may contain MAVLink, MSP/OSD, or another router-specific payload. Use
RadioPort::TunnelRx, RadioPort::AudioRx, or RadioPort::Custom(n) for other
payload channels. openipc-core does not parse MAVLink or any other telemetry
protocol. Applications can parse, display, record, or inspect those bytes later.
Audio follows the same rule, with one extra helper. OpenIPC-documented audio is
usually Opus RTP payload type 98 mixed into the main video RTP route. Use
ReceiverBatchOptions::rtp_payload_taps to copy only that payload type while
the video depacketizer keeps consuming the same route. Custom wfb-ng profiles
can also carry audio on a separate route such as RadioPort::AudioRx.
openipc-core still does not own audio playback; it only provides recovered RTP
packet bytes and metadata.
RtpDepacketizer is also conservative about fragmented video. If a fragmented
H.264/H.265 RTP access unit has a sequence gap, the partial frame is dropped and
the depacketizer waits for the next clean fragment start.
Crate Boundaries
openipc-core intentionally has no USB device ownership. Pair it with:
openipc-rtl88xxfor native or WebUSB Realtek adapter IO.openipc-webor@openipc-rs/webfor browser/WASM applications.apps/openipc-clifor CLI-style native receive-loop examples.
Status
The protocol pipeline has unit tests for parser, crypto, FEC, RTP, and uplink helpers. Live radio behavior still depends on the USB driver and adapter validation in higher-level crates.
An optional PixelPilot/wfb-ng reference test can compare Rust FEC output against
PixelPilot's vendored zfex.c implementation:
OPENIPC_PIXELPILOT_REF=/path/to/PixelPilot \
The test builds a temporary C harness, generates PixelPilot parity/recovery
vectors, and compares them with FecCode plus a WFB-shaped
PlainAssembler recovery case. It is ignored by default so normal CI does not
depend on a PixelPilot checkout or a C compiler.