srt

The SRT C API (defined in srt.h file) is largely based in design on the legacy UDT API, with some important changes. The API contained in udt.h file contains the legacy UDT API plus some minor optional functions that require the C++ standard library to be used. There are a few optional C++ API functions stored there, as there is no real C++ API for SRT. These functions may be useful in certain situations.

There are some example applications so that you can see how the API is being used, including srt-live-transmit, srt-file-transmit and srt-multiplex. All SRT related material is contained in transmitmedia.* files in the common directory which is used by all applications. See SrtSource::Read and SrtTarget::Write as examples of how data are read and written in SRT.

Setup and teardown

Before any part of the SRT C API can be used, the user should call srt_startup() function. Likewise, before the application exits, the srt_cleanup() function should be called. Note that one of the things the startup function does is to create a new thread, so choose the point of execution for these functions carefully.

Creating and destroying a socket

To do anything with SRT, you have to create an SRT socket first. The term “socket” in this case is used because of its logical similarity to system-wide sockets. An SRT socket is not directly related to system sockets, but like a system socket it is used to define a point of communication.

Synopsis

SRTSOCKET srt_socket(int af, int, int);
int srt_close(SRTSOCKET s);

The srt_socket function is based on the legacy UDT API except the first parameter. The other two are ignored.

Note that SRTSOCKET is just an alias for int; this is a legacy naming convention from UDT, which is here only for clarity.

Usage

sock = srt_socket(AF_INET, SOCK_DGRAM, 0);

This creates a socket, which can next be configured and then used for communication.

srt_close(sock);

This closes the socket and frees all its resources. Note that the true life of the socket does not end exactly after this function exits - some details are being finished in a separate “SRT GC” thread. Still, at least all shared system resources (such as listener port) should be released after this function exits.

Important Remarks

  1. Please note that the use of SRT with AF_INET6 has not been fully tested; use at your own risk.
  2. SRT uses the system UDP protocol as an underlying communication layer, and so it uses also UDP sockets. The underlying communication layer is used only instrumentally, and SRT manages UDP sockets as its own system resource as it pleases - so in some cases it may be reasonable for multiple SRT sockets to share one UDP socket, or for one SRT socket to use multiple UDP sockets.
  3. The term “port” used in SRT is occasionally identical to the term “UDP port”. However SRT offers more flexibility than UDP (or TCP, if we think about the more logical similarity) because it manages ports as its own resources. For example, one port may be shared between various services.

Binding and connecting

Connections are established using the same philosophy as TCP, using functions with names and signatures similar to the BSD Socket API. What is new here is the rendezvous mode.

Synopsis

int srt_bind(SRTSOCKET u, const struct sockaddr* name, int namelen);
int srt_bind_peerof(SRTSOCKET u, UDPSOCKET udpsock);

This function sets up the “sockname” for the socket, that is, the local IP address of the network device (use INADDR_ANY for using any device) and port. Note that this can be done on both listening and connecting sockets; for the latter it will define the outgoing port. If you don’t set up the outgoing port by calling this function (or use port number 0), a unique port number will be selected automatically.

The *_peerof version simply copies the bound address setting from an existing UDP socket.

int srt_listen(SRTSOCKET u, int backlog);

This sets the backlog (maximum allowed simultaneously pending connections) and puts the socket into listening state – that is, incoming connections will be accepted in the call srt_accept.

SRTSOCKET srt_accept(SRTSOCKET u, struct sockaddr* addr, int* addrlen);

This function accepts the incoming connection (the peer should do srt_connect) and returns a socket that is exclusively bound to an opposite socket at the peer. The peer’s address is returned in the addr argument.

int srt_connect(SRTSOCKET u, const struct sockaddr* name, int namelen);
int srt_connect_debug(SRTSOCKET u, const struct sockaddr* name, int namelen, int forced_isn);

This function initiates the connection of a given socket with its peer’s counterpart (the peer gets the new socket for this connection from srt_accept). The address for connection is passed in ‘name’. The connect_debug version allows for enforcing the ISN (initial sequence number); this is used only for debugging or unusual experiments.

int srt_rendezvous(SRTSOCKET u, const struct sockaddr* local_name, int local_namelen,
    const struct sockaddr* remote_name, int remote_namelen);

