Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/EttusResearch/uhd/llms.txt

Use this file to discover all available pages before exploring further.

Streamers are the host-side objects that move IQ samples between your application and USRP hardware. An rx_streamer receives samples from the device into host memory; a tx_streamer sends samples from host memory to the device. Both are created by calling get_rx_stream() / get_tx_stream() on a multi_usrp (or rfnoc_graph) object, and neither is thread-safe — only one thread should call recv() or send() on a given streamer at a time.
#include <uhd/stream.hpp>

stream_args_t

stream_args_t is passed to get_rx_stream() or get_tx_stream() to specify the data formats and channel mapping.
struct stream_args_t {
    std::string            cpu_format;
    std::string            otw_format;
    uhd::device_addr_t     args;
    std::vector<size_t>    channels;
};
cpu_format
std::string
required
Format of samples in host memory. See the table below for supported values.
otw_format
std::string
required
Over-the-wire (transport) format used between the host and device. Using a narrower format reduces link bandwidth at the cost of dynamic range.
args
uhd::device_addr_t
Optional key/value arguments. Notable keys:
  • "spp" — samples per packet (reduces packet size and latency).
  • "fullscale" — full-scale amplitude for floating-point formats (default 1.0).
  • "peak" — fractional peak level used for sc8 wire-format scaling.
  • "underflow_policy" — TX behavior on underflow: "next_burst" or "next_packet".
channels
std::vector<size_t>
List of channel indices to include in this streamer. Default is {0}. For multi-channel streaming, list all channels in the desired order.

CPU Format Values

ValueC++ TypeDescription
"fc64"std::complex<double>64-bit float complex (128 bits/sample)
"fc32"std::complex<float>32-bit float complex (64 bits/sample) — most common
"sc16"std::complex<int16_t>16-bit signed integer complex (32 bits/sample)
"sc8"std::complex<int8_t>8-bit signed integer complex (16 bits/sample)

OTW Format Values

ValueWire EncodingNotes
"sc16"Q16 I16Default; full dynamic range
"sc8"Q8 I8 (packed pairs)Halves link bandwidth, allows higher sample rates on bandwidth-limited links
"sc12"12-bit packedOnly supported on select devices
// fc32 host / sc16 wire — typical configuration
uhd::stream_args_t args("fc32", "sc16");
args.channels = {0, 1};           // Two-channel MIMO
args.args["spp"] = "200";         // 200 samples per packet

auto rx_stream = usrp->get_rx_stream(args);

rx_streamer

The rx_streamer class provides the host interface for receiving samples.
class rx_streamer {
public:
    using sptr = std::shared_ptr<rx_streamer>;

    virtual size_t get_num_channels()   const = 0;
    virtual size_t get_max_num_samps()  const = 0;

    virtual size_t recv(const buffs_type& buffs,
                        const size_t      nsamps_per_buff,
                        rx_metadata_t&    metadata,
                        const double      timeout    = 0.1,
                        const bool        one_packet = false) = 0;

    virtual void issue_stream_cmd(const stream_cmd_t& stream_cmd) = 0;
};

recv()

size_t recv(const buffs_type& buffs,
            const size_t      nsamps_per_buff,
            rx_metadata_t&    metadata,
            const double      timeout    = 0.1,
            const bool        one_packet = false);
Blocking call to receive samples into the provided buffers. Returns as soon as one of the following occurs: buffers are full, end-of-burst is received, timeout elapses, or an error is detected.
buffs
rx_streamer::buffs_type
required
A ref_vector<void*> containing one pointer per channel. Each pointer must address a writable buffer of at least nsamps_per_buff samples. For single-channel use: rx_stream->recv(&buf.front(), ...).
nsamps_per_buff
size_t
required
Maximum number of samples to write into each channel buffer. Passing 0 is valid for metadata-only retrieval.
metadata
rx_metadata_t&
required
Output parameter filled with timing and error information. Always check metadata.error_code after the call.
timeout
double
default:"0.1"
Timeout in seconds applied per internal sub-call within recv(). The total blocking time may exceed this value for multi-packet operations.
one_packet
bool
default:"false"
When true, return immediately after a single packet is processed regardless of buffer size.
Returns: number of samples actually received, which may be less than nsamps_per_buff.

issue_stream_cmd()

void issue_stream_cmd(const stream_cmd_t& stream_cmd);
Sends a streaming command to the device. Must be called to start reception before recv() will return data. See stream_cmd_t below.

