uvgrtp-base/include/uvgrtp/util.hh

409 lines
13 KiB
C++
Raw Normal View History

/// \file util.hh
2020-02-13 05:47:51 +00:00
#pragma once
2019-03-30 09:51:30 +00:00
/// \cond DO_NOT_DOCUMENT
#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#else
#include <sys/time.h>
#endif
#include <algorithm>
2019-03-30 09:51:30 +00:00
#include <cstdint>
2019-05-17 09:49:33 +00:00
#include <cstddef>
2019-06-14 08:34:10 +00:00
#include <cstdio>
2020-08-04 07:16:38 +00:00
#include <cstring>
#include <string>
2019-03-30 09:51:30 +00:00
2020-02-14 12:24:42 +00:00
#if defined(_MSC_VER)
typedef SSIZE_T ssize_t;
#endif
/* https://stackoverflow.com/questions/1537964/visual-c-equivalent-of-gccs-attribute-packed */
#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__GNUC__) || defined(__linux__)
#define PACK(__Declaration__) __Declaration__ __attribute__((__packed__))
2019-07-15 08:49:24 +00:00
#else
#define PACK(__Declaration__) __pragma(pack(push, 1)) __Declaration__ __pragma(pack(pop))
#endif
#ifdef _WIN32
typedef SOCKET socket_t;
#else
typedef int socket_t;
#endif
2021-02-13 02:33:03 +00:00
const int MAX_PACKET = 65536;
const int MAX_PAYLOAD = 1446;
2022-06-17 07:29:46 +00:00
const int PKT_MAX_DELAY = 500;
2021-02-13 02:33:03 +00:00
/* TODO: add ability for user to specify these? */
// TODO: IPv6 size is 40
2021-02-13 02:33:03 +00:00
enum HEADER_SIZES {
ETH_HDR_SIZE = 14,
IPV4_HDR_SIZE = 20,
UDP_HDR_SIZE = 8,
RTP_HDR_SIZE = 12
};
/// \endcond
/**
* \enum RTP_ERROR
*
* \brief RTP error codes
*
* \details These error valus are returned from various uvgRTP functions. Functions that return a pointer set rtp_errno global value that should be checked if a function call failed
*/
typedef enum RTP_ERROR {
RTP_MULTIPLE_PKTS_READY = 6,
RTP_PKT_READY = 5,
RTP_PKT_MODIFIED = 4,
RTP_PKT_NOT_HANDLED = 3,
RTP_INTERRUPTED = 2,
RTP_NOT_READY = 1,
RTP_OK = 0, ///< Success
RTP_GENERIC_ERROR = -1, ///< Generic error condition
RTP_SOCKET_ERROR = -2, ///< Failed to create socket
RTP_BIND_ERROR = -3, ///< Failed to bind to interface
RTP_INVALID_VALUE = -4, ///< Invalid value
RTP_SEND_ERROR = -5, ///< System call send(2) or one of its derivatives failed
RTP_MEMORY_ERROR = -6, ///< Memory allocation failed
RTP_SSRC_COLLISION = -7, ///< SSRC collision detected
RTP_INITIALIZED = -8, ///< Object already initialized
RTP_NOT_INITIALIZED = -9, ///< Object has not been initialized
RTP_NOT_SUPPORTED = -10, ///< Method/version/extension not supported
RTP_RECV_ERROR = -11, ///< System call recv(2) or one of its derivatives failed
RTP_TIMEOUT = -12, ///< Operation timed out
RTP_NOT_FOUND = -13, ///< Object not found
RTP_AUTH_TAG_MISMATCH = -14, ///< Authentication tag does not match the RTP packet contents
} rtp_error_t;
2019-03-30 09:51:30 +00:00
/**
* \enum RTP_FORMAT
*
* \brief These flags are given to uvgrtp::session::create_stream()
*/
2019-03-30 09:51:30 +00:00
typedef enum RTP_FORMAT {
// See RFC 3551 for more details
// static audio profiles
RTP_FORMAT_GENERIC = 0, ///< Same as PCMU
RTP_FORMAT_PCMU = 0, ///< PCMU, ITU-T G.711
// 1 is reserved in RFC 3551
// 2 is reserved in RFC 3551
RTP_FORMAT_GSM = 3, ///< GSM (Group Speciale Mobile)
RTP_FORMAT_G723 = 4, ///< G723
RTP_FORMAT_DVI4_32 = 5, ///< DVI 32 kbit/s
RTP_FORMAT_DVI4_64 = 6, ///< DVI 64 kbit/s
RTP_FORMAT_LPC = 7, ///< LPC
RTP_FORMAT_PCMA = 8, ///< PCMA
RTP_FORMAT_G722 = 9, ///< G722
RTP_FORMAT_L16_STEREO = 10, ///< L16 Stereo
RTP_FORMAT_L16_MONO = 11, ///< L16 Mono
// 12 QCELP is unsupported in uvgRTP
// 13 CN is unsupported in uvgRTP
// 14 MPA is unsupported in uvgRTP
RTP_FORMAT_G728 = 15, ///< G728
RTP_FORMAT_DVI4_441 = 16, ///< DVI 44.1 kbit/s
RTP_FORMAT_DVI4_882 = 17, ///< DVI 88.2 kbit/s
RTP_FORMAT_G729 = 18, ///< G729, 8 kbit/s
// 19 is reserved in RFC 3551
// 20 - 23 are unassigned in RFC 3551
/* static video profiles, unsupported in uvgRTP
* 24 is unassigned
* 25 is CelB,
* 26 is JPEG
* 27 is unassigned
* 28 is nv
* 29 is unassigned
* 30 is unassigned
* 31 is H261
* 32 is MPV
* 33 is MP2T
* 32 is H263
*/
/* Rest of static numbers
* 35 - 71 are unassigned
* 72 - 76 are reserved
* 77 - 95 are unassigned
*/
/* Formats with dynamic payload numbers 96 - 127, including default values.
* Use RCC_DYN_PAYLOAD_TYPE flag to change the number if desired. */
RTP_FORMAT_G726_40 = 96, ///< G726, 40 kbit/s
RTP_FORMAT_G726_32 = 97, ///< G726, 32 kbit/s
RTP_FORMAT_G726_24 = 98, ///< G726, 24 kbit/s
RTP_FORMAT_G726_16 = 99, ///< G726, 16 kbit/s
RTP_FORMAT_G729D = 100, ///< G729D, 6.4 kbit/s
RTP_FORMAT_G729E = 101, ///< G729E, 11.8 kbit/s
RTP_FORMAT_GSM_EFR = 102, ///< GSM enhanced full rate speech transcoding
RTP_FORMAT_L8 = 103, ///< L8, linear audio data samples
// RED is unsupported in uvgRTP
RTP_FORMAT_VDVI = 104, ///< VDVI, variable-rate DVI4
RTP_FORMAT_OPUS = 105, ///< Opus, see RFC 7587
// H263-1998 is unsupported in uvgRTP
RTP_FORMAT_H264 = 106, ///< H.264/AVC, see RFC 6184
RTP_FORMAT_H265 = 107, ///< H.265/HEVC, see RFC 7798
RTP_FORMAT_H266 = 108 ///< H.266/VVC
2019-03-30 09:51:30 +00:00
} rtp_format_t;
/**
* \enum RTP_FLAGS
*
* \brief These flags are given to uvgrtp::media_stream::push_frame()
* and they can be OR'ed together
*/
typedef enum RTP_FLAGS {
/** No flags */
RTP_NO_FLAGS = 0 << 0,
/** Obsolete */
RTP_SLICE = 1 << 0,
/** Not implemented, may be implemented in the future */
RTP_COPY = 1 << 1,
/** By default, uvgRTP searches for start code prefixes (0x000001 or 0x00000001)
* from the frame to divide NAL units and remove the prefix. If you instead
* want to provide the NAL units without the start code prefix yourself,
* you may use this flag to disable Start Code Lookup (SCL) and the frames
* will be treated as send-ready NAL units. */
RTP_NO_H26X_SCL = 1 << 2
} rtp_flags_t;
/**
* \enum RTP_CTX_ENABLE_FLAGS
*
* \brief RTP context enable flags
*
* \details These flags are passed to uvgrtp::session::create_stream and can be OR'ed together
*/
enum RTP_CTX_ENABLE_FLAGS {
RCE_NO_FLAGS = 0,
// Obsolete flags
RCE_SYSTEM_CALL_DISPATCHER = 0,
RCE_NO_H26X_INTRA_DELAY = 0,
RCE_NO_H26X_SCL = 0,
RCE_H26X_NO_DEPENDENCY_ENFORCEMENT = 0,
/** Use SRTP for this connection */
RCE_SRTP = 1,
/** Use ZRTP for key management
*
2020-07-30 06:41:01 +00:00
* If this flag is provided, before the session starts,
* ZRTP will negotiate keys with the remote participants
* and these keys are used as salting/keying material for the session.
*
* This flag must be coupled with RCE_SRTP and is mutually exclusive
* with RCE_SRTP_KMNGMNT_USER. */
RCE_SRTP_KMNGMNT_ZRTP = 1 << 1,
/** Use user-defined way to manage keys
*
2020-07-30 06:41:01 +00:00
* If this flag is provided, before the media transportation starts,
* user must provide a master key and salt form which SRTP session
* keys are derived
*
* This flag must be coupled with RCE_SRTP and is mutually exclusive
* with RCE_SRTP_KMNGMNT_ZRTP */
RCE_SRTP_KMNGMNT_USER = 1 << 2,
/** By default, the RTP packet payload does not include the start code prefixes.
* Use this flag to prepend the 4-byte start code (0x00000001) to each received
* H26x frame, so there is no difference with sender input. Recommended in
* most cases. */
RCE_H26X_PREPEND_SC = 1 << 3,
/** Use this flag to discard inter frames that don't have their previous dependencies
arrived. Does not work if the dependencies are not in monotonic order. */
RCE_H26X_DEPENDENCY_ENFORCEMENT = 1 << 4,
2022-04-01 05:24:37 +00:00
/** Fragment frames into RTP packets of MTU size (1500 bytes).
*
* Some RTP profiles define fragmentation with marker bit indicating the end of frame.
* You can enable this functionality using this flag at both sender and receiver.
*/
RCE_FRAGMENT_GENERIC = 1 << 5,
/** If SRTP is enabled and RCE_INPLACE_ENCRYPTION flag is *not* given,
2020-04-27 11:07:24 +00:00
* uvgRTP will make a copy of the frame given to push_frame().
*
* If the frame is writable and the application no longer needs the frame,
* RCE_INPLACE_ENCRYPTION should be given to create_stream() to prevent
* unnecessary copy operations.
*
* If RCE_INPLACE_ENCRYPTION is given to push_frame(), the input pointer must be writable! */
RCE_SRTP_INPLACE_ENCRYPTION = 1 << 6,
/** Disable System Call Clustering (SCC) */
RCE_NO_SYSTEM_CALL_CLUSTERING = 1 << 7,
2020-05-28 09:24:18 +00:00
/** Disable RTP payload encryption */
RCE_SRTP_NULL_CIPHER = 1 << 8,
2020-07-30 08:47:11 +00:00
/** Enable RTP packet authentication
*
* This flag forces the security layer to add authentication tag
* to each outgoing RTP packet for all streams that have SRTP enabled.
*
* NOTE: this flag must be coupled with at least RCE_SRTP */
RCE_SRTP_AUTHENTICATE_RTP = 1 << 9,
/** Enable packet replay protection */
RCE_SRTP_REPLAY_PROTECTION = 1 << 10,
2020-09-04 06:03:28 +00:00
/** Enable RTCP for the media stream.
* If SRTP is enabled, SRTCP is used instead */
RCE_RTCP = 1 << 11,
2022-04-01 05:24:37 +00:00
/** If the Mediastream object is used as a unidirectional stream
2021-02-14 01:36:27 +00:00
* but holepunching has been enabled, this flag can be used to make
* uvgRTP periodically send a short UDP datagram to keep the hole
* in the firewall open */
RCE_HOLEPUNCH_KEEPALIVE = 1 << 12,
2021-02-14 01:36:27 +00:00
/** Use 192-bit keys with SRTP */
RCE_SRTP_KEYSIZE_192 = 1 << 13,
/** Use 256-bit keys with SRTP */
RCE_SRTP_KEYSIZE_256 = 1 << 14,
RCE_ZRTP_MULTISTREAM_NO_DH = 1 << 16,
RCE_LAST = 1 << 17,
};
/**
* \enum RTP_CTX_CONFIGURATION_FLAGS
*
* \brief RTP context configuration flags
*
* \details These flags are given to uvgrtp::media_stream::configure_ctx
*/
enum RTP_CTX_CONFIGURATION_FLAGS {
RCC_NO_FLAGS = 0,
/** How large is the receiver UDP buffer size
*
* Default value is 4 MB
*
* For video with high bitrate, it is advisable to set this
* to a high number to prevent OS from dropping packets */
RCC_UDP_RCV_BUF_SIZE = 1,
/** How large is the sender UDP buffer size
*
* Default value is 4 MB
*
* For video with high bitrate, it is advisable to set this
* to a high number to prevent OS from dropping packets */
RCC_UDP_SND_BUF_SIZE = 2,
/** How many milliseconds is each frame waited for until it is considered lost.
2021-02-12 12:05:35 +00:00
*
* Default is 500 milliseconds
2021-02-12 12:05:35 +00:00
*
* This is valid only for fragmented frames,
* i.e. RTP_FORMAT_H26X and RTP_FORMAT_GENERIC with RCE_FRAGMENT_GENERIC (TODO) */
RCC_PKT_MAX_DELAY = 3,
/** Overwrite uvgRTP's own payload type in RTP packets and specify your own
* dynamic payload type for all packets of an RTP stream */
RCC_DYN_PAYLOAD_TYPE = 4,
/** Set a maximum value for the Ethernet frame size assumed by uvgRTP.
2021-02-13 02:33:03 +00:00
*
* Default is 1500, from this Ethernet, IPv4 and UDP, and RTP headers
* are removed from this, giving a payload size of 1446 bytes
*
* If application wishes to use small UDP datagrams for some reason,
* it can set MTU size to, for example, 500 bytes or if it wishes
* to use jumbo frames, it can set the MTU size to 9000 bytes */
RCC_MTU_SIZE = 5,
/** Set the enumerator of frame rate enforced by uvgRTP.
*
* Default is 30.
*
* Setting a positive value enables this functionality. Setting it to 0 or less, disables it.
*
* The fps API paces the sending of the RTP packets so that receiver is under less
* strain to receive all. Setting this is not neccessary for small frame sizes,
* but even then it makes the stream smoother. The cost is at most one frame extra latency. */
RCC_FPS_ENUMERATOR = 6,
/** Set the denominator of frame rate enforced by uvgRTP.
*
* Default is 1.
*
* Setting a positive value enables this functionality. Setting it to 0 or less, disables it.
*
* Setting the denominator is only necessary for fractional fps values as setting the enumerator
* already enables the fps functionality. */
RCC_FPS_DENOMINATOR = 7,
2022-08-19 12:22:43 +00:00
RCC_LAST
};
extern thread_local rtp_error_t rtp_errno;
2020-07-28 07:35:21 +00:00
#define TIME_DIFF(s, e, u) ((ssize_t)std::chrono::duration_cast<std::chrono::u>(e - s).count())
#define SET_NEXT_FIELD_32(a, p, v) do { *(uint32_t *)&(a)[p] = (v); p += 4; } while (0)
#define SET_FIELD_32(a, i, v) do { *(uint32_t *)&(a)[i] = (v); } while (0)
static inline void hex_dump(uint8_t *buf, size_t len)
{
if (!buf)
return;
for (size_t i = 0; i < len; i += 10) {
fprintf(stderr, "\t");
for (size_t k = i; k < i + 10; ++k) {
fprintf(stderr, "0x%02x ", buf[k]);
}
fprintf(stderr, "\n");
}
}
static inline void set_bytes(int *ptr, int nbytes)
{
if (ptr)
*ptr = nbytes;
}
2019-06-26 04:52:07 +00:00
2020-08-04 07:16:38 +00:00
static inline void *memdup(const void *src, size_t len)
{
uint8_t *dst = new uint8_t[len];
std::memcpy(dst, src, len);
return dst;
}
2019-06-26 04:52:07 +00:00
static inline std::string generate_string(size_t length)
{
auto randchar = []() -> char
{
const char charset[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const size_t max_index = (sizeof(charset) - 1);
return charset[ rand() % max_index ];
};
std::string str(length, 0);
std::generate_n(str.begin(), length, randchar);
return str;
}
/// \endcond