Reference

Warning

There is no compatibility promise until 1.0.0 is released. Small breaking changes are possible.

roc_context

#include <roc/context.h>
typedef roc_context

Roc context.

Context contains memory pools and network worker thread(s). Other objects that work with memory and network should be attached to a context. It is allowed both to create a separate context for every object, or to create a single context shared between multiple objects.

A context is created using roc_context_open() and destroyed using roc_context_close(). Objects can be attached and detached to an opened context at any moment from any thread. However, the user should ensure that the context is not closed until there are no objects attached to the context.

Thread-safety

  • can be used concurrently

See
roc_sender, roc_receiver

roc_context* roc_context_open(const roc_context_config * config)

Open a new context.

Allocates and initializes a new context. May start some background threads.

Parameters

  • config should point to an initialized config

Returns

  • returns a new context if it was successfully created
  • returns NULL if the arguments are invalid
  • returns NULL if there are not enough resources

int roc_context_close(roc_context * context)

Close the context.

Stops any started background threads, deinitializes and deallocates the context. The user should ensure that nobody uses the context during and after this call.

If this function fails, the context is kept opened.

Parameters

  • context should point to an opened context

Returns

  • returns zero if the context was successfully closed
  • returns a negative value if the arguments are invalid
  • returns a negative value if there are objects attached to the context

roc_sender

#include <roc/sender.h>
typedef roc_sender

Roc sender.

Sender gets an audio stream from the user, encodes it into network packets, and transmits them to a remote receiver.

Context

Sender is automatically attached to a context when opened and detached from it when closed. The user should not close the context until the sender is not closed.

Sender work consists of two parts: stream encoding and packet transmission. The encoding part is performed in the sender itself, and the transmission part is performed in the context network worker thread(s).

Lifecycle

A sender is created using roc_sender_open(). Then it should be bound to a local port using roc_sender_bind() and connected to a single or multiple remote receiver ports using roc_sender_connect(). After that, the audio stream is iteratively written to the sender using roc_sender_write(). When the sender is not needed anymore, it is destroyed using roc_sender_close().

Ports

The user is responsible for connecting the sender to all necessary receiver ports and selecting the same port types and protocols as at the receiver side.

Currently, two configurations are possible:

  • If FEC is disabled, a single port of type ROC_PORT_AUDIO_SOURCE should be connected. The only supported protocol in this case is ROC_PROTO_RTP. This port will be used to send audio packets.
  • If FEC is enabled, two ports of types ROC_PORT_AUDIO_SOURCE and ROC_PORT_AUDIO_REPAIR should be connected. These ports will be used to send audio packets and redundant data for audio packets, respectively. The supported protocols in this case depend on the selected FEC code. For example, if ROC_FEC_RS8M is used, the corresponding protocols would be ROC_PROTO_RTP_RSM8_SOURCE and ROC_PROTO_RSM8_REPAIR.

Resampling

If the sample rate of the user frames and the sample rate of the network packets are different, the sender employs resampler to convert one rate to another.

Resampling is a quite time-consuming operation. The user can choose between completely disabling resampling (and so use the same rate for frames and packets) or several resampler profiles providing different compromises between CPU consumption and quality.

Timing

Sender should encode samples at a constant rate that is configured when the sender is created. There are two ways to accomplish this:

  • If the user enabled the automatic timing feature, the sender employs a CPU timer to block writes until it’s time to encode the next bunch of samples according to the configured sample rate. This mode is useful when the user gets samples from a non-realtime source, e.g. from an audio file.
  • Otherwise, the samples written to the sender are encoded immediately and the user is responsible to write samples in time. This mode is useful when the user gets samples from a realtime source with its own clock, e.g. from an audio device. Automatic clocking should not be used in this case because the audio device and the CPU might have slightly different clocks, and the difference will eventually lead to an underrun or an overrun.

Thread-safety

  • can be used concurrently

roc_sender* roc_sender_open(roc_context * context, const roc_sender_config * config)

Open a new sender.

Allocates and initializes a new sender, and attaches it to the context.

Parameters

  • context should point to an opened context
  • config should point to an initialized config

Returns

  • returns a new sender if it was successfully created
  • returns NULL if the arguments are invalid
  • returns NULL if there are not enough resources

