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.

Streaming in UHD refers to moving IQ sample data between the host computer and the USRP device. Two objects handle this: uhd::rx_streamer carries samples from the device to the host, and uhd::tx_streamer carries samples from the host to the device. Both are created from a uhd::stream_args_t object that specifies data formats and channel mapping, and both expose a simple blocking API — recv() and send() — for the actual data transfer.

Stream Args

Before creating either streamer type, you must configure a uhd::stream_args_t. The two most important fields are cpu_format (the sample type in host memory) and otw_format (the sample type over the link layer).
// Create stream args: fc32 in host memory, sc16 over the wire
uhd::stream_args_t stream_args("fc32", "sc16");

// Optional: set samples per packet (reduces latency)
stream_args.args["spp"] = std::to_string(200);

// Optional: specify channels (defaults to channel 0)
stream_args.channels = {0, 1};  // two-channel stream

CPU Format Reference

StringC++ TypeNotes
fc64std::complex<double>Highest precision
fc32std::complex<float>Most common choice
sc16std::complex<int16_t>16-bit integer IQ
sc8std::complex<int8_t>8-bit integer IQ

OTW Format Reference

StringDevicesNotes
sc16B2xx, N2xx, N3xx, E3xx, X3xx, X4xxDefault; full dynamic range
sc12B2xxIntermediate precision
sc8B2xx, N2xx2× bandwidth, reduced dynamic range
fc32B2xxFloat over the wire

RX Streaming

Receiving samples involves three steps: create the streamer, issue a stream command to start data flow, then loop on recv().
1

Create the RX streamer

uhd::stream_args_t stream_args("fc32", "sc16");
uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);
2

Allocate a receive buffer

std::vector<std::complex<float>> buff(rx_stream->get_max_num_samps());
uhd::rx_metadata_t md;
3

Issue the stream command

uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
stream_cmd.stream_now = true;
rx_stream->issue_stream_cmd(stream_cmd);
4

Receive samples in a loop

while (keep_running) {
    size_t num_rx_samps = rx_stream->recv(
        &buff.front(), buff.size(), md, 3.0 /*timeout s*/);

    if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT) {
        std::cerr << "Timeout while streaming\n";
        break;
    }
    if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW) {
        std::cerr << "Overflow detected\n";
        continue; // keep going in continuous mode
    }
    // process buff[0..num_rx_samps-1]
}
5

Stop the stream

uhd::stream_cmd_t stop_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
rx_stream->issue_stream_cmd(stop_cmd);

TX Streaming

Transmitting samples involves creating the streamer, then calling send() in a loop. TX metadata controls burst boundaries and timed transmissions.
1

Create the TX streamer

uhd::stream_args_t stream_args("fc32", "sc16");
uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
2

Prepare metadata and buffer

uhd::tx_metadata_t md;
md.start_of_burst = true;
md.end_of_burst   = false;
md.has_time_spec  = false; // send immediately

std::vector<std::complex<float>> buff(tx_stream->get_max_num_samps(), {0, 0});
3

Send samples in a loop

while (keep_running) {
    // fill buff with your signal here
    size_t num_tx_samps = tx_stream->send(
        &buff.front(), buff.size(), md, 3.0 /*timeout s*/);
    md.start_of_burst = false; // only first packet is SOB
}
4

Send end-of-burst

md.end_of_burst = true;
tx_stream->send("", 0, md);

Stream Modes

The stream_cmd_t (C++) / StreamCMD (Python) controls how the device streams to the host. Four modes are available:
C++ EnumPython EnumDescription
STREAM_MODE_START_CONTINUOUSStreamMode.start_contStream indefinitely until stopped
STREAM_MODE_STOP_CONTINUOUSStreamMode.stop_contStop an ongoing continuous stream
STREAM_MODE_NUM_SAMPS_AND_DONEStreamMode.num_samps_and_doneStream exactly num_samps, then stop
STREAM_MODE_NUM_SAMPS_AND_MOREStreamMode.num_samps_and_moreStream exactly num_samps, expect another command immediately after