get_num_channels() / get_max_num_samps()

size_t get_num_channels() const;  // channels in this streamer
size_t get_max_num_samps() const; // max samples per recv() call
Size your receive buffer to get_max_num_samps() for maximum efficiency. Calling recv() with a larger buffer is valid but will return at most get_max_num_samps() per call.

tx_streamer

The tx_streamer class provides the host interface for transmitting samples.
class tx_streamer {
public:
    using sptr = std::shared_ptr<tx_streamer>;

    virtual size_t get_num_channels()   const = 0;
    virtual size_t get_max_num_samps()  const = 0;

    virtual size_t send(const buffs_type&     buffs,
                        const size_t          nsamps_per_buff,
                        const tx_metadata_t&  metadata,
                        const double          timeout = 0.1) = 0;

    virtual bool recv_async_msg(async_metadata_t& async_metadata,
                                double timeout = 0.1) = 0;
};

send()

size_t send(const buffs_type&    buffs,
            const size_t         nsamps_per_buff,
            const tx_metadata_t& metadata,
            const double         timeout = 0.1);
Blocking call to transmit samples. Automatically fragments large buffers into multiple packets, respecting burst flags across fragment boundaries.
buffs
tx_streamer::buffs_type
required
A ref_vector<const void*> containing one pointer per channel. Each pointer must address a readable buffer of at least nsamps_per_buff samples.
nsamps_per_buff
size_t
required
Number of samples to transmit from each channel buffer.
metadata
const tx_metadata_t&
required
Timing and burst flag information. Set start_of_burst = true on the first call and end_of_burst = true on the last call of a burst sequence.
timeout
double
default:"0.1"
Timeout in seconds. If the device cannot accept samples within the timeout, fewer samples than requested may be returned.
Returns: number of samples sent.

recv_async_msg()

bool recv_async_msg(async_metadata_t& async_metadata, double timeout = 0.1);
Receives an asynchronous acknowledgement or error message from the device. Call this in a background thread to detect underflows, sequence errors, and burst acknowledgements. Returns: true when a valid message is available; false on timeout.

stream_cmd_t

A stream command controls when and how the device delivers samples to the host.
struct stream_cmd_t {
    enum stream_mode_t : uint32_t {
        STREAM_MODE_START_CONTINUOUS   = 'a', // stream indefinitely
        STREAM_MODE_STOP_CONTINUOUS    = 'o', // stop ongoing stream
        STREAM_MODE_NUM_SAMPS_AND_DONE = 'd', // stream N samples, then stop
        STREAM_MODE_NUM_SAMPS_AND_MORE = 'm'  // stream N samples, expect another cmd
    } stream_mode;

    uint64_t    num_samps;   // used with NUM_SAMPS modes
    bool        stream_now;  // true = start immediately
    time_spec_t time_spec;   // used when stream_now = false and trigger = TIMED

    enum class trigger_t {
        TIMED,      // start when time_spec is reached (default)
        TX_RUNNING, // start when the transmitter is running
    } trigger;
};
stream_mode
stream_mode_t
required
One of the four modes above.
num_samps
uint64_t
Number of samples to acquire. Only used with STREAM_MODE_NUM_SAMPS_AND_DONE and STREAM_MODE_NUM_SAMPS_AND_MORE.
stream_now
bool
When true, start streaming immediately (ASAP). When false, start at time_spec.
time_spec
time_spec_t
Time at which to begin streaming when stream_now = false and trigger = TIMED. Must be in the future.
trigger
trigger_t
default:"TIMED"
Trigger source when stream_now = false. TIMED starts streaming when time_spec is reached; TX_RUNNING starts streaming when the transmitter is active.
// Start continuous streaming immediately
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
cmd.stream_now = true;
rx_stream->issue_stream_cmd(cmd);

