2020-02-13 05:47:51 +00:00
|
|
|
#pragma once
|
2019-03-30 09:51:30 +00:00
|
|
|
|
2019-07-15 06:28:35 +00:00
|
|
|
#ifdef _WIN32
|
2019-08-15 05:38:49 +00:00
|
|
|
#include <winsock2.h>
|
|
|
|
#include <windows.h>
|
2019-07-15 06:28:35 +00:00
|
|
|
#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>
|
2019-07-15 06:28:35 +00:00
|
|
|
#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
|
|
|
|
|
2019-06-17 09:01:23 +00:00
|
|
|
|
2019-07-15 08:49:24 +00:00
|
|
|
#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__linux__)
|
2019-06-17 09:01:23 +00:00
|
|
|
#define PACKED_STRUCT(name) \
|
|
|
|
struct __attribute__((packed)) name
|
2019-07-15 08:49:24 +00:00
|
|
|
#else
|
2020-02-14 12:24:42 +00:00
|
|
|
//#warning "structures are not packed!"
|
2019-07-15 08:49:24 +00:00
|
|
|
#define PACKED_STRUCT(name) struct name
|
2019-06-17 09:01:23 +00:00
|
|
|
#endif
|
|
|
|
|
2020-01-17 11:41:52 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
typedef SOCKET socket_t;
|
|
|
|
#else
|
|
|
|
typedef int socket_t;
|
|
|
|
#endif
|
|
|
|
|
2019-05-17 08:08:40 +00:00
|
|
|
const int MAX_PACKET = 65536;
|
2019-09-06 09:47:26 +00:00
|
|
|
const int MAX_PAYLOAD = 1441;
|
2019-05-17 09:49:33 +00:00
|
|
|
|
2019-05-22 06:39:16 +00:00
|
|
|
typedef enum RTP_ERROR {
|
2020-01-22 08:57:40 +00:00
|
|
|
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 */
|
2020-02-21 07:20:57 +00:00
|
|
|
RTP_TIMEOUT = -12, /* operation timed out */
|
|
|
|
RTP_NOT_FOUND = -13, /* object not found */
|
2019-05-22 06:39:16 +00:00
|
|
|
} rtp_error_t;
|
2019-03-30 09:51:30 +00:00
|
|
|
|
|
|
|
typedef enum RTP_FORMAT {
|
|
|
|
RTP_FORMAT_GENERIC = 0,
|
|
|
|
RTP_FORMAT_HEVC = 96,
|
|
|
|
RTP_FORMAT_OPUS = 97,
|
|
|
|
} rtp_format_t;
|
2019-06-03 08:53:27 +00:00
|
|
|
|
Add support for HEVC slices
The API didn't change much, if user wishes to use HEVC slices
(and thus preserve the state between push_frame() calls), he must
call the push_frame() with RTP_SLICE and RTP_MORE flags, like this:
push_frame(conn, data, 123, RTP_SLICE | RTP_MORE);
push_frame(conn, data, 456, RTP_SLICE | RTP_MORE);
push_frame(conn, data, 789, RTP_SLICE | RTP_MORE);
push_frame(conn, data, 100, RTP_SLICE);
RTP_MORE preserves the state between push_frame() calls and when the
last slice is given to kvzRTP, the RTP_MORE flags must be removed.
This flushes the frame queue and deinitializes it.
2019-09-24 05:54:09 +00:00
|
|
|
typedef enum RTP_FLAGS {
|
|
|
|
RTP_NO_FLAGS = 0 << 0,
|
|
|
|
|
|
|
|
/* TODO */
|
|
|
|
RTP_SLICE = 1 << 0,
|
|
|
|
|
|
|
|
/* TODO */
|
|
|
|
RTP_MORE = 1 << 1,
|
2019-10-11 07:17:49 +00:00
|
|
|
|
|
|
|
/* 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,
|
Add support for HEVC slices
The API didn't change much, if user wishes to use HEVC slices
(and thus preserve the state between push_frame() calls), he must
call the push_frame() with RTP_SLICE and RTP_MORE flags, like this:
push_frame(conn, data, 123, RTP_SLICE | RTP_MORE);
push_frame(conn, data, 456, RTP_SLICE | RTP_MORE);
push_frame(conn, data, 789, RTP_SLICE | RTP_MORE);
push_frame(conn, data, 100, RTP_SLICE);
RTP_MORE preserves the state between push_frame() calls and when the
last slice is given to kvzRTP, the RTP_MORE flags must be removed.
This flushes the frame queue and deinitializes it.
2019-09-24 05:54:09 +00:00
|
|
|
} rtp_flags_t;
|
|
|
|
|
2020-01-08 08:55:00 +00:00
|
|
|
/* These flags are given when kvzRTP context is created */
|
2020-01-13 08:00:02 +00:00
|
|
|
enum RTP_CTX_ENABLE_FLAGS {
|
|
|
|
RTP_CTX_NO_FLAGS = 0 << 0,
|
2020-01-08 08:55:00 +00:00
|
|
|
|
|
|
|
/* Use optimistic receiver (HEVC only) */
|
|
|
|
RCE_OPTIMISTIC_RECEIVER = 1 << 0,
|
|
|
|
|
|
|
|
/* Enable system call dispatcher (HEVC only) */
|
|
|
|
RCE_SYSTEM_CALL_DISPATCHER = 1 << 2,
|
|
|
|
|
2020-01-22 08:57:40 +00:00
|
|
|
/* Use SRTP for this connection */
|
2020-04-24 08:31:40 +00:00
|
|
|
RCE_SRTP = 1 << 3,
|
2020-01-22 08:57:40 +00:00
|
|
|
|
|
|
|
/* Use ZRTP for key management
|
|
|
|
*
|
|
|
|
* TODO selitä paremmin */
|
|
|
|
RCE_SRTP_KMNGMNT_ZRTP = 1 << 4,
|
|
|
|
|
|
|
|
/* Use user-defined way to manage keys
|
|
|
|
*
|
|
|
|
* TODO selitä paremmin */
|
|
|
|
RCE_SRTP_KMNGMNT_USER = 1 << 4,
|
|
|
|
|
2020-04-21 13:10:49 +00:00
|
|
|
/* When kvzRTP 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, kvzRTP 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, kvzRTP 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, kvzRTP treats all frame types
|
|
|
|
* equally and drops all frames that are late */
|
2020-04-24 08:31:40 +00:00
|
|
|
RCE_HEVC_NO_INTRA_DELAY = 1 << 5,
|
|
|
|
|
2020-04-24 18:20:27 +00:00
|
|
|
/* Fragment generic frames into RTP packets of 1500 bytes.
|
|
|
|
*
|
|
|
|
* If RCE_FRAGMENT_GENERIC is given to create_stream(), kvzRTP 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 kvzRTP so it
|
|
|
|
* will break interoperability between libraries if enabled.
|
|
|
|
*
|
|
|
|
* RCE_FRAGMENT_GENERIC can be used, for example, when you're using kvzRTP for
|
|
|
|
* both sender and receiver and the media stream you wish to stream is not supported
|
|
|
|
* by kvzRTP but requires packetization because MEDIA_FRAME_SIZE > MTU */
|
|
|
|
RCE_FRAGMENT_GENERIC = 1 << 6,
|
|
|
|
|
|
|
|
RCE_LAST = 1 << 7,
|
2020-04-21 13:10:49 +00:00
|
|
|
};
|
|
|
|
|
2020-01-08 08:55:00 +00:00
|
|
|
/* These options are given to configuration() */
|
2020-01-13 08:00:02 +00:00
|
|
|
enum RTP_CTX_CONFIGURATION_FLAGS {
|
2020-01-08 08:55:00 +00:00
|
|
|
/* No configuration flags */
|
|
|
|
RCC_NO_FLAGS = 0,
|
|
|
|
|
|
|
|
/* How many packets can be fit into
|
|
|
|
* probation zone until they overflow to separate frames.
|
|
|
|
*
|
|
|
|
* By default, probation zone is disabled
|
|
|
|
*
|
|
|
|
* NOTE: how many **packets**, not bytes */
|
|
|
|
RCC_PROBATION_ZONE_SIZE = 1,
|
|
|
|
|
2020-01-22 08:57:40 +00:00
|
|
|
/* How many transactions can be cached for later use
|
2020-01-08 08:55:00 +00:00
|
|
|
* Caching transactions improves performance by reducing
|
|
|
|
* the number of (de)allocations but increases the memory
|
|
|
|
* footprint of the program
|
|
|
|
*
|
|
|
|
* By default, 10 transactions are cached */
|
|
|
|
RCC_MAX_TRANSACTIONS = 2,
|
|
|
|
|
|
|
|
/* How many UDP packets does one transaction object hold.
|
|
|
|
*
|
|
|
|
* kvzRTP splits one input frame [argument of push_frame()] into
|
|
|
|
* multiple UDP packets, each of size 1500 bytes. This UDP packets
|
|
|
|
* are stored into a transaction object.
|
|
|
|
*
|
2020-01-22 08:57:40 +00:00
|
|
|
* Video with high bitrate may require large value for "RCC_MAX_MESSAGES"
|
2020-01-08 08:55:00 +00:00
|
|
|
*
|
|
|
|
* By default, it is set to 500 (ie. one frame can take up to 500 * 1500 bytes) */
|
|
|
|
RCC_MAX_MESSAGES = 3,
|
|
|
|
|
|
|
|
/* How many chunks each UDP packet can at most contain
|
|
|
|
*
|
|
|
|
* By default, this is set to 4 */
|
|
|
|
RCC_MAX_CHUNKS_PER_MSG = 4,
|
|
|
|
|
2020-01-13 08:00:02 +00:00
|
|
|
/* How large is the receiver/sender UDP buffer size
|
2020-01-08 08:55:00 +00:00
|
|
|
*
|
|
|
|
* 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 */
|
2020-01-13 08:00:02 +00:00
|
|
|
RCC_UDP_BUF_SIZE = 5,
|
2020-01-08 08:55:00 +00:00
|
|
|
|
2020-01-13 08:00:02 +00:00
|
|
|
RCC_LAST
|
2020-04-16 08:00:07 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum NOTIFY_REASON {
|
|
|
|
|
|
|
|
/* Timer for the active frame has expired and it has been dropped */
|
|
|
|
NR_FRAME_DROPPED = 0,
|
2020-01-13 08:00:02 +00:00
|
|
|
};
|
2020-01-08 08:55:00 +00:00
|
|
|
|
|
|
|
/* see src/util.hh for more information */
|
|
|
|
typedef struct rtp_ctx_conf {
|
2020-01-13 08:00:02 +00:00
|
|
|
int flags;
|
|
|
|
ssize_t ctx_values[RCC_LAST];
|
2020-01-08 08:55:00 +00:00
|
|
|
} rtp_ctx_conf_t;
|
|
|
|
|
2019-06-17 06:59:32 +00:00
|
|
|
extern thread_local rtp_error_t rtp_errno;
|
2019-06-03 08:53:27 +00:00
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
2019-06-20 06:25:01 +00:00
|
|
|
|
|
|
|
static inline void set_bytes(int *ptr, int nbytes)
|
|
|
|
{
|
|
|
|
if (ptr)
|
|
|
|
*ptr = nbytes;
|
|
|
|
}
|
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;
|
|
|
|
}
|