A convenience function that combines the calls to bind, setting the SRTO_RENDEZVOUS flag, and connecting to the rendezvous counterpart. For simplest usage, the local_name should be set to INADDR_ANY (or a specified adapter’s IP) and port. Note that both local_name and remote_name must use the same port. The peer to which this is going to connect should call the same function, with appropriate local and remote addresses. A rendezvous connection means that both parties connect to one another simultaneously.

SRT Usage - listener (server)

    sockaddr_in sa = { ... }; // set local listening port and possibly interface's IP
    int st = srt_bind(sock, (sockaddr*)&sa, sizeof sa);
    srt_listen(sock, 5);
    while ( !finish ) {
       socklen_t sa_len = sizeof sa;
       newsocket = srt_accept(sock, (sockaddr*)&sa, &sa_len);
       HandleNewClient(newsocket, sa);
    }

SRT Usage - caller (client)

    sockaddr_in sa = { ... }; // set target IP and port

    int st = srt_connect(sock, (sockaddr*)&sa, sizeof sa);
    HandleConnection(sock);

SRT Usage - rendezvous

    sockaddr_in lsa = { ... }; // set local listening IP/port
    sockaddr_in rsa = { ... }; // set remote IP/port

    srt_setsockopt(m_sock, 0, SRTO_RENDEZVOUS, &yes, sizeof yes);
    int stb = srt_bind(sock, (sockaddr*)&lsa, sizeof lsa);
    int stc = srt_connect(sock, (sockaddr*)&rsa, sizeof rsa);
    HandleConnection(sock);

or simpler

    sockaddr_in lsa = { ... }; // set local listening IP/port
    sockaddr_in rsa = { ... }; // set remote IP/port

    int stc = srt_rendezvous(sock, (sockaddr*)&lsa, sizeof lsa,
                                   (sockaddr*)&rsa, sizeof rsa);
    HandleConnection(sock);

Sending and Receiving

The SRT API for sending and receiving is split into three categories: simple, rich, and for files only.

The simple API includes: srt_send and srt_recv functions. They need only the socket and the buffer to send from or receive to, just like system read and write functions.

The rich API includes the srt_sendmsg and srt_recvmsg functions. Actually srt_recvmsg is provided for convenience and backward compatibility, as it is identical to srt_recv. The srt_sendmsg receives more parameters, specifically for messages. The srt_sendmsg2 and srt_recvmsg2 functions receive the socket, buffer, and the SRT_MSGCTRL object, which is an input-output object specifying extra data for the operation.

Functions with the msg2 suffix use the SRT_MSGCTRL object, and have the following interpretation (except flags and boundary that are reserved for future use and should be 0):

Please note that the msgttl and inorder arguments and fields in SRT_MSGCTRL are meaningful only when you use the message API in file mode (this will be explained later). In live mode, which is the SRT default, packets are always delivered when the time comes (always in order), where you don’t want a packet to be dropped before sending (so -1 should be passed here).

The srctime parameter is an SRT addition for applications (i.e. gateways) forwarding SRT streams. It permits pulling and pushing of the sender’s original time stamp, converted to local time and drift adjusted. The srctime parameter is the number of usec (since epoch) in local time. If the connection is not between SRT peers or if Timestamp-Based Packet Delivery mode (TSBPDMODE) is not enabled (see Options), the extracted srctime will be 0. Passing srctime = 0 in sendmsg is like using the API without srctime and the local send time will be used (if TSBPDMODE is enabled and receiver supports it).

Synopsis

int srt_send(SRTSOCKET s, const char* buf, int len);
int srt_sendmsg(SRTSOCKET s, const char* buf, int len, int msgttl, bool inorder, uint64_t srctime);
int srt_sendmsg2(SRTSOCKET s, const char* buf, int len, SRT_MSGCTRL* msgctrl);

int srt_recv(SRTSOCKET s, char* buf, int len);
int srt_recvmsg(SRTSOCKET s, char* buf, int len);
int srt_recvmsg2(SRTSOCKET s, char* buf, int len, SRT_MSGCTRL* msgctrl);

Usage

Sending a payload:

nb = srt_sendmsg(u, buf, nb, -1, true);

nb = srt_send(u, buf, nb);

SRT_MSGCTL mc = srt_msgctl_default;
nb = srt_sendmsg2(u, buf, nb, &mc);

Receiving a payload:

nb = srt_recvmsg(u, buf, nb);
nb = srt_recv(u, buf, nb);

SRT_MSGCTL mc = srt_msgctl_default;
nb = srt_recvmsg2(u, buf, nb, &mc);