// Receive exactly 10000 samples starting at t=2.0 seconds
uhd::stream_cmd_t timed(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
timed.num_samps  = 10000;
timed.stream_now = false;
timed.time_spec  = uhd::time_spec_t(2.0);
rx_stream->issue_stream_cmd(timed);

rx_metadata_t

Returned by rx_streamer::recv() on every call.
struct rx_metadata_t {
    bool         has_time_spec;
    time_spec_t  time_spec;
    bool         more_fragments;
    size_t       fragment_offset;
    bool         start_of_burst;
    bool         end_of_burst;
    error_code_t error_code;
    bool         out_of_sequence;
};
has_time_spec
bool
true when time_spec contains the timestamp of the first sample in the buffer.
time_spec
time_spec_t
Timestamp of the first sample returned. Valid when has_time_spec is true.
more_fragments
bool
true when the current packet was too large to fit in the buffer. Subsequent recv() calls will continue from where this one left off.
fragment_offset
size_t
Sample count at the start of the buffer relative to the beginning of the fragmented packet.
end_of_burst
bool
true when the last sample in the buffer is the end of a burst.
error_code
error_code_t
Error status. Check this on every recv() call.
out_of_sequence
bool
When error_code == ERROR_CODE_OVERFLOW, this flag distinguishes a hardware overflow (false) from a dropped transport packet (true).

RX Error Codes

CodeValueDescription
ERROR_CODE_NONE0x0No error
ERROR_CODE_TIMEOUT0x1No packet received within the timeout
ERROR_CODE_LATE_COMMAND0x2A stream command was issued in the past
ERROR_CODE_BROKEN_CHAIN0x4An expected follow-on stream command was not received
ERROR_CODE_OVERFLOW0x8Hardware FIFO overflowed or a packet was dropped
ERROR_CODE_ALIGNMENT0xcMulti-channel time alignment failed
ERROR_CODE_BAD_PACKET0xfReceived packet could not be parsed

tx_metadata_t

Passed to tx_streamer::send() on every call.
struct tx_metadata_t {
    bool         has_time_spec;
    time_spec_t  time_spec;
    bool         start_of_burst;
    bool         end_of_burst;
};
has_time_spec
bool
When false, transmit immediately. When true, hold samples until time_spec is reached.
time_spec
time_spec_t
Absolute time at which the first sample should be transmitted. Requires has_time_spec = true.
start_of_burst
bool
Set true on the first send() call of a burst sequence.
end_of_burst
bool
Set true on the last send() call of a burst sequence. Causes the device to flush remaining samples and mark end-of-burst in the RF output.

async_metadata_t

Returned by tx_streamer::recv_async_msg() to report asynchronous TX events.
struct async_metadata_t {
    size_t       channel;
    bool         has_time_spec;
    time_spec_t  time_spec;
    event_code_t event_code;
    uint32_t     user_payload[4];
};

TX Async Event Codes

CodeValueDescription
EVENT_CODE_OK0x0Status report with no error
EVENT_CODE_BURST_ACK0x1Burst transmitted successfully
EVENT_CODE_UNDERFLOW0x2TX buffer underflowed between packets
EVENT_CODE_SEQ_ERROR0x4Packet loss between host and device
EVENT_CODE_TIME_ERROR0x8Packet arrived late (time was in the past)
EVENT_CODE_UNDERFLOW_IN_PACKET0x10Underflow occurred mid-packet
EVENT_CODE_SEQ_ERROR_IN_BURST0x20Packet lost within a burst
EVENT_CODE_USER_PAYLOAD0x40Custom payload from user-defined FPGA fabric
// Poll async messages in a separate thread to catch TX errors
void async_monitor(uhd::tx_streamer::sptr tx_stream) {
    uhd::async_metadata_t meta;
    while (tx_stream->recv_async_msg(meta, 0.1)) {
        if (meta.event_code != uhd::async_metadata_t::EVENT_CODE_BURST_ACK) {
            std::cerr << "TX async error: " << meta.strevent() << "\n";
        }
    }
}

Full TX Example

#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/stream.hpp>
#include <complex>
#include <vector>
#include <cmath>

int main() {
    auto usrp = uhd::usrp::multi_usrp::make("type=b200");

    usrp->set_tx_rate(1e6);
    usrp->set_tx_freq(915e6, 0);
    usrp->set_tx_gain(60.0, 0);

    uhd::stream_args_t stream_args("fc32", "sc16");
    stream_args.channels = {0};
    auto tx_stream = usrp->get_tx_stream(stream_args);

    // Build a tone at 100 kHz
    const size_t N = 1000;
    std::vector<std::complex<float>> buf(N);
    for (size_t i = 0; i < N; ++i) {
        float phase = 2.0f * M_PI * 100e3f / 1e6f * i;
        buf[i] = {std::cos(phase), std::sin(phase)};
    }

    // Send as a single burst
    uhd::tx_metadata_t md;
    md.start_of_burst = true;
    md.end_of_burst   = true;
    md.has_time_spec  = false;

    tx_stream->send(&buf.front(), N, md, 3.0);
    return 0;
}

Build docs developers (and LLMs) love