int roc_sender_bind(roc_sender * sender, roc_address * address)

Bind the sender to a local port.

Binds the sender to a local port. Should be called exactly once before calling roc_sender_write() first time.

If address has zero port, the sender is bound to a randomly chosen ephemeral port. If the function succeeds, the actual port to which the sender was bound is written back to address.

Parameters

  • sender should point to an opened sender
  • address should point to a properly initialized address

Returns

  • returns zero if the sender was successfully bound to a port
  • returns a negative value if the arguments are invalid
  • returns a negative value if the sender is already bound
  • returns a negative value if the address can’t be bound
  • returns a negative value if there are not enough resources

int roc_sender_connect(roc_sender * sender, roc_port_type type, roc_protocol proto, const roc_address * address)

Connect the sender to a remote receiver port.

Connects the sender to a receiver port. Should be called one or multiple times before calling roc_sender_write() first time. The type and proto should be the same as they are set at the receiver for this port.

Parameters

  • sender should point to an opened sender
  • type specifies the receiver port type
  • proto specifies the receiver port protocol
  • address should point to a properly initialized address

Returns

  • returns zero if the sender was successfully connected to a port
  • returns a negative value if the arguments are invalid
  • returns a negative value if roc_sender_write() was already called

int roc_sender_write(roc_sender * sender, const roc_frame * frame)

Encode samples to packets and transmit them to the receiver.

Encodes samples to packets and enqueues them for transmission by the context network worker thread. Should be called after roc_sender_bind() and roc_sender_connect().

If the automatic timing is enabled, the function blocks until it’s time to encode the samples according to the configured sample rate. The function returns after encoding and enqueuing the packets, without waiting when the packets are actually transmitted.

Parameters

  • sender should point to an opened, bound, and connected sender
  • frame should point to a valid frame with an array of samples to send

Returns

  • returns zero if all samples were successfully encoded and enqueued
  • returns a negative value if the arguments are invalid
  • returns a negative value if the sender is not bound or connected
  • returns a negative value if there are not enough resources

int roc_sender_close(roc_sender * sender)

Close the sender.

Deinitializes and deallocates the sender, and detaches it from the context. The user should ensure that nobody uses the sender during and after this call. If this function fails, the sender is kept opened and attached to the context.

Parameters

  • sender should point to an opened sender

Returns

  • returns zero if the sender was successfully closed
  • returns a negative value if the arguments are invalid

roc_receiver

#include <roc/receiver.h>
typedef roc_receiver

Roc receiver.

Receiver receives the network packets from multiple senders, decodes audio streams from them, mixes multiple streams into a single stream, and returns it to the user.

Context

Receiver is automatically attached to a context when opened and detached from it when closed. The user should not close the context until the receiver is not closed.

Receiver work consists of two parts: packet reception and stream decoding. The decoding part is performed in the receiver itself, and the reception part is performed in the context network worker thread(s).

Lifecycle

A receiver is created using roc_receiver_open(). Then it should be bound to a single or multiple local ports using roc_receiver_bind(). After that, the audio stream is iteratively read from the receiver using roc_receiver_read(). When the receiver is not needed anymore, it is destroyed using roc_receiver_close().

Ports

Receiver can be bound to multiple network ports of several types. Every port handles packets of the specific protocol selected when the port is bound. It is allowed to bind multiple ports of the same type, typically handling different protocols.

Senders can then be connected to some or all receiver ports to transmit one or several packet streams. If a sender employs FEC, it needs to be connected to a pair of ROC_PORT_AUDIO_SOURCE and ROC_PORT_AUDIO_REPAIR ports which protocols correspond to the employed FEC code. Otherwise, the sender needs to be connected to a single ROC_PORT_AUDIO_SOURCE port.

Sessions

Receiver creates a session object for every sender connected to it. Sessions can appear and disappear at any time. Multiple sessions can be active at the same time.

A session is identified by the sender address. A session may contain multiple packet streams sent to different receiver ports. If the sender employs FEC, the session will contain source and repair packet streams. Otherwise, the session will contain a single source packet stream.

A session is created automatically on the reception of the first packet from a new address and destroyed when there are no packets during a timeout. A session is also destroyed on other events like a large latency underrun or overrun or broken playback, but if the sender continues to send packets, it will be created again shortly.

