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.
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.
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.
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.
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.
AF_INET6
has not been fully tested;
use at your own risk.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.
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.
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);
}
sockaddr_in sa = { ... }; // set target IP and port
int st = srt_connect(sock, (sockaddr*)&sa, sizeof sa);
HandleConnection(sock);
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);
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):
srt_sendmsg2
:
srt_recvmsg2
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).
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);
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);
Mode settings determine how the sender and receiver functions work. The main socket options (see below for full description) that control it are:
SRTO_TRANSTYPE
. Sets several parameters in accordance with the selected
mode:
SRTT_LIVE
(default) the Live mode (for live stream transmissions)SRTT_FILE
the File mode (for “no time controlled” fastest data transmission)SRTO_MESSAGEAPI
We have then three cases (note that Live mode implies Message API):
Live mode (default)
In this mode, the application is expected to send single pieces of data that are already under sending speed control. Default size is 1316, which is 7 * 188 (MPEG TS unit size). With default settings in this mode, the receiver will be delivered payloads with the same time distances between them as when they were sent, with a small delay (default 120 ms).
File mode, Buffer API (default when set SRTT_FILE
mode)
In this mode the application may deliver data with any speed and of any size. The facility will try to send them as long as there is buffer space for it. A single call for sending may send only fragments of the buffer, and the receiver will receive as much as is available and fits in the buffer.
File mode, Message API (when SRTO_TRANSTYPE
is SRTT_FILE
and SRTO_MESSAGEAPI
is true)
In this mode the application delivers single pieces of data that have declared boundaries. The sending is accepted only when the whole message can be scheduled for sending, and the receiver will be given either the whole message, or nothing at all, including when the buffer is too small for the whole message.
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”.
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 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.
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 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:
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.
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.
There’s a general method of setting options on a socket in the SRT C API, similar to the system setsockopt/getsockopt functions.
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:
UDT_
prefix from UDT options was changed to the prefix SRTO_
UDP_
prefix from UDT options was changed to the prefix SRTO_UDP_
SRT_
prefix in older SRT versions was changed to SRTO_
The Binding column should define for these options one of the following statements concerning setting a value:
srt_connect()
and never changed thereafter. For a listener socket it should be set to a binding
socket and it will be derived by every socket returned by srt_accept()
.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 |
SRT_EPOLL_OPT
enum (a combination of
SRT_EPOLL_IN
, SRT_EPOLL_OUT
and SRT_EPOLL_ERR
).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.. |
This option is effective only if SRTO_MAXBW
is set to 0 (relative). It
controls the maximum bandwidth together with SRTO_OHEADBW
option according
to the formula: MAXBW = INPUTBW * (100 + OHEADBW) / 100
. When this option
is set to 0 (automatic) then the real INPUTBW value will be estimated from
the rate of the input (cases when the application calls the srt_send*
function) during transmission.
*Recommended: set this option to the predicted bitrate of your live stream
and keep default 25% value for SRTO_OHEADBW
.
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 |
IP_TTL
option for IP) or IPv6 unicast hops (see
IPV6_UNICAST_HOPS
for IPV6) depending on socket address family. Applies to sender only.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 |
SRTO_KMPREANNOUNCE
) before and after the switchover.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 |
SRTO_SNDKMSTATE
, if the socket has set SRTO_SENDER
to true, and
SRTO_RCVKMSTATE
otherwise. This option shall not be used if the application
meant to use the versions at least 1.3.0 and does not use the SRTO_SENDER
flag.OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_LATENCY |
1.0.2 | pre | int32_t |
msec | 0 | positive only |
SRTO_RCVLATENCY
and SRTO_PEERLATENCY
to the same value.
Note that prior to version 1.3.0 this is the only flag to set the latency, however
this is effectively equivalent to setting SRTO_PEERLATENCY
, when the side is
sender (see SRTO_SENDER
) and SRTO_RCVLATENCY
when the side is receiver, and
the bidirectional stream sending in version 1.2.0is not supported.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 |
-1
: infinite (the limit in Live Mode is 1Gbps)0
: relative to input rate (see SRTO_INPUTBW
)>0
: absolute limit in B/s
SRTO_INPUTBW
and SRTO_OHEADBW
options. However, if you want to do so,
you should make sure that your stream has a fairly constant bitrate, or that
changes are not abrupt, as high bitrate changes may work against the
measurement. SRT cannot ensure that this is always the case for a live stream,
therefore the default -1 remains even in live mode.OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_MESSAGEAPI |
1.3.0 | pre | bool | boolean | true |
[SET] - When set, this socket uses the Message API[*], otherwise it uses
Buffer API. Note that in live mode (see SRTO_TRANSTYPE
option) there’s only
message API available. In File mode you can chose to use one of two modes:
Stream API (default, when this option is false). In this mode you may send as many data as you wish with one sending instruction, or even use dedicated functions that read directly from a file. The internal facility will take care of any speed and congestion control. When receiving, you can also receive as many data as desired, the data not extracted will be waiting for the next call. There is no boundary between data portions in the Stream mode.
Message API. In this mode your single sending instruction passes exactly one
piece of data that has boundaries (a message). Contrary to Live mode,
this message may span across multiple UDP packets and the only size limitation
is that it shall fit as a whole in the sending buffer. The receiver shall use
as large buffer as necessary to receive the message, otherwise the message will
not be given up. When the message is not complete (not all packets received or
there was a packet loss) it will not be given up. The messages that are sent
later, but were earlier reassembled by the receiver, will be given up to the
received once ready, if the inorder
flag (see srt_sendmsg
) was set to
false.
As a comparison to the standard system protocols, the Stream API makes the transmission similar to TCP, whereas the Message API functions like the SCTP protocol.
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 |
UMSG_LOSSREPORT
messages periodically until the lost packet is retransmitted or intentionally
droppedOptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_OHEADBW |
1.0.5 | post | int |
% | 25 | 5..100 |
Recovery bandwidth overhead above input rate (see SRTO_INPUTBW
). It is
effective only if SRTO_MAXBW
is set to 0.
Sender: user configurable, default: 25%.
Recommendations:
Overhead is intended to give you extra bandwidth for a case when some packet has taken part of the bandwidth, but then was lost and has to be retransmitted. Therefore the effective maximum bandwidth should be appropriately higher than your stream’s bitrate so that there’s some room for retransmission, but still limited so that the retransmitted packets don’t cause the bandwidth usage to skyrocket when larger groups of packets were lost
Don’t configure it too low and avoid 0 in case when you have
SRTO_INPUTBW
option set to 0 (automatic) otherwise your stream will
choke and break quickly at any rising packet loss.
To do: set-only. get should be supported.
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) |
[GET or SET] - Sender encryption key length. The use is slightly different in 1.2.0 (HSv4) and 1.3.0 (HSv5):
HSv4: This is set on the sender and enables encryption, if not 0. The receiver shall not set it and will agree on the length as defined by the sender.
HSv5: On the sending party it will default to 16 if not changed the default 0 and the passphrase was set. The party that has set this value to non-zero value will advertise it at the beginning of the handshake. Actually there are two methods of defining it predicted to be used and all other uses are considered an undefined behavior:
Unidirectional: the sender shall set PBKEYLEN
and the receiver shall
not alter the default value 0. The effective PBKEYLEN
will be the one set
on the sender. The receiver need not know the sender’s PBKEYLEN
, just the
passphrase, PBKEYLEN
will be correctly passed.
Bidirectional in Caller-Listener arrangement: use a rule in your use
case that you will be setting the PBKEYLEN
exclusively either on the
Listener or on the Caller. Simply the value set on the Listener will win,
if set.
Bidirectional in Rendezvous arrangement: you have to know both parties
passphrases as well as PBKEYLEN
and you shall set PBKEYLEN
to the same
value on both parties (or leave the default value on both parties, which will
result in 16)
Unwanted behavior cases: if both parties set PBKEYLEN
and the value
on both sides is different, the effective PBKEYLEN
will be the one that is
set on the Responder party, which may also override the PBKEYLEN
32 set by
the sender to value 16 if such value was used by the receiver. The Responder
party is Listener in Caller-Listener arrangement, and in Rendezvous it’s the
matter of luck which one.
PBKEYLEN
not set)OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_PEERIDLETIMEO |
1.3.3 | pre | int32_t |
msec | 5000 | positive only |
[ms]
to wait until any packet is received from peer since
the last such packet reception. If this time is passed, connection is considered
broken on timeout.OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_PEERLATENCY |
1.3.0 | pre | int32_t |
msec | 0 | positive only |
SRTO_RCVLATENCY
) that is set by the sender
side as a minimum value for the receiver.OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_PEERVERSION |
1.1.0 | n/a | int32_t |
n/a | n/a | n/a |
SRTO_VERSION
for the version format.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 |
SRTO_KMSTATE
SRT_KM_STATE
:
SRT_KM_S_UNSECURED
: no decryption (even if sent data are encrypted)SRT_KM_S_SECURING
: securing: (HSv4 only) encryption is desired, but KMX
handshake not yet done, still waiting (until done, behaves like UNSECURED)SRT_KM_S_SECURED
: KM exchange was successful and it will be decrypting
encrypted dataSRT_KM_S_NOSECRET
: (HSv5 only) This site has set password, but data will
be received as plainSRT_KM_S_BADSECRET
: The password is wrong, encrypted payloads won’t be
decrypted.OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_RCVLATENCY |
1.3.0 | pre | int32_t |
msec | 120 | positive only |
SRTO_RCVLATENCY
to 120 ms!
The buffer mode settings set SRTO_RCVLATENCY
to 0.SRTO_PEERLATENCY
set by the peer side. This option in
pre-1.3.0 version is available only as SRTO_LATENCY
.OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_RCVSYN |
pre | bool |
true | true | false |
[GET or SET] - When true, sets blocking mode on reading function when
it’s not ready to perform the operation. When false (“non-blocking mode”), the
reading function will in this case report error SRT_EASYNCRCV
and return
immediately. Details depend on the tested entity:
On a connected socket or group this applies to a receiving function
(srt_recv
and others) and a situation when there are no data available for
reading. The readiness state for this operation can be tested by checking the
SRT_EPOLL_IN
flag on the aforementioned socket or group.
On a freshly created socket or group that is about to be connected to a peer
listener this applies to any srt_connect
call (and derived), which in
“non-blocking mode” always return immediately. The connected state for that
socket or group can be tested by checking the SRT_EPOLL_OUT
flag. NOTE
that a socket that failed to connect doesn’t change the SRTS_CONNECTING
state and can be found out only by testing SRT_EPOLL_ERR
flag.
On a listener socket this applies to srt_accept
call. The readiness state
for this operation can be tested by checking the SRT_EPOLL_IN
flag on
this listener socket. This flag is also derived from the listener socket
by the accepted socket or group, although the meaning of this flag is
effectively different.
Note that when this flag is set only on a group, it applies to a specific receiving operation being done on that group (i.e. it is not derived from the socket of which the group is a member).
OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_RCVTIMEO |
post | int |
msecs | -1 | -1.. |
[GET or SET] - limit the time up to which the receiving operation will
block (see SRTO_RCVSYN
for details), so when this time is exceeded, it
will behave as if in “non-blocking mode”. The -1 value means no time limit.
Note that when this flag is set only on a group, it applies to a specific receiving operation being done on that group (i.e. it is not derived from the socket of which the group is a member).
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 |
When true, allows the SRT socket use the binding address used already by
another SRT socket in the same application. Note that SRT socket use an
intermediate object to access the underlying UDP sockets called Multiplexer,
so multiple SRT socket may share one UDP socket and the packets received to this
UDP socket will be correctly dispatched to the SRT socket to which they are
currently destined. This has some similarities to SO_REUSEADDR
system socket
option, although it’s only used inside SRT.
TODO: This option weirdly only allows the socket used in bind() to use the local address that another socket is already using, but not to disallow another socket in the same application to use the binding address that the current socket is already using. What it actually changes is that when given address in bind() is already used by another socket, this option will make the binding fail instead of making the socket added to the shared group of that socket that already has bound this address - but it will not disallow another socket reuse its address.
OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_SENDER |
1.0.4 | pre | int32_t bool? |
false |
SRTO_MINVERSION
if you expect that it
be true) and therefore support HSv5 handshake, where the SRT extended handshake
is done with the overall handshake process. This flag is however obligatory
if at least one party may be SRT below version 1.3.0 and does not support HSv5.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.. |
NB: The default live mode settings set SRTO_SNDDROPDELAY
to 0.
The buffer mode settings set SRTO_SNDDROPDELAY
to -1.
[SET] - Sets an extra delay before TLPKTDROP is triggered on the data
sender. TLPKTDROP discards packets reported as lost if it is already too late
to send them (the receiver would discard them even if received). The total
delay before TLPKTDROP is triggered consists of the LATENCY (SRTO_PEERLATENCY
),
plus SRTO_SNDDROPDELAY
, plus 2 * the ACK interval (default ACK interval is 10ms).
The minimum total delay is 1 second.
A value of -1 discards packet drop.
SRTO_SNDDROPDELAY
extends the tolerance for retransmitting packets at
the expense of more likely retransmitting them uselessly. To be effective, it
must have a value greater than 1000 - SRTO_PEERLATENCY
.
OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_SNDKMSTATE |
1.2.0 | post | enum | n/a | n/a |
SRTO_KMSTATE
SRT_KM_STATE
:
SRT_KM_S_UNSECURED
: data will not be encryptedSRT_KM_S_SECURING
: (HSv4 only): encryption is desired, but KM exchange
isn’t finished. Payloads will be encrypted, but the receiver won’t be able
to decrypt them yet.SRT_KM_S_SECURED
: payloads will be encrypted and the receiver will
decrypt themSRT_KM_S_NOSECRET
: Encryption is desired on this side and payloads will
be encrypted, but the receiver didn’t set the password and therefore won’t be
able to decrypt themSRT_KM_S_BADSECRET
: Encryption is configured on both sides, but the
password is wrong (in HSv5 terms: both sides have set different passwords).
The payloads will be encrypted and the receiver won’t be able to decrypt them.OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_SNDSYN |
post | bool |
true | true | false |
[GET or SET] - When true, sets blocking mode on writing function when
it’s not ready to perform the operation. When false (“non-blocking mode”), the
writing function will in this case report error SRT_EASYNCSND
and return
immediately.
On a connected socket or group this applies to a sending function
(srt_send
and others) and a situation when there’s no free space in
the sender buffer, caused by inability to send all the scheduled data over
the network. Readiness for this operation can be tested by checking the
SRT_EPOLL_OUT
flag.
On a freshly created socket or group it will have no effect until the socket enters a connected state.
On a listener socket it will be derived by the accepted socket or group, but will have no effect on the listener socket itself.
Note that when this flag is set only on a group, it applies to a specific sending operation being done on that group (i.e. it is not derived from the socket of which the group is a member).
OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_SNDTIMEO |
post | int |
msecs | -1 | -1.. |
[GET or SET] - limit the time up to which the sending operation will
block (see SRTO_SNDSYN
for details), so when this time is exceeded, it
will behave as if in “non-blocking mode”. The -1 value means no time limit.
Note that when this flag is set only on a group, it applies to a specific sending operation being done on that group (i.e. it is not derived from the socket of which the group is a member).
OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_STATE |
n/a | int32_t |
n/a | n/a |
SRT_SOCKSTATUS
)OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_STREAMID |
1.3.0 | pre | const char* |
empty | any string |
srt_accept
and was
connected by a socket with that set stream ID (so you usually use SET on the
socket used for srt_connect
and GET on the socket retrieved from srt_accept
).
This string can be used completely free-form, however it’s highly recommended
to follow the SRT Access Control guidlines.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 |
SRTT_LIVE
: Set options as for live transmission. In this mode, you should
send by one sending instruction only so many data that fit in one UDP packet,
and limited to the value defined first in SRTO_PAYLOADSIZE
option (1316 is
default in this mode). There is no speed control in this mode, only the
bandwidth control, if configured, in order to not exceed the bandwidth with
the overhead transmission (retransmitted and control packets).SRTT_FILE
: Set options as for non-live transmission. See SRTO_MESSAGEAPI
for further explanationsOptName | 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.. |
SRTO_MSS
value.OptName | Since | Binding | Type | Units | Default | Range |
---|---|---|---|---|---|---|
SRTO_VERSION |
1.1.0 | n/a | int32_t |
n/a | n/a |
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:
SRTO_TRANSTYPE
: uses the enum value with SRTT_LIVE
for live mode
and SRTT_FILE
for file mode. This option actually changes several parameters to
their default values for that mode. After this is done, additional parameters,
including those that are set here, can be further changed.SRTO_MESSAGEAPI
: This sets the Message API (true) or Buffer API (false)This makes possible a total of three data transmission methods:
NOTE THE TERMS used below:
MJ_AGAIN
category (see SRT_EASYNC*
, SRT_ETIMEOUT
and
SRT_ECONGEST
symbols from SRT_ERRNO
enumeration type), if it’s in
non-blocking mode. In blocking mode it will block until the condition that
caused the HANGUP no longer applies, which is defined as that the function
RESUMES. In nonblocking mode, the function RESUMES when the call to it has done
something and returned the non-error status. The blocking mode in SRT is
separate for sending and receiving and set by SRTO_SNDSYN
and SRTO_RCVSYN
options respectivelySetting SRTO_TRANSTYPE
to SRTT_LIVE
sets the following parameters:
SRTO_TSBPDMODE
= trueSRTO_RCVLATENCY
= 120SRTO_PEERLATENCY
= 0SRTO_TLPKTDROP
= trueSRTO_MESSAGEAPI
= trueSRTO_NAKREPORT
= trueSRTO_PAYLOADSIZE
= 1316SRTO_CONGESTION
= “live”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:
SRTO_TSBPDMODE
: you can turn off controlled latency, if your
application uses some alternative and its own method of latency controlSRTO_RCVLATENCY
: you can increase the latency time, if this is
too short (setting shorter latency than default is strongly
discouraged, although in some very specific and dedicated networks
this may still be reasonable). Note that SRTO_PEERLATENCY
is an option
for the sending party, which is the minimum possible value for a receiver.SRTO_TLPKTDROP
: When true (default), it will drop the packets
that haven’t been retransmitted on time, that is, before the next packet
that is already received becomes ready to play. You can turn this off to always
ensure a clean delivery. However, a lost packet can simply pause a
delivery for some longer, potentially undefined time, and cause even
worse tearing for the player. Setting higher latency will help much more in
the case when TLPKTDROP causes packet drops too often.SRTO_NAKREPORT
: Turns on repeated sending of lossreport, when the lost
packet was not recovered quickly enough, which raises suspicions that the
lossreport itself was lost. Without it, the lossreport will be always reported
just once and never repeated again, and then the lost payload packet will
be probably dropped by the TLPKTDROP mechanism.SRTO_PAYLOADSIZE
: Default value is for MPEG TS; if you are going
to use SRT to send any different kind of payload, such as, for example,
wrapping a live stream in very small frames, then you can use a bigger
maximum frame size, though not greater than 1456 bytes.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.
Setting SRTO_TRANSTYPE
to SRTT_FILE
sets the following parameters:
SRTO_TSBPDMODE
= falseSRTO_RCVLATENCY
= 0SRTO_PEERLATENCY
= 0SRTO_TLPKTDROP
= falseSRTO_MESSAGEAPI
= falseSRTO_NAKREPORT
= falseSRTO_PAYLOADSIZE
= 0SRTO_CONGESTION
= “file”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.
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.