Transmission Modes

Mode settings determine how the sender and receiver functions work. The main socket options (see below for full description) that control it are:

We have then three cases (note that Live mode implies Message API):

The File mode and its Buffer and Message APIs are derived from UDT, just implemented in a slightly different way. This will be explained below in HISTORICAL INFO under “Transmission Method: Message”.

Blocking and Non-blocking Mode

SRT functions can also work in blocking and non-blocking mode, for which there are two separate options for sending and receiving: SRTO_SNDSYN and SRTO_RCVSYN. When blocking mode is used, a function will not exit until the availability condition is satisfied; in non-blocking mode the function always exits immediately, and in case of lack of resource availability, it returns an error with appropriate code. The use of non-blocking mode usually requires using some polling mechanism, which in SRT is EPoll.

Note also that the blocking and non-blocking modes apply not only for sending and receiving. For example, SNDSYN defines blocking for srt_connect and RCVSYN defines blocking for srt_accept. The SNDSYN also makes srt_close exit only after the sending buffer is completely empty.

EPoll (Non-blocking Mode Events)

EPoll is a mechanism to track the events happening on the sockets, both “system sockets” (see SYSSOCKET type) and SRT Sockets. Note that SYSSOCKET is also an alias for int, used only for clarity.

Synopsis

int srt_epoll_update_usock(int eid, SRTSOCKET u, const int* events = NULL);
int srt_epoll_update_ssock(int eid, SYSSOCKET s, const int* events = NULL);
int srt_epoll_wait(int eid, SRTSOCKET* readfds, int* rnum, SRTSOCKET* writefds, int* wnum,
                    int64_t msTimeOut,
                    SYSSOCKET* lrfds, int* lrnum, SYSSOCKET* lwfds, int* lwnum);
int srt_epoll_uwait(int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut);
int srt_epoll_clear_usocks(int eid);

SRT Usage

SRT socket being a user level concept, the system epoll (or other select) cannot be used to handle SRT non-blocking mode events. Instead, SRT provides a user-level epoll that supports both SRT and system sockets.

The srt_epoll_update_{u|s}sock() API functions described here are SRT additions to the UDT-derived srt_epoll_add_{u|s}sock() and epoll_remove_{u|s}sock() functions to atomically change the events of interest. For example, to remove SRT_EPOLL_OUT but keep SRT_EPOLL_IN for a given socket with the existing API, the socket must be removed from epoll and re-added. This cannot be done atomically, the thread protection (against the epoll thread) being applied within each function but unprotected between the two calls. It is then possible to lose an SRT_EPOLL_IN event if it fires while the socket is not in the epoll list.

Event flags are of various categories: IN, OUT and ERR are events, which are level-triggered by default and become edge-triggered if combined with SRT_EPOLL_ET flag. The latter is only an edge-triggered flag, not an event. There’s also an SRT_EPOLL_UPDATE flag, which is an edge-triggered only event, and it reports an event on the listener socket that handles socket group new connection for an already connected group - this is for internal use only and it’s used in the internal code for socket groups.

Once the subscriptions are made, you can call an SRT polling function (srt_epoll_wait or srt_epoll_uwait) that will block until an event is raised on any of the subscribed sockets. This function will exit as soon as st least one event is deteted or a timeout occurs. The timeout is specified in [ms], with two special values:

There are some differences in the synopsis between these two:

  1. srt_epoll_wait: Both system and SRT sockets can be subscribed. This function reports events on both socket types according to subscriptions, in these arrays:

    • readfds and lrfds: subscribed for IN and ERR
    • writefds and lwfds: subscribed for OUT and ERR

where:

- `readfds` and `writefds` report SRT sockets ("user" socket)
- `lrfds` and `lwfds` report system sockets

Note: this function provides no straightforward possibility to report sockets with an error. If you want to distinguish a report of readiness for operation from an error report, the only way is to subscribe the socket in only one direction (either SRT_EPOLL_IN or SRT_EPOLL_OUT, but not both) and SRT_EPOLL_ERR, and then check the socket’s presence in the array for which’s direction the socket wasn’t subscribed (for example, when an SRT socket is subscribed for SRT_EPOLL_OUT | SRT_EPOLL_ERR, its presence in readfds means that an error is reported for it). This need not be a big problem because when an error is reported on a socket, an appearance as if it were ready for an operation, followed by doing this operation, will simply result in an error from that operation, so you can use it also as an alternative error check method.