Timed Start Example

To start streaming at a precise future time (required for multi-device phase alignment):
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
stream_cmd.stream_now = false;
stream_cmd.time_spec  = usrp->get_time_now() + uhd::time_spec_t(0.1); // 100 ms from now
rx_stream->issue_stream_cmd(stream_cmd);

Finite Burst Example

uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
stream_cmd.num_samps   = 10000;
stream_cmd.stream_now  = true;
rx_stream->issue_stream_cmd(stream_cmd);

RX Metadata

Every recv() call fills an rx_metadata_t structure. Always check error_code before processing samples.
FieldTypeDescription
has_time_specboolWhether time_spec is valid
time_spectime_spec_tTimestamp of the first sample in the buffer
start_of_burstboolFirst packet of a burst
end_of_burstboolLast packet of a burst
out_of_sequenceboolTransport dropped a packet (sequence error)
more_fragmentsboolBuffer was too small; more data pending
fragment_offsetsize_tSample index of this fragment within its packet
error_codeerror_code_tSee table below

RX Error Codes

Error CodeValueMeaning
ERROR_CODE_NONE0x0No error
ERROR_CODE_TIMEOUT0x1No packet received within timeout
ERROR_CODE_LATE_COMMAND0x2Stream command arrived too late
ERROR_CODE_BROKEN_CHAIN0x4Expected another stream command
ERROR_CODE_OVERFLOW0x8Receive buffer filled or sequence error (check out_of_sequence)
ERROR_CODE_ALIGNMENT0xcMulti-channel alignment failed
ERROR_CODE_BAD_PACKET0xfPacket could not be parsed

TX Metadata

The tx_metadata_t structure is passed into each send() call to describe the buffer contents.
FieldTypeDescription
has_time_specboolSet true to transmit at the time in time_spec
time_spectime_spec_tScheduled transmit time for the first sample
start_of_burstboolSet true on the first send() of a burst
end_of_burstboolSet true on the last send() of a burst

Timed TX Burst

uhd::tx_metadata_t md;
md.start_of_burst = true;
md.end_of_burst   = false;
md.has_time_spec  = true;
md.time_spec      = usrp->get_time_now() + uhd::time_spec_t(0.1);

size_t num_tx_samps = tx_stream->send(&buff.front(), buff.size(), md);

Overflow and Underflow Handling

Overflow (RX)

What it is: The device is producing samples faster than recv() is consuming them. Buffers back up.What UHD does: Prints "O" (or "D") to stdout and sets ERROR_CODE_OVERFLOW in the RX metadata.Recovery: In continuous streaming mode the device resets itself once the FIFO clears — just keep calling recv(). In finite/triggered modes you may need to re-issue a stream command.

Underflow (TX)

What it is: The device is consuming samples faster than send() is supplying them.What UHD does: Prints "U" to stdout and pushes a message into the async message stream.Recovery: Call send() more frequently, or use the streamer=replay_buffered stream arg to buffer data in FPGA DRAM via the Replay block (requires RFNoC-capable device with Replay block in the FPGA image).
"O" and "U" prints are generally harmless informational messages indicating the host cannot sustain the requested rate. They do not by themselves indicate a fatal error.

Checking Async TX Messages

TX underflows and other asynchronous events are reported via the async message channel:
uhd::async_metadata_t async_md;
while (tx_stream->recv_async_msg(async_md, 0.0 /*non-blocking*/)) {
    if (async_md.event_code == uhd::async_metadata_t::EVENT_CODE_UNDERFLOW) {
        std::cerr << "TX underflow detected\n";
    }
}

Thread Safety

recv() and send() are not thread-safe on a single streamer instance. Do not call recv() from two threads concurrently on the same rx_streamer, or send() from two threads on the same tx_streamer. Multiple different streamers may be called from separate threads simultaneously.
All three fast-path methods — tx_streamer::send(), rx_streamer::recv(), and tx_streamer::recv_async_msg() — can safely coexist in different threads.

Build docs developers (and LLMs) love