Mixing

Receiver mixes audio streams from all currently active sessions into a single output stream. The output stream continues no matter how much active sessions there are at the moment. In particular, if there are no sessions, the receiver produces a stream with all zeros. Sessions can be added and removed from the output stream at any time, probably in the middle of a frame.

Resampling

Every session may have a different sample rate. And even if nominally all of them are of the same rate, device frequencies usually differ by a few tens of Hertz.

Receiver compensates these differences by adjusting the rate of every session stream to the rate of the receiver output stream using a per-session resampler. The frequencies factor between the sender and the receiver clocks is calculated dynamically for every session based on the session incoming packet queue size.

Resampling is a quite time-consuming operation. The user can choose between completely disabling resampling (at the cost of occasional underruns or overruns) or several resampler profiles providing different compromises between CPU consumption and quality.

Timing

Receiver should decode samples at a constant rate that is configured when the receiver is created. There are two ways to accomplish this:

  • If the user enabled the automatic timing feature, the receiver employs a CPU timer to block reads until it’s time to decode the next bunch of samples according to the configured sample rate. This mode is useful when the user passes samples to a non-realtime destination, e.g. to an audio file.
  • Otherwise, the samples read from the receiver are decoded immediately and the user is responsible to read samples in time. This mode is useful when the user passes samples to a realtime destination with its own clock, e.g. to an audio device. Automatic clocking should not be used in this case because the audio device and the CPU might have slightly different clocks, and the difference will eventually lead to an underrun or an overrun.

Thread-safety

  • can be used concurrently

roc_receiver* roc_receiver_open(roc_context * context, const roc_receiver_config * config)

Open a new receiver.

Allocates and initializes a new receiver, and attaches it to the context.

Parameters

  • context should point to an opened context
  • config should point to an initialized config

Returns

  • returns a new receiver if it was successfully created
  • returns NULL if the arguments are invalid
  • returns NULL if there are not enough resources

int roc_receiver_bind(roc_receiver * receiver, roc_port_type type, roc_protocol proto, roc_address * address)

Bind the receiver to a local port.

Binds the receiver to a local port. May be called multiple times to bind multiple port. May be called at any time.

If address has zero port, the receiver is bound to a randomly chosen ephemeral port. If the function succeeds, the actual port to which the receiver was bound is written back to address.

Parameters

  • receiver should point to an opened receiver
  • type specifies the port type
  • proto specifies the port protocol
  • address should point to a properly initialized address

Returns

  • returns zero if the receiver was successfully bound to a port
  • returns a negative value if the arguments are invalid
  • returns a negative value if the address can’t be bound
  • returns a negative value if there are not enough resources

int roc_receiver_read(roc_receiver * receiver, roc_frame * frame)

Read samples from the receiver.

Reads network packets received on bound ports, routes packets to sessions, repairs lost packets, decodes samples, resamples and mixes them, and finally stores samples into the provided frame.

If the automatic timing is enabled, the function blocks until it’s time to decode the samples according to the configured sample rate.

Parameters

  • receiver should point to an opened receiver
  • frame should point to an initialized frame which will be filled with samples; the number of samples is defined by the frame size

Returns

  • returns zero if all samples were successfully decoded
  • returns a negative value if the arguments are invalid
  • returns a negative value if there are not enough resources

int roc_receiver_close(roc_receiver * receiver)

Close the receiver.

Deinitializes and deallocates the receiver, and detaches it from the context. The user should ensure that nobody uses the receiver during and after this call. If this function fails, the receiver is kept opened and attached to the context.

Parameters

  • receiver should point to an opened receiver

Returns

  • returns zero if the receiver was successfully closed
  • returns a negative value if the arguments are invalid

roc_frame

#include <roc/frame.h>
typedef roc_frame
struct roc_frame

Audio frame.

Represents a multichannel sequence of audio samples. The user is responsible for allocating and deallocating the frame and the data it is pointing to.

Thread-safety

  • should not be used concurrently

Public Members

void* samples

Audio samples.

Sample rate, channel set, and encoding are defined by the sender or receiver parameters.

size_t samples_size

Sample buffer size.

Defines the size of samples buffer in bytes.

roc_address