This function also reports error of type SRT_ETIMEOUT when no socket is ready as the timeout elapses (including 0). This behavior is different in srt_epoll_uwait.

Note that in this function there’s a loop that checks for socket readiness every 10ms. Thus, the minimum poll timeout the function can reliably support, when system sockets are involved, is also 10ms. The return time from a poll function can only be quicker when there is an event raised on one of the active SRT sockets.

  1. srt_epoll_uwait: In this function only the SRT sockets can be subscribed (it reports error if you pass an epoll id that is subscribed to system sockets). This function waits for the first event on subscribed SRT socket and reports all events collected at this moment in an array of this structure:
typedef struct SRT_EPOLL_EVENT_
{
    SRTSOCKET fd;
    int       events;
} SRT_EPOLL_EVENT;

Every item reports a single socket with all events as flags.

When the timeout is not -1, and no sockets are ready until the timeout time passes, this function returns 0. This behavior is different in srt_epoll_wait.

The extra srt_epoll_clear_usocks function removes all subscriptions from the epoll container.

The SRT EPoll system does not supports all features of Linux epoll. For example, it only supports level-triggered events for system sockets.

Options

There’s a general method of setting options on a socket in the SRT C API, similar to the system setsockopt/getsockopt functions.

Synopsis

Legacy version:

int srt_getsockopt(SRTSOCKET socket, int level, SRT_SOCKOPT optName, void* optval, int& optlen);
int srt_setsockopt(SRTSOCKET socket, int level, SRT_SOCKOPT optName, const void* optval, int optlen);

New version:

int srt_getsockflag(SRTSOCKET socket, SRT_SOCKOPT optName, void* optval, int& optlen);
int srt_setsockflag(SRTSOCKET socket, SRT_SOCKOPT optName, const void* optval, int optlen);

(In the legacy version, there’s an additional unused level parameter. It was there in the original UDT API just to mimic the system setsockopt function).

Some options require a value of type bool and some others of type int, which is not the same – they differ in size, and mistaking them may end up with a crash. This must be kept in mind especially in any C wrapper. For convenience, the setting option function may accept both int and bool types, but this is not so in the case of getting an option value.

Almost all options from the UDT library are derived (there are a few deleted, including some deprecated already in UDT), many new SRT options have been added. All options are available exclusively with the SRTO_ prefix. Old names are provided as alias names in the udt.h legacy/C++ API file. Note the translation rules:

The Binding column should define for these options one of the following statements concerning setting a value:

Note that options are usually set either on a group or on a socket. When set on a group, the options will persist. They will be derived by every socket automatically created and added to the group. This applies to every socket option, unless a different rule is declared explicitly for a specific case.

This option list is sorted alphabetically. Note that some options can be either only a retrieved (GET) or specified (SET) value.

OptName Since Binding Type Units Default Range
SRTO_CONNTIMEO 1.1.2 pre int msec 3000 tbd

OptName Since Binding Type Units Default Range
SRTO_EVENT   n/a int32_t   n/a n/a

OptName Since Binding Type Units Default Range
SRTO_FC   pre int pkts 25600 32..

OptName Since Binding Type Units Default Range
SRTO_GROUPCONNECT   pre bool   false  

OptName Since Binding Type Units Default Range
SRTO_INPUTBW 1.0.5 post int64_t bytes/s 0 0..

OptName Since Binding Type Units Default Range
SRTO_IPTOS 1.0.5 pre int32_t   (platform default) 0..255

OptName Since Binding Type Units Default Range
SRTO_ISN 1.3.0 post int32_t sequence n/a n/a

OptName Since Binding Type Units Default Range
SRTO_IPTTL 1.0.5 pre int32_t hops (platform default) 1..255

OptName Since Binding Type Units Default Range
SRTO_IPV6ONLY 1.4.0 pre int n/a (platform default) -1..1

OptName Since Binding Type Units Default Range
SRTO_KMREFRESHRATE 1.3.2 pre int32_t pkts 0x1000000 0..unlimited

Having a preannounce period before switchover ensures the new SEK is installed at the receiver before the first packet encrypted with the new SEK is received. The old key remains active after switchover in order to decrypt packets that might still be in flight, or packets that have to be retransmitted.


OptName Since Binding Type Units Default Range
SRTO_KMPREANNOUNCE 1.3.2 pre int32_t pkts 0x1000 see below

