uvgrtp-base/include/util.hh

284 lines
9.2 KiB
C++

#pragma once
#ifdef _WIN32
#include <winsock2.h>
#include <windows.h>
#else
#include <sys/time.h>
#endif
#include <algorithm>
#include <cstdint>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <string>
#if defined(_MSC_VER)
typedef SSIZE_T ssize_t;
#endif
#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__linux__)
#define PACKED_STRUCT(name) \
struct __attribute__((packed)) name
#else
//#warning "structures are not packed!"
#define PACKED_STRUCT(name) struct name
#endif
#ifdef _WIN32
typedef SOCKET socket_t;
#else
typedef int socket_t;
#endif
const int MAX_PACKET = 65536;
const int MAX_PAYLOAD = 1443;
typedef enum RTP_ERROR {
RTP_PKT_READY = 5, /* packet can be returned to user */
RTP_PKT_MODIFIED = 4, /* packet was modified by the layer (see src/pkt_dispatch.cc) */
RTP_PKT_NOT_HANDLED = 3, /* packet does not belong to this layer */
RTP_INTERRUPTED = 2,
RTP_NOT_READY = 1,
RTP_OK = 0,
RTP_GENERIC_ERROR = -1,
RTP_SOCKET_ERROR = -2,
RTP_BIND_ERROR = -3,
RTP_INVALID_VALUE = -4,
RTP_SEND_ERROR = -5,
RTP_MEMORY_ERROR = -6,
RTP_SSRC_COLLISION = -7,
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, /* 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;
typedef enum RTP_FORMAT {
RTP_FORMAT_GENERIC = 0,
RTP_FORMAT_HEVC = 96,
RTP_FORMAT_OPUS = 97,
} rtp_format_t;
typedef enum RTP_FLAGS {
RTP_NO_FLAGS = 0 << 0,
/* TODO */
RTP_SLICE = 1 << 0,
/* TODO */
RTP_MORE = 1 << 1,
/* Make a copy of "data" given to push_frame()
*
* This is an easy way out of the memory ownership/deallocation problem
* for the application but can significantly damage the performance
*
* NOTE: Copying is necessary only when the following conditions are met:
* - SCD is enabled
* - Media format is such that it uses SCD (HEVC is the only for now)
* - Application hasn't provided a deallocation callback
* - Application doens't use unique_ptrs
*
* If all of those conditions are met, then it's advised to pass RTP_COPY.
* Otherwise there might be a lot of leaked memory */
RTP_COPY = 1 << 2,
} rtp_flags_t;
/* These flags are given when uvgRTP context is created */
enum RTP_CTX_ENABLE_FLAGS {
RTP_CTX_NO_FLAGS = 0 << 0,
/* Use optimistic receiver (HEVC only) */
RCE_OPTIMISTIC_RECEIVER = 1 << 0,
/* Enable system call dispatcher (HEVC only) */
RCE_SYSTEM_CALL_DISPATCHER = 1 << 2,
/* Use SRTP for this connection */
RCE_SRTP = 1 << 3,
/* Use ZRTP for key management
*
* 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 << 4,
/* Use user-defined way to manage keys
*
* 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 << 5,
/* When uvgRTP is receiving HEVC stream, as an attempt to improve
* QoS, it will set frame delay for intra frames to be the same
* as intra period.
*
* What this means is that if the regular timer expires for frame
* (100 ms) and the frame type is intra, uvgRTP will not drop the
* frame but will continue receiving packets in hopes that all the
* packets of the intra frame will be received and the frame can be
* returned to user. During this period, when the intra frame is deemed
* to be late and incomplete, uvgRTP will drop all inter frames until
* a) all the packets of late intra frame are received or
* b) a new intra frame is received
*
* This behaviour should reduce the number of gray screens during
* HEVC decoding but might cause the video stream to freeze for a while
* which is subjectively lesser of two evils
*
* This behavior can be disabled with RCE_HEVC_NO_INTRA_DELAY
* If this flag is given, uvgRTP treats all frame types
* equally and drops all frames that are late */
RCE_HEVC_NO_INTRA_DELAY = 1 << 5,
/* Fragment generic frames into RTP packets of 1500 bytes.
*
* If RCE_FRAGMENT_GENERIC is given to create_stream(), uvgRTP will split frames
* of type RTP_FORMAT_GENERIC into packets of 1500 bytes automatically and reconstruct
* the full frame from the fragments in the receiver
*
* This behavior is not from any specification and only supported by uvgRTP so it
* will break interoperability between libraries if enabled.
*
* RCE_FRAGMENT_GENERIC can be used, for example, when you're using uvgRTP for
* both sender and receiver and the media stream you wish to stream is not supported
* by uvgRTP but requires packetization because MEDIA_FRAME_SIZE > MTU */
RCE_FRAGMENT_GENERIC = 1 << 6,
/* If SRTP is enabled and RCE_INPLACE_ENCRYPTION flag is *not* given,
* 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 << 7,
/* Disable System Call Clustering (SCC), System Call Dispatching is still usable */
RCE_NO_SYSTEM_CALL_CLUSTERING = 1 << 8,
/* Make the media stream unidirectional, i.e. sender/receiver only */
RCE_UNIDIRECTIONAL = 1 << 9,
/* Media stream is only used for sending
* Mutually exclusive with RCE_UNIDIR_RECEIVER */
RCE_UNIDIR_SENDER = 1 << 10,
/* Media stream is only used for receiving
* Mutually exclusive with RCE_UNIDIR_SENDER */
RCE_UNIDIR_RECEIVER = 1 << 11,
/* Disable RTP payload encryption */
RCE_SRTP_NULL_CIPHER = 1 << 12,
/* 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 << 13,
/* Enable RTCP for the media stream.
* If SRTP is enabled, SRTCP is used instead */
RCE_RTCP = 1 << 14,
RCE_LAST = 1 << 15,
};
/* These options are given to configuration() */
enum RTP_CTX_CONFIGURATION_FLAGS {
/* No configuration flags */
RCC_NO_FLAGS = 0,
/* How large is the receiver/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_RCV_BUF_SIZE = 1,
RCC_UDP_SND_BUF_SIZE = 2,
RCC_LAST
};
enum NOTIFY_REASON {
/* Timer for the active frame has expired and it has been dropped */
NR_FRAME_DROPPED = 0,
};
/* see src/util.hh for more information */
typedef struct rtp_ctx_conf {
int flags;
ssize_t ctx_values[RCC_LAST];
} rtp_ctx_conf_t;
extern thread_local rtp_error_t rtp_errno;
#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;
}
static inline void *memdup(const void *src, size_t len)
{
uint8_t *dst = new uint8_t[len];
std::memcpy(dst, src, len);
return dst;
}
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;
}