#include <roc/address.h>
typedef roc_family
enum roc_family

Network address family.

Values:

ROC_AF_INVALID = -1

Invalid address.

ROC_AF_AUTO = 0

Automatically detect address family from string format.

ROC_AF_IPv4 = 1

IPv4 address.

ROC_AF_IPv6 = 2

IPv6 address.

typedef roc_address
struct roc_address

Network address.

Represents an Internet address, i.e. and IP address plus UDP or TCP port. Similar to struct sockaddr.

Thread-safety

  • should not be used concurrently

int roc_address_init(roc_address * address, roc_family family, const char * ip, int port)

Initialize address.

Parses an IP address from a string representation and initializes address. If family is ROC_AF_AUTO, the address family is auto-detected from the ip format. Otherwise, the ip format should correspond to the family specified.

When address is used to bind a sender or receiver port, the “0.0.0.0” ip may be used to bind the port to all network interfaces, and the zero port may be used to bind the port to a randomly chosen ephemeral port.

The user is responsible for allocating and deallocating address. An address doesn’t contain any dynamically allocated data, so no special deinitialization is required.

Parameters

  • address should point to a probably uninitialized struct allocated by user
  • family should be ROC_AF_AUTO, ROC_AF_IPv4, or ROC_AF_IPv6
  • ip should point to a zero-terminated string with a valid IPv4 or IPv6 address
  • port should be a port number in range [0; 65536)

Returns

  • returns zero if address was successfully initialized
  • returns a negative value if the arguments are invalid

roc_family roc_address_family(const roc_address * address)

Get address family.

Parameters

  • address should point to a properly initialized address struct

Returns

  • returns the address family if no error occurred
  • returns ROC_AF_INVALID if the arguments are invalid

const char* roc_address_ip(const roc_address * address, char * buf, size_t bufsz)

Get IP address.

Formats the zero-terminated string representation of the IP address to the given buffer. The function fails if the buffer is not large enough to store the string plus the terminating zero.

Parameters

  • address should point to a properly initialized address struct
  • buf should point to a probably uninitialized buffer allocated by user at least of the bufsz size
  • bufsz defines the buf size

Returns

  • returns buf if the IP address was successfully stored into the buf
  • returns NULL if the buffer is too small to store the formatted IP address
  • returns NULL if the arguments are invalid

int roc_address_port(const roc_address * address)

Get address port.

Parameters

  • address should point to a properly initialized address struct

Returns

  • returns a non-negative port number if no error occurred
  • returns a negative value if the arguments are invalid

roc_config

#include <roc/config.h>
typedef roc_port_type
enum roc_port_type

Network port type.

Values:

ROC_PORT_AUDIO_SOURCE = 1

Network port for audio source packets.

If FEC is not used, this type of port is used to send or receive audio packets. If FEC is used, this type of port is used to send or receive FEC source packets containing audio data plus some FEC headers.

ROC_PORT_AUDIO_REPAIR = 2

Network port for audio repair packets.

If FEC is used, this type of port is used to send or receive FEC repair packets containing redundant data for audio plus some FEC headers.

typedef roc_protocol
enum roc_protocol

Network protocol.

Values:

ROC_PROTO_RTP = 1

Bare RTP (RFC 3550).

ROC_PROTO_RTP_RS8M_SOURCE = 2

RTP source packet (RFC 3550) + FECFRAME Reed-Solomon footer (RFC 6865) with m=8.

ROC_PROTO_RS8M_REPAIR = 3

FEC repair packet + FECFRAME Reed-Solomon header (RFC 6865) with m=8.

ROC_PROTO_RTP_LDPC_SOURCE = 4

RTP source packet (RFC 3550) + FECFRAME LDPC-Staircase footer (RFC 6816).

ROC_PROTO_LDPC_REPAIR = 5

FEC repair packet + FECFRAME LDPC-Staircase header (RFC 6816).

typedef roc_fec_code
enum roc_fec_code

Forward Error Correction code.

Values:

ROC_FEC_DISABLE = -1

No FEC code.

Compatible with ROC_PROTO_RTP protocol.

ROC_FEC_DEFAULT = 0

Default FEC code.

Current default is ROC_FEC_RS8M.

ROC_FEC_RS8M = 1

Reed-Solomon FEC code (RFC 6865) with m=8.

