RTL-SDR is natively supported through RemoteRF's built-in rtl_sdr schema. The base remoterf-server and remoterf-host packages include PyRtlSdr and the packaged native library. The machine that owns the physical USB dongle performs capture; clients receive a generated RtlSdr class and need no RTL-SDR installation.

Overview

RemoteRF exposes the common receive controls used by RTL2832U-based SDRs, bounded complex-sample and raw-byte reads, and device identity. This is a receive-only path: RTL-SDR hardware cannot transmit.

RTL-SDR describes a family rather than one completely uniform radio. Dongles can contain different tuners, and available native functions depend on the installed librtlsdr build. RemoteRF therefore probes optional controls when a session opens instead of assuming that bias tee, direct sampling, offset tuning, or dithering exists on every device.

The setup flow is:

  1. Optionally install the native RTL-SDR diagnostic tools on the Linux machine that owns the dongle. The Python runtime and packaged library are included with the base RemoteRF package.
  2. Verify that the same account used to run serverrf or hostrf can open the dongle locally.
  3. Register the dongle by its USB serial when possible, then restart that machine’s RemoteRF process.
  4. Reserve the device and let the client download or refresh the generated RtlSdr wrapper.

Install and Detect

Step 1

Install Diagnostic Tools

The base remoterf-server package already installs the supported Python wrapper and packaged native library. Install the command-line utilities in the same Conda environment only when you need local diagnostics. The client machine does not need them.

Run on the server or host that owns the dongle:
conda activate YOUR_REMOTERF_ENV
conda install -y -c conda-forge rtl-sdr
Why is Conda still used here? It provides the rtl_test diagnostic utility. The base RemoteRF package already includes PyRtlSdr and a compatible packaged native library, avoiding optional-symbol mismatches with an older system librtlsdr. For API details, see the official PyRtlSdr overview.
Step 2

Verify Local Detection

Connect the dongle by USB, then confirm that native discovery works before changing the RemoteRF inventory.

Run as the account that starts RemoteRF:
rtl_test -t
Expected result: The utility finds at least one RTL-SDR, opens it, identifies its tuner, and completes the test without a permissions or kernel-driver error. Copy the USB serial shown by the utility when one is available.

Manifest Example

Register by serial whenever possible. A serial remains stable when USB enumeration order changes and prevents RemoteRF from silently opening the wrong dongle.

devices.yml
yaml
devices:
  - device_id: 4
    device_type: rtl_sdr
    name: RTL-SDR FM Bench
    init:
      serial: "00000001"

Alternatively, create the same entry with the server CLI:

serverrf --device --add --rtl-sdr "4:RTL-SDR FM Bench:serial=00000001"
serverrf --device --show

If the RTL-SDR is attached to a RemoteRF Host instead, use hostrf for the add command:

hostrf --device --add --rtl-sdr "4:RTL-SDR FM Bench:serial=00000001"

If a dongle has no useful unique serial, select its current zero-based USB index instead:

serverrf --device --add --rtl-sdr "4:RTL-SDR FM Bench:index=0"

On a RemoteRF Host, the same index-based command is:

hostrf --device --add --rtl-sdr "4:RTL-SDR FM Bench:index=0"

The index form writes init.device_index: 0. Use it only when serial selection is impossible, because unplugging or adding USB devices can change enumeration order. Restart serverrf after any inventory change.

Client Usage

After reserving the RTL-SDR, let the client automatically fetch or refresh the schema-generated driver, configure the receiver, and perform a bounded synchronous read:

from remoteRF.drivers import ensure_driver

token = "reservation-token"
ensure_driver(token=token)

from remoteRF.drivers.rtl_sdr import RtlSdr

sdr = RtlSdr(token)
sdr.sample_rate = 2_048_000
sdr.center_freq = 100_000_000
sdr.gain = "auto"

samples = sdr.read_samples(16_384)
print(samples.shape, samples.dtype)

read_samples() returns normalized NumPy complex64 IQ. read_bytes() returns packed unsigned 8-bit interleaved IQ. A single response is limited to 4 MiB, so longer recordings should use repeated bounded reads and write or process each block as it arrives.

Remote callbacks are intentionally not exposed. PyRtlSdr’s asynchronous callback runs in the native process and cannot cross the RPC boundary as a normal Python callback; repeated synchronous reads provide explicit backpressure and bounded network payloads.

Troubleshooting

Common Problems
Kernel driver is busy
Linux may bind the dongle to dvb_usb_rtl28xxu. A compatible librtlsdr normally detaches it while opening the radio. If your native build cannot, unload or blacklist that DVB module before starting RemoteRF.
Permission denied
Install the RTL-SDR udev rules, reload them, reconnect the dongle, and confirm that rtl_test -t succeeds without sudo for the server account.
Undefined native symbol
An error such as undefined symbol: rtlsdr_set_dithering means PyRtlSdr loaded an incompatible native library. Reinstall or upgrade the appropriate base remoterf-server or remoterf-host package so the wrapper and packaged library agree; there is no RTL-SDR extra.
Serial not found
Rerun rtl_test -t and copy the reported serial exactly. Use index=0 only as a temporary fallback when the device has no stable serial.
Optional control fails
An optional operation may be absent for the tuner or installed librtlsdr; this is expected and is reported as NotImplementedError rather than emulated.

Next Steps