At SRTO_KMPREANNOUNCE packets before switchover the new key is sent (repeatedly, if necessary, until it is confirmed by the receiver).

At the switchover point (see SRTO_KMREFRESHRATE), the sender starts encrypting and sending packets using the new key. The old key persists in case it is needed to decrypt packets that were in the flight window, or retransmitted packets.

The old key is decommissioned at SRTO_KMPREANNOUNCE packets after switchover.

The allowed range for this value is between 1 and half of the current value of SRTO_KMREFRESHRATE. The minimum value should never be less than the flight window (i.e. the number of packets that have already left the sender but have not yet arrived at the receiver).


OptName Since Binding Type Units Default Range
SRTO_KMSTATE 1.0.2 n/a int32_t   n/a n/a

OptName Since Binding Type Units Default Range
SRTO_LATENCY 1.0.2 pre int32_t msec 0 positive only

OptName Since Binding Type Units Default Range
SRTO_LINGER   pre linger secs on (180)  

OptName Since Binding Type Units Default Range
SRTO_LOSSMAXTTL 1.2.0 pre int packets 0 reasonable

OptName Since Binding Type Units Default Range
SRTO_MAXBW 1.0.5 pre int64_t bytes/sec -1 -1

OptName Since Binding Type Units Default Range
SRTO_MESSAGEAPI 1.3.0 pre bool boolean true  

OptName Since Binding Type Units Default Range
SRTO_MINVERSION 1.3.0 pre int32_t version 0 up to current

OptName Since Binding Type Units Default Range
SRTO_MSS   pre int bytes 1500 76..

OptName Since Binding Type Units Default Range
SRTO_NAKREPORT 1.1.0 pre bool true true false

OptName Since Binding Type Units Default Range
SRTO_OHEADBW 1.0.5 post int % 25 5..100

OptName Since Binding Type Units Default Range
SRTO_PACKETFILTER 1.4.0 pre string     […512]

For details, see Packet Filtering & FEC.


OptName Since Binding Type Units Default Range
SRTO_PASSPHRASE 0.0.0 pre string   [0] [10..79]

OptName Since Binding Type Units Default Range
SRTO_PAYLOADSIZE 1.3.0 pre int bytes 1316 (Live) up to MTUsize-28-16, usually 1456

OptName Since Binding Type Units Default Range
SRTO_PBKEYLEN 0.0.0 pre int32_t bytes 0 0 16(128/8) 24(192/8) 32(256/8)

OptName Since Binding Type Units Default Range
SRTO_PEERIDLETIMEO 1.3.3 pre int32_t msec 5000 positive only

OptName Since Binding Type Units Default Range
SRTO_PEERLATENCY 1.3.0 pre int32_t msec 0 positive only

OptName Since Binding Type Units Default Range
SRTO_PEERVERSION 1.1.0 n/a int32_t n/a n/a n/a

OptName Since Binding Type Units Default Range
SRTO_RCVBUF   pre int bytes 8192 × (1500-28) 32 × (1500-28) ..FC × (1500-28)

OptName Since Binding Type Units Default Range
SRTO_RCVDATA   n/a int32_t pkts n/a  

OptName Since Binding Type Units Default Range
SRTO_RCVKMSTATE 1.2.0 post enum n/a n/a  

OptName Since Binding Type Units Default Range
SRTO_RCVLATENCY 1.3.0 pre int32_t msec 120 positive only

OptName Since Binding Type Units Default Range
SRTO_RCVSYN   pre bool true true false

OptName Since Binding Type Units Default Range
SRTO_RCVTIMEO   post int msecs -1 -1..

OptName Since Binding Type Units Default Range
SRTO_RENDEZVOUS   pre bool false true false

OptName Since Binding Type Units Default Range
SRTO_REUSEADDR   pre     true true, false

OptName Since Binding Type Units Default Range
SRTO_SENDER 1.0.4 pre int32_t bool?   false  

OptName Since Binding Type Units Default Range
SRTO_CONGESTION 1.3.0 pre const char* predefined “live” “live” or “file”

OptName Since Binding Type Units Default Range
SRTO_SNDBUF   pre int bytes 8192 × (1500-28)  

OptName Since Binding Type Units Default Range
SRTO_SNDDATA   n/a int32_t pkts n/a n/a

OptName Since Binding Type Units Default Range
SRTO_SNDDROPDELAY 1.3.2 pre int ms 0 -1..