Good for small block sizes (below 256 packets). Compatible with ROC_PROTO_RTP_RS8M_SOURCE and ROC_PROTO_RS8M_REPAIR protocols for source and repair ports.

ROC_FEC_LDPC_STAIRCASE = 2

LDPC-Staircase FEC code (RFC 6816).

Good for large block sizes (above 1024 packets). Compatible with ROC_PROTO_RTP_LDPC_SOURCE and ROC_PROTO_LDPC_REPAIR protocols for source and repair ports.

typedef roc_packet_encoding
enum roc_packet_encoding

Packet encoding.

Values:

ROC_PACKET_ENCODING_AVP_L16 = 2

PCM signed 16-bit.

“L16” encoding from RTP A/V Profile (RFC 3551). Uncompressed samples coded as interleaved 16-bit signed big-endian integers in two’s complement notation.

typedef roc_frame_encoding
enum roc_frame_encoding

Frame encoding.

Values:

ROC_FRAME_ENCODING_PCM_FLOAT = 1

PCM floats.

Uncompressed samples coded as floats in range [-1; 1]. Channels are interleaved, e.g. two channels are encoded as “L R L R ...”.

typedef roc_channel_set
enum roc_channel_set

Channel set.

Values:

ROC_CHANNEL_SET_STEREO = 2

Stereo.

Two channels: left and right.

typedef roc_resampler_profile
enum roc_resampler_profile

Resampler profile.

Values:

ROC_RESAMPLER_DISABLE = -1

No resampling.

ROC_RESAMPLER_DEFAULT = 0

Default profile.

Current default is ROC_RESAMPLER_MEDIUM.

ROC_RESAMPLER_HIGH = 1

High quality, low speed.

ROC_RESAMPLER_MEDIUM = 2

Medium quality, medium speed.

ROC_RESAMPLER_LOW = 3

Low quality, high speed.

typedef roc_context_config
struct roc_context_config

Context configuration.

See
roc_context

Public Members

unsigned int max_packet_size

Maximum size in bytes of a network packet.

Defines the amount of bytes allocated per network packet. Sender and receiver won’t handle packets larger than this. If zero, default value is used.

unsigned int max_frame_size

Maximum size in bytes of an audio frame.

Defines the amount of bytes allocated per intermediate internal frame in the pipeline. Does not limit the size of the frames provided by user. If zero, default value is used.

typedef roc_sender_config
struct roc_sender_config

Sender configuration.

See
roc_sender

Public Members

unsigned int frame_sample_rate

The rate of the samples in the frames passed to sender.

Number of samples per channel per second. If frame_sample_rate and packet_sample_rate are different, resampler should be enabled. Should be set.

roc_channel_set frame_channels

The channel set in the frames passed to sender.

Should be set.

roc_frame_encoding frame_encoding

The sample encoding in the frames passed to sender.

Should be set.

unsigned int packet_sample_rate

The rate of the samples in the packets generated by sender.

Number of samples per channel per second. If zero, default value is used.

roc_channel_set packet_channels

The channel set in the packets generated by sender.

If zero, default value is used.

roc_packet_encoding packet_encoding

The sample encoding in the packets generated by sender.

If zero, default value is used.

unsigned long long packet_length

The length of the packets produced by sender, in nanoseconds.

Number of nanoseconds encoded per packet. The samples written to the sender are buffered until the full packet is accumulated or the sender is flushed or closed. Larger number reduces packet overhead but also increases latency. If zero, default value is used.

unsigned int packet_interleaving

Enable packet interleaving.

If non-zero, the sender shuffles packets before sending them. This may increase robustness but also increases latency.

unsigned int automatic_timing

Enable automatic timing.

If non-zero, the sender write operation restricts the write rate according to the frame_sample_rate parameter. If zero, no restrictions are applied.

roc_resampler_profile resampler_profile

Resampler profile to use.

If non-zero, the sender employs resampler if the frame sample rate differs from the packet sample rate.

roc_fec_code fec_code

FEC code to use.

If non-zero, the sender employs a FEC codec to generate redundant packets which may be used on receiver to restore lost packets. This requires both sender and receiver to use two separate source and repair ports.

unsigned int fec_block_source_packets

Number of source packets per FEC block.