OptName Since Binding Type Units Default Range
SRTO_SNDKMSTATE 1.2.0 post enum n/a n/a  

OptName Since Binding Type Units Default Range
SRTO_SNDSYN   post bool true true false

OptName Since Binding Type Units Default Range
SRTO_SNDTIMEO   post int msecs -1 -1..

OptName Since Binding Type Units Default Range
SRTO_STATE   n/a int32_t   n/a n/a

OptName Since Binding Type Units Default Range
SRTO_STREAMID 1.3.0 pre const char*   empty any string

As this uses internally the std::string type, there are additional functions for it in the legacy/C++ API (udt.h): UDT::setstreamid and UDT::getstreamid. This option doesn’t make sense in Rendezvous connection; the result might be that simply one side will override the value from the other side and it’s the matter of luck which one would win


OptName Since Binding Type Units Default Range
SRTO_ENFORCEDENCRYPTION 1.3.2 pre int (bool)   true false

When this option is set to FALSE on both connection parties, the connection is allowed even if the passphrase differs on both parties, or it was set only on one party. Note that the party that has set a passphrase is still allowed to send data over the network. However, the receiver will not be able to decrypt that data and will not deliver it to the application. The party that has set no passphrase can send (unencrypted) data that will be successfully received by its peer.

This option can be used in some specific situations when the user knows both parties of the connection, so there’s no possible situation of a rogue sender and can be useful in situations where it is important to know whether a connection is possible. The inability to decrypt an incoming transmission can be then reported as a different kind of problem.


OptName Since Binding Type Units Default Range
SRTO_TLPKTDROP 1.0.6 pre int32_t bool? true true false

OptName Since Binding Type Units Default Range
SRTO_TRANSTYPE 1.3.0 pre enum   SRTT_LIVE alt: SRTT_FILE

OptName Since Binding Type Units Default Range
SRTO_TSBPDMODE 0.0.0 pre int32_t (bool?) false true false

OptName Since Binding Type Units Default Range
SRTO_UDP_RCVBUF   pre int bytes 8192 × 1500 MSS..

OptName Since Binding Type Units Default Range
SRTO_UDP_SNDBUF   pre int bytes 65536 MSS..

OptName Since Binding Type Units Default Range
SRTO_VERSION 1.1.0 n/a int32_t   n/a n/a

Transmission types

SRT has been mainly created for Live Streaming and therefore its main and default transmission type is “live”. SRT supports, however, the modes that the original UDT library supported, that is, file and message transmission.

There are two general modes: Live and File transmission. Inside File transmission mode, there are also two possibilities: Buffer API and Message API. The Live mode uses Message API. However it doesn’t exactly match the description of the Message API because it uses a maximum single sending buffer up to the size that fits in one UDP packet.

There are two options to set a particular type:

This makes possible a total of three data transmission methods:

NOTE THE TERMS used below:

Transmission method: Live

Setting SRTO_TRANSTYPE to SRTT_LIVE sets the following parameters:

In this mode, every call to a sending function is allowed to send only so much data, as declared by SRTO_PAYLOADSIZE, whose value is still limited to a maximum of 1456 bytes. The application that does the sending is by itself responsible for calling the sending function in appropriate time intervals between subsequent calls. By default, this implies that the receiver uses 120 ms of latency, which is the declared time interval between the moment when the packet is scheduled for sending at the sender side, and when it is received by the receiver application (that is, the data are kept in the buffer and declared as not received, until the time comes for the packet to “play”).

This mode uses the LiveCC congestion control class, which puts only a slight limitation on the bandwidth, if needed, just to add extra time, if the distance between two consecutive packets would be too short for the defined speed limit. Note that it is not predicted to work with “virtually infinite” ingest speeds (such as, for example, reading directly from a file). Therefore the application is not allowed to stream data with maximum speed – it must take care that the speed of data being sent is in rhythm with timestamps in the live stream. Otherwise the behavior is undefined and might be surprisingly disappointing.

The reading function will always return only a payload that was sent, and it will HANGUP until the time to play has come for this packet (if TSBPD mode is on) or when it is available without gaps of lost packets (if TSBPD mode is off - see SRTO_TSBPDMODE).

You may wish to tweak some of the parameters below:

Parameters from the modified for transmission type list, not mentioned in the list above, are crucial for Live mode and shall not be changed.