Used if some FEC code is selected. Larger number increases robustness but also increases latency. If zero, default value is used.

unsigned int fec_block_repair_packets

Number of repair packets per FEC block.

Used if some FEC code is selected. Larger number increases robustness but also increases traffic. If zero, default value is used.

typedef roc_receiver_config
struct roc_receiver_config

Receiver configuration.

See
roc_receiver

Public Members

unsigned int frame_sample_rate

The rate of the samples in the frames returned to the user.

Number of samples per channel per second. Should be set.

roc_channel_set frame_channels

The channel set in the frames returned to the user.

Should be set.

roc_frame_encoding frame_encoding

The sample encoding in the frames returned to the user.

Should be set.

unsigned int automatic_timing

Enable automatic timing.

If non-zero, the receiver read operation restricts the read rate according to the frame_sample_rate parameter. If zero, no restrictions are applied.

roc_resampler_profile resampler_profile

Resampler profile to use.

If non-zero, the receiver employs resampler for two purposes:

  • adjust the sender clock to the receiver clock, which may differ a bit
  • convert the packet sample rate to the frame sample rate if they are different

unsigned long long target_latency

Target latency, in nanoseconds.

The session will not start playing until it accumulates the requested latency. Then, if resampler is enabled, the session will adjust its clock to keep actual latency as close as close as possible to the target latency. If zero, default value is used.

unsigned long long max_latency_overrun

Maximum delta between current and target latency, in nanoseconds.

If current latency becomes larger than the target latency plus this value, the session is terminated. If zero, default value is used.

unsigned long long max_latency_underrun

Maximum delta between target and current latency, in nanoseconds.

If current latency becomes smaller than the target latency minus this value, the session is terminated. May be larger than the target latency because current latency may be negative, which means that the playback run ahead of the last packet received from network. If zero, default value is used.

long long no_playback_timeout

Timeout for the lack of playback, in nanoseconds.

If there is no playback during this period, the session is terminated. This mechanism allows to detect dead, hanging, or broken clients generating invalid packets. If zero, default value is used. If negative, the timeout is disabled.

long long broken_playback_timeout

Timeout for broken playback, in nanoseconds.

If there the playback is considered broken during this period, the session is terminated. The playback is broken if there is a breakage detected at every breakage_detection_window during broken_playback_timeout. This mechanism allows to detect vicious circles like when all client packets are a bit late and receiver constantly drops them producing unpleasant noise. If zero, default value is used. If negative, the timeout is disabled.

unsigned long long breakage_detection_window

Breakage detection window, in nanoseconds.

If zero, default value is used.

See
broken_playback_timeout.

roc_log

#include <roc/log.h>
typedef roc_log_level
enum roc_log_level

Log level.

See
roc_log_set_level

Values:

ROC_LOG_NONE = 0

No messages.

Setting this level disables logging completely.

ROC_LOG_ERROR = 1

Error messages.

Setting this level enables logging only when something goes wrong, e.g. a user operation can’t be completed, or there is not enough memory for a new session.

ROC_LOG_INFO = 2

Informational messages.

Setting this level enables logging of important high-level events, like binding a new port or creating a new session.

ROC_LOG_DEBUG = 3

Debug messages.

Setting this level enables logging of debug messages. Doesn’t affect performance.

ROC_LOG_TRACE = 4

Debug messages (extra verbosity).

Setting this level enables verbose tracing. May cause significant slow down.

typedef (* roc_log_handler)(roc_log_level level, const char *component, const char *message)

Log handler.

Parameters

  • level defines the message level
  • component defines the component that produces the message
  • message defines the message text

See
roc_log_set_handler

void roc_log_set_level(roc_log_level level)

Set maximum log level.

Messages with log levels higher than level will be dropped. By default the log level is set to ROC_LOG_ERROR.

Thread-safety

  • can be used concurrently

void roc_log_set_handler(roc_log_handler handler)

Set log handler.

If handler is not NULL, messages are passed to the handler. Otherwise, messages are printed to stderr. By default the log handler is set to NULL.

It’s guaranteed that the previously set handler, if any, will not be used after this function returns.

Thread-safety

  • can be used concurrently
  • handler calls are serialized, so the handler itself doesn’t need to be thread-safe