The BLIND REXMIT situation is resolved using the FASTREXMIT algorithm by LiveCC: sending non-acknowledged packets blindly on the premise that the receiver lingers too long before acknowledging them. This mechanism isn’t used (that is, the BLIND REXMIT situation isn’t handled at all) when SRTO_NAKREPORT is set by the peer – the NAKREPORT method is considered so effective that FASTREXMIT isn’t necessary.

Transmission method: Buffer

Setting SRTO_TRANSTYPE to SRTT_FILE sets the following parameters:

In this mode, calling a sending function is allowed to potentially send virtually any size of data. The sending function will HANGUP only if the sending buffer is completely replete, and RESUME if the sending buffers are available for at least one smallest portion of data passed for sending. The sending function need not send everything in this call, and the caller must be aware that the sending function might return sent data of smaller size than was actually requested.

From the receiving function there will be retrieved as many data as the minimum of the passed buffer size and available data; data still available and not retrieved by this call will be available for retrieval in the next call.

There is also a dedicated pair of functions that can only be used in this mode: srt_sendfile and srt_recvfile. These functions can be used to transmit the whole file, or a fragment of it, based on the offset and size.

This mode uses the FileCC congestion control class, which is a direct copy of the UDT’s CUDTCC congestion control class, adjusted to the needs of SRT’s congestion control framework. This class generally sends the data with maximum speed in the beginning, until the flight window is full, and then keeps the speed at the edge of the flight window, only slowing down in the case where packet loss was detected. The bandwidth usage can be directly limited by SRTO_MAXBW option.

The BLIND REXMIT situation is resolved in FileCC using the LATEREXMIT algorithm: when the repeated ACK was received for the same packet, or when the loss list is empty and the flight window is full, all packets since the last ACK are sent again (that’s more or less the TCP behavior, but in contrast to TCP, this is done as a very low probability fallback).

As you can see in the parameters described above, most have false or 0 values as they usually designate features used in Live mode. None are used with File mode. The only option that makes sense to modify after the SRTT_FILE type was set is SRTO_MESSAGEAPI, which is described below.

Transmission method: Message

Setting SRTO_TRANSTYPE to SRTT_FILE and then SRTO_MESSAGEAPI to true implies usage of the Message transmission method. Parameters are set as described above for the Buffer method, with the exception of SRTO_MESSAGEAPI, and the “file” congestion controller is also used in this mode. It differs from the Buffer method, however, in terms of the rules concerning sending and receiving.

HISTORICAL INFO: The library that SRT was based on, UDT, somewhat misleadingly used the terms STREAM and DGRAM, and used the system symbols SOCK_STREAM and SOCK_DGRAM in the socket creation function. The “datagram” in the UDT terminology has nothing to do with the “datagram” term in networking terminology, where its size is limited to as much it can fit in one MTU. In UDT it is actually a message, which may span through multiple UDP packets and has clearly defined boundaries. It’s something rather similar to the SCTP protocol. Also, in UDP the API functions were strictly bound to DGRAM or STREAM mode: UDT::send/UDT::recv were only for STREAM and UDT::sendmsg/UDT::recvmsg only for DGRAM. In SRT this is changed: all functions can be used in all modes, except srt_sendfile/srt_recvfile, and how the functions actually work is controlled by the SRTO_MESSAGEAPI flag.

The message mode means that every sending function sends exactly as much data as it is passed in a single sending function call, and the receiver receives also not less than exactly the number of bytes that was sent (although every message may have a different size). Every message may also have extra parameters:

The sending function will HANGUP when the free space in the sending buffer does not exactly fit the whole message, and it will only RESUME if the free space in the sending buffer grows up to this size. The call to the sending function also returns with an error, when the size of the message exceeds the total size of the buffer (this can be modified by SRTO_SNDBUF option). In other words, it is not designed to send just a part of the message – either the whole message is sent, or nothing at all.

The receiving function will HANGUP until the whole message is available for reading; if the message spans multiple UDP packets, then the function RESUMES only when every single packet from the message has been received, including recovered packets, if any. When the INORDER flag is set to false and parts of multiple messages are currently available, the first message that is complete (possibly recovered) is returned. Otherwise the function does a HANGUP until the next message is complete. The call to the receiving function is rejected if the buffer size is too small for a single message to fit in it.

Note that you can use any of the sending and receiving functions for sending and receiving messages, except sendfile/recvfile, which are dedicated exclusively for Buffer API.