update toxcore, toxav fixes merged
Some checks are pending
ContinuousDelivery / linux-ubuntu (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android]) (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android]) (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android]) (push) Waiting to run
ContinuousDelivery / windows (push) Waiting to run
ContinuousDelivery / windows-asan (push) Waiting to run
ContinuousDelivery / release (push) Blocked by required conditions
ContinuousIntegration / linux (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android]) (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android]) (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android]) (push) Waiting to run
ContinuousIntegration / macos (push) Waiting to run
ContinuousIntegration / windows (push) Waiting to run
Some checks are pending
ContinuousDelivery / linux-ubuntu (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android]) (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android]) (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android]) (push) Waiting to run
ContinuousDelivery / windows (push) Waiting to run
ContinuousDelivery / windows-asan (push) Waiting to run
ContinuousDelivery / release (push) Blocked by required conditions
ContinuousIntegration / linux (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android]) (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android]) (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android]) (push) Waiting to run
ContinuousIntegration / macos (push) Waiting to run
ContinuousIntegration / windows (push) Waiting to run
Merge commit 'cae0ab9c5c75eda665d21dc36cfeef48c1e04b53'
This commit is contained in:
395
external/toxcore/c-toxcore/toxav/rtp.c
vendored
395
external/toxcore/c-toxcore/toxav/rtp.c
vendored
@ -9,12 +9,16 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bwcontroller.h"
|
||||
#include <sodium.h>
|
||||
|
||||
#include "bwcontroller.h"
|
||||
#include "toxav_hacks.h"
|
||||
|
||||
#include "../toxcore/Messenger.h"
|
||||
#include "../toxcore/ccompat.h"
|
||||
#include "../toxcore/logger.h"
|
||||
#include "../toxcore/mono_time.h"
|
||||
#include "../toxcore/net_crypto.h"
|
||||
#include "../toxcore/tox_private.h"
|
||||
#include "../toxcore/util.h"
|
||||
|
||||
/**
|
||||
@ -23,30 +27,15 @@
|
||||
*/
|
||||
#define VIDEO_KEEP_KEYFRAME_IN_BUFFER_FOR_MS 15
|
||||
|
||||
/**
|
||||
* return -1 on failure, 0 on success
|
||||
*
|
||||
*/
|
||||
static int rtp_send_custom_lossy_packet(Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t length)
|
||||
{
|
||||
Tox_Err_Friend_Custom_Packet error;
|
||||
tox_friend_send_lossy_packet(tox, friendnumber, data, (size_t)length, &error);
|
||||
|
||||
if (error == TOX_ERR_FRIEND_CUSTOM_PACKET_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// allocate_len is NOT including header!
|
||||
static struct RTPMessage *new_message(const struct RTPHeader *header, size_t allocate_len, const uint8_t *data,
|
||||
uint16_t data_length)
|
||||
static struct RTPMessage *new_message(const Logger *log, const struct RTPHeader *header, size_t allocate_len,
|
||||
const uint8_t *data, uint16_t data_length)
|
||||
{
|
||||
assert(allocate_len >= data_length);
|
||||
struct RTPMessage *msg = (struct RTPMessage *)calloc(1, sizeof(struct RTPMessage) + allocate_len);
|
||||
|
||||
if (msg == nullptr) {
|
||||
LOGGER_DEBUG(log, "Could not allocate RTPMessage buffer");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -241,7 +230,7 @@ static struct RTPMessage *process_frame(const Logger *log, struct RTPWorkBufferL
|
||||
}
|
||||
|
||||
/**
|
||||
* @param log A logger.
|
||||
* @param log A pointer to the Logger object.
|
||||
* @param wkbl The list of in-progress frames, i.e. all the slots.
|
||||
* @param slot_id The slot we want to fill the data into.
|
||||
* @param is_keyframe Whether the data is part of a key frame.
|
||||
@ -309,7 +298,7 @@ static bool fill_data_into_slot(const Logger *log, struct RTPWorkBufferList *wkb
|
||||
return slot->received_len == header->data_length_full;
|
||||
}
|
||||
|
||||
static void update_bwc_values(const Logger *log, RTPSession *session, const struct RTPMessage *msg)
|
||||
static void update_bwc_values(RTPSession *session, const struct RTPMessage *msg)
|
||||
{
|
||||
if (session->first_packets_counter < DISMISS_FIRST_LOST_VIDEO_PACKET_COUNT) {
|
||||
++session->first_packets_counter;
|
||||
@ -319,7 +308,7 @@ static void update_bwc_values(const Logger *log, RTPSession *session, const stru
|
||||
bwc_add_recv(session->bwc, data_length_full);
|
||||
|
||||
if (received_length_full < data_length_full) {
|
||||
LOGGER_DEBUG(log, "BWC: full length=%u received length=%d", data_length_full, received_length_full);
|
||||
LOGGER_DEBUG(session->log, "BWC: full length=%u received length=%d", data_length_full, received_length_full);
|
||||
bwc_add_lost(session->bwc, data_length_full - received_length_full);
|
||||
}
|
||||
}
|
||||
@ -347,22 +336,16 @@ static void update_bwc_values(const Logger *log, RTPSession *session, const stru
|
||||
* @retval -1 on error.
|
||||
* @retval 0 on success.
|
||||
*/
|
||||
static int handle_video_packet(RTPSession *session, const struct RTPHeader *header,
|
||||
const uint8_t *incoming_data, uint16_t incoming_data_length, const Logger *log)
|
||||
static int handle_video_packet(const Logger *log, RTPSession *session, const struct RTPHeader *header,
|
||||
const uint8_t *incoming_data, uint16_t incoming_data_length)
|
||||
{
|
||||
// Full frame length in bytes. The frame may be split into multiple packets,
|
||||
// but this value is the complete assembled frame size.
|
||||
const uint32_t full_frame_length = header->data_length_full;
|
||||
|
||||
// Current offset in the frame. If this is the first packet of a multipart
|
||||
// frame or it's not a multipart frame, then this value is 0.
|
||||
const uint32_t offset = header->offset_full; // without header
|
||||
|
||||
// The sender tells us whether this is a key frame.
|
||||
const bool is_keyframe = (header->flags & RTP_KEY_FRAME) != 0;
|
||||
|
||||
LOGGER_DEBUG(log, "-- handle_video_packet -- full lens=%u len=%u offset=%u is_keyframe=%s",
|
||||
(unsigned)incoming_data_length, (unsigned)full_frame_length, (unsigned)offset, is_keyframe ? "K" : ".");
|
||||
LOGGER_DEBUG(log, "wkbl->next_free_entry:003=%d", session->work_buffer_list->next_free_entry);
|
||||
|
||||
const bool is_multipart = full_frame_length != incoming_data_length;
|
||||
@ -387,10 +370,13 @@ static int handle_video_packet(RTPSession *session, const struct RTPHeader *head
|
||||
// get_slot just told us it's full, so process_frame must return non-null.
|
||||
assert(m_new != nullptr);
|
||||
|
||||
LOGGER_DEBUG(log, "-- handle_video_packet -- CALLBACK-001a b0=%d b1=%d", (int)m_new->data[0], (int)m_new->data[1]);
|
||||
update_bwc_values(log, session, m_new);
|
||||
LOGGER_DEBUG(log, "-- handle_video_packet -- CALLBACK-001a b0=%d b1=%d", (int)m_new->data[0],
|
||||
(int)m_new->data[1]);
|
||||
update_bwc_values(session, m_new);
|
||||
// Pass ownership of m_new to the callback.
|
||||
session->mcb(session->m->mono_time, session->cs, m_new);
|
||||
Mono_Time *mt = toxav_get_av_mono_time(session->toxav);
|
||||
assert(mt != nullptr);
|
||||
session->mcb(mt, session->cs, m_new);
|
||||
// Now we no longer own m_new.
|
||||
m_new = nullptr;
|
||||
|
||||
@ -425,9 +411,12 @@ static int handle_video_packet(RTPSession *session, const struct RTPHeader *head
|
||||
struct RTPMessage *m_new = process_frame(log, session->work_buffer_list, slot_id);
|
||||
|
||||
if (m_new != nullptr) {
|
||||
LOGGER_DEBUG(log, "-- handle_video_packet -- CALLBACK-003a b0=%d b1=%d", (int)m_new->data[0], (int)m_new->data[1]);
|
||||
update_bwc_values(log, session, m_new);
|
||||
session->mcb(session->m->mono_time, session->cs, m_new);
|
||||
LOGGER_DEBUG(log, "-- handle_video_packet -- CALLBACK-003a b0=%d b1=%d", (int)m_new->data[0],
|
||||
(int)m_new->data[1]);
|
||||
update_bwc_values(session, m_new);
|
||||
Mono_Time *mt = toxav_get_av_mono_time(session->toxav);
|
||||
assert(mt != nullptr);
|
||||
session->mcb(mt, session->cs, m_new);
|
||||
|
||||
m_new = nullptr;
|
||||
}
|
||||
@ -436,80 +425,113 @@ static int handle_video_packet(RTPSession *session, const struct RTPHeader *head
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval -1 on error.
|
||||
* @retval 0 on success.
|
||||
* receive custom lossypackets and process them. they can be incoming audio or video packets
|
||||
*/
|
||||
static int handle_rtp_packet(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object)
|
||||
void handle_rtp_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, void *user_data)
|
||||
{
|
||||
RTPSession *session = (RTPSession *)object;
|
||||
ToxAV *toxav = (ToxAV *)tox_get_av_object(tox);
|
||||
|
||||
if (session == nullptr || length < RTP_HEADER_SIZE + 1) {
|
||||
LOGGER_WARNING(m->log, "No session or invalid length of received buffer!");
|
||||
return -1;
|
||||
if (toxav == nullptr) {
|
||||
// LOGGER_WARNING(log, "ToxAV is NULL!");
|
||||
return;
|
||||
}
|
||||
|
||||
const Logger *log = toxav_get_logger(toxav);
|
||||
|
||||
if (length < RTP_HEADER_SIZE + 1) {
|
||||
LOGGER_WARNING(log, "Invalid length of received buffer!");
|
||||
return;
|
||||
}
|
||||
|
||||
ToxAVCall *call = call_get(toxav, friend_number);
|
||||
|
||||
if (call == nullptr) {
|
||||
LOGGER_WARNING(log, "ToxAVCall is NULL!");
|
||||
return;
|
||||
}
|
||||
|
||||
RTPSession *session = rtp_session_get(call, data[0]);
|
||||
|
||||
if (session == nullptr) {
|
||||
LOGGER_WARNING(log, "No session!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!session->rtp_receive_active) {
|
||||
LOGGER_WARNING(log, "receiving not allowed!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the packet type.
|
||||
const uint8_t packet_type = data[0];
|
||||
++data;
|
||||
--length;
|
||||
const uint8_t *payload = &data[1];
|
||||
// TODO(Zoff): is this ok?
|
||||
const uint16_t payload_size = (uint16_t)length - 1;
|
||||
|
||||
// Unpack the header.
|
||||
struct RTPHeader header;
|
||||
rtp_header_unpack(data, &header);
|
||||
rtp_header_unpack(payload, &header);
|
||||
|
||||
if (header.pt != packet_type % 128) {
|
||||
LOGGER_WARNING(m->log, "RTPHeader packet type and Tox protocol packet type did not agree: %d != %d",
|
||||
LOGGER_WARNING(log, "RTPHeader packet type and Tox protocol packet type did not agree: %d != %d",
|
||||
header.pt, packet_type % 128);
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (header.pt != session->payload_type % 128) {
|
||||
LOGGER_WARNING(m->log, "RTPHeader packet type does not match this session's payload type: %d != %d",
|
||||
LOGGER_WARNING(log, "RTPHeader packet type does not match this session's payload type: %d != %d",
|
||||
header.pt, session->payload_type % 128);
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((header.flags & RTP_LARGE_FRAME) != 0 && header.offset_full >= header.data_length_full) {
|
||||
LOGGER_ERROR(m->log, "Invalid video packet: frame offset (%u) >= full frame length (%u)",
|
||||
LOGGER_ERROR(log, "Invalid video packet: frame offset (%u) >= full frame length (%u)",
|
||||
(unsigned)header.offset_full, (unsigned)header.data_length_full);
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (header.offset_lower >= header.data_length_lower) {
|
||||
LOGGER_ERROR(m->log, "Invalid old protocol video packet: frame offset (%u) >= full frame length (%u)",
|
||||
LOGGER_ERROR(log, "Invalid old protocol video packet: frame offset (%u) >= full frame length (%u)",
|
||||
(unsigned)header.offset_lower, (unsigned)header.data_length_lower);
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER_DEBUG(m->log, "header.pt %d, video %d", (uint8_t)header.pt, RTP_TYPE_VIDEO % 128);
|
||||
LOGGER_DEBUG(log, "header.pt %d, video %d", (uint8_t)header.pt, RTP_TYPE_VIDEO % 128);
|
||||
|
||||
// The sender uses the new large-frame capable protocol and is sending a
|
||||
// video packet.
|
||||
if ((header.flags & RTP_LARGE_FRAME) != 0 && header.pt == (RTP_TYPE_VIDEO % 128)) {
|
||||
return handle_video_packet(session, &header, data + RTP_HEADER_SIZE, length - RTP_HEADER_SIZE, m->log);
|
||||
handle_video_packet(log, session, &header, &payload[RTP_HEADER_SIZE], payload_size - RTP_HEADER_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
// everything below here is for the old 16 bit protocol ------------------
|
||||
|
||||
if (header.data_length_lower == length - RTP_HEADER_SIZE) {
|
||||
if (header.data_length_lower == payload_size - RTP_HEADER_SIZE) {
|
||||
/* The message is sent in single part */
|
||||
|
||||
/* Message is not late; pick up the latest parameters */
|
||||
session->rsequnum = header.sequnum;
|
||||
session->rtimestamp = header.timestamp;
|
||||
bwc_add_recv(session->bwc, length);
|
||||
bwc_add_recv(session->bwc, payload_size);
|
||||
|
||||
/* Invoke processing of active multiparted message */
|
||||
if (session->mp != nullptr) {
|
||||
session->mcb(session->m->mono_time, session->cs, session->mp);
|
||||
Mono_Time *mt = toxav_get_av_mono_time(session->toxav);
|
||||
assert(mt != nullptr);
|
||||
session->mcb(mt, session->cs, session->mp);
|
||||
session->mp = nullptr;
|
||||
}
|
||||
|
||||
/* The message came in the allowed time;
|
||||
*/
|
||||
|
||||
return session->mcb(session->m->mono_time, session->cs, new_message(&header, length - RTP_HEADER_SIZE,
|
||||
data + RTP_HEADER_SIZE, length - RTP_HEADER_SIZE));
|
||||
session->mp = new_message(log, &header, payload_size - RTP_HEADER_SIZE, &payload[RTP_HEADER_SIZE], payload_size - RTP_HEADER_SIZE);
|
||||
Mono_Time *mt = toxav_get_av_mono_time(session->toxav);
|
||||
assert(mt != nullptr);
|
||||
session->mcb(mt, session->cs, session->mp);
|
||||
session->mp = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
/* The message is sent in multiple parts */
|
||||
@ -527,24 +549,26 @@ static int handle_rtp_packet(Messenger *m, uint32_t friend_number, const uint8_t
|
||||
/* First case */
|
||||
|
||||
/* Make sure we have enough allocated memory */
|
||||
if (session->mp->header.data_length_lower - session->mp->len < length - RTP_HEADER_SIZE ||
|
||||
if (session->mp->header.data_length_lower - session->mp->len < payload_size - RTP_HEADER_SIZE ||
|
||||
session->mp->header.data_length_lower <= header.offset_lower) {
|
||||
/* There happened to be some corruption on the stream;
|
||||
* continue wihtout this part
|
||||
*/
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(session->mp->data + header.offset_lower, data + RTP_HEADER_SIZE,
|
||||
length - RTP_HEADER_SIZE);
|
||||
session->mp->len += length - RTP_HEADER_SIZE;
|
||||
bwc_add_recv(session->bwc, length);
|
||||
memcpy(session->mp->data + header.offset_lower, &payload[RTP_HEADER_SIZE],
|
||||
payload_size - RTP_HEADER_SIZE);
|
||||
session->mp->len += payload_size - RTP_HEADER_SIZE;
|
||||
bwc_add_recv(session->bwc, payload_size);
|
||||
|
||||
if (session->mp->len == session->mp->header.data_length_lower) {
|
||||
/* Received a full message; now push it for the further
|
||||
* processing.
|
||||
*/
|
||||
session->mcb(session->m->mono_time, session->cs, session->mp);
|
||||
Mono_Time *mt = toxav_get_av_mono_time(session->toxav);
|
||||
assert(mt != nullptr);
|
||||
session->mcb(mt, session->cs, session->mp);
|
||||
session->mp = nullptr;
|
||||
}
|
||||
} else {
|
||||
@ -553,17 +577,19 @@ static int handle_rtp_packet(Messenger *m, uint32_t friend_number, const uint8_t
|
||||
/* The received message part is from the old message;
|
||||
* discard it.
|
||||
*/
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Push the previous message for processing */
|
||||
session->mcb(session->m->mono_time, session->cs, session->mp);
|
||||
Mono_Time *mt = toxav_get_av_mono_time(session->toxav);
|
||||
assert(mt != nullptr);
|
||||
session->mcb(mt, session->cs, session->mp);
|
||||
|
||||
session->mp = nullptr;
|
||||
goto NEW_MULTIPARTED;
|
||||
}
|
||||
} else {
|
||||
/* In this case threat the message as if it was received in order
|
||||
/* In this case treat the message as if it was received in order
|
||||
*/
|
||||
/* This is also a point for new multiparted messages */
|
||||
NEW_MULTIPARTED:
|
||||
@ -571,21 +597,21 @@ NEW_MULTIPARTED:
|
||||
/* Message is not late; pick up the latest parameters */
|
||||
session->rsequnum = header.sequnum;
|
||||
session->rtimestamp = header.timestamp;
|
||||
bwc_add_recv(session->bwc, length);
|
||||
bwc_add_recv(session->bwc, payload_size);
|
||||
|
||||
/* Store message.
|
||||
*/
|
||||
session->mp = new_message(&header, header.data_length_lower, data + RTP_HEADER_SIZE, length - RTP_HEADER_SIZE);
|
||||
session->mp = new_message(log, &header, header.data_length_lower, &payload[RTP_HEADER_SIZE], payload_size - RTP_HEADER_SIZE);
|
||||
|
||||
if (session->mp != nullptr) {
|
||||
memmove(session->mp->data + header.offset_lower, session->mp->data, session->mp->len);
|
||||
} else {
|
||||
LOGGER_WARNING(m->log, "new_message() returned a null pointer");
|
||||
return -1;
|
||||
LOGGER_WARNING(log, "new_message() returned a null pointer");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t rtp_header_pack(uint8_t *const rdata, const struct RTPHeader *header)
|
||||
@ -647,24 +673,29 @@ size_t rtp_header_unpack(const uint8_t *data, struct RTPHeader *header)
|
||||
return p - data;
|
||||
}
|
||||
|
||||
RTPSession *rtp_new(int payload_type, Messenger *m, Tox *tox, uint32_t friendnumber,
|
||||
static uint32_t rtp_random_u32(void)
|
||||
{
|
||||
// HINT: uses libsodium function
|
||||
return randombytes_random();
|
||||
}
|
||||
|
||||
RTPSession *rtp_new(const Logger *log, int payload_type, Tox *tox, ToxAV *toxav, uint32_t friendnumber,
|
||||
BWController *bwc, void *cs, rtp_m_cb *mcb)
|
||||
{
|
||||
assert(mcb != nullptr);
|
||||
assert(cs != nullptr);
|
||||
assert(m != nullptr);
|
||||
|
||||
RTPSession *session = (RTPSession *)calloc(1, sizeof(RTPSession));
|
||||
|
||||
if (session == nullptr) {
|
||||
LOGGER_WARNING(m->log, "Alloc failed! Program might misbehave!");
|
||||
LOGGER_WARNING(log, "Alloc failed! Program might misbehave!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
session->work_buffer_list = (struct RTPWorkBufferList *)calloc(1, sizeof(struct RTPWorkBufferList));
|
||||
|
||||
if (session->work_buffer_list == nullptr) {
|
||||
LOGGER_ERROR(m->log, "out of memory while allocating work buffer list");
|
||||
LOGGER_ERROR(log, "out of memory while allocating work buffer list");
|
||||
free(session);
|
||||
return nullptr;
|
||||
}
|
||||
@ -672,11 +703,12 @@ RTPSession *rtp_new(int payload_type, Messenger *m, Tox *tox, uint32_t friendnum
|
||||
// First entry is free.
|
||||
session->work_buffer_list->next_free_entry = 0;
|
||||
|
||||
session->ssrc = payload_type == RTP_TYPE_VIDEO ? 0 : random_u32(m->rng);
|
||||
session->ssrc = payload_type == RTP_TYPE_VIDEO ? 0 : rtp_random_u32(); // Zoff: what is this??
|
||||
session->payload_type = payload_type;
|
||||
session->m = m;
|
||||
session->tox = tox;
|
||||
session->toxav = toxav;
|
||||
session->friend_number = friendnumber;
|
||||
session->rtp_receive_active = true;
|
||||
|
||||
// set NULL just in case
|
||||
session->mp = nullptr;
|
||||
@ -687,26 +719,18 @@ RTPSession *rtp_new(int payload_type, Messenger *m, Tox *tox, uint32_t friendnum
|
||||
session->cs = cs;
|
||||
session->mcb = mcb;
|
||||
|
||||
if (-1 == rtp_allow_receiving(session)) {
|
||||
LOGGER_WARNING(m->log, "Failed to start rtp receiving mode");
|
||||
free(session->work_buffer_list);
|
||||
free(session);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
void rtp_kill(RTPSession *session)
|
||||
void rtp_kill(const Logger *log, RTPSession *session)
|
||||
{
|
||||
if (session == nullptr) {
|
||||
LOGGER_WARNING(log, "No session");
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER_DEBUG(session->m->log, "Terminated RTP session: %p", (void *)session);
|
||||
rtp_stop_receiving(session);
|
||||
|
||||
LOGGER_DEBUG(session->m->log, "Terminated RTP session V3 work_buffer_list->next_free_entry: %d",
|
||||
LOGGER_DEBUG(log, "Terminated RTP session: %p", (void *)session);
|
||||
LOGGER_DEBUG(log, "Terminated RTP session V3 work_buffer_list->next_free_entry: %d",
|
||||
(int)session->work_buffer_list->next_free_entry);
|
||||
|
||||
for (int8_t i = 0; i < session->work_buffer_list->next_free_entry; ++i) {
|
||||
@ -716,36 +740,95 @@ void rtp_kill(RTPSession *session)
|
||||
free(session);
|
||||
}
|
||||
|
||||
int rtp_allow_receiving(RTPSession *session)
|
||||
void rtp_allow_receiving_mark(RTPSession *session)
|
||||
{
|
||||
if (session == nullptr) {
|
||||
return -1;
|
||||
if (session != nullptr) {
|
||||
session->rtp_receive_active = true;
|
||||
}
|
||||
|
||||
if (m_callback_rtp_packet(session->m, session->friend_number, session->payload_type,
|
||||
handle_rtp_packet, session) == -1) {
|
||||
LOGGER_WARNING(session->m->log, "Failed to register rtp receive handler");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOGGER_DEBUG(session->m->log, "Started receiving on session: %p", (void *)session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtp_stop_receiving(RTPSession *session)
|
||||
void rtp_stop_receiving_mark(RTPSession *session)
|
||||
{
|
||||
if (session == nullptr) {
|
||||
return -1;
|
||||
if (session != nullptr) {
|
||||
session->rtp_receive_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
void rtp_allow_receiving(Tox *tox)
|
||||
{
|
||||
// register callback
|
||||
tox_callback_friend_lossy_packet_per_pktid(tox, handle_rtp_packet, RTP_TYPE_AUDIO);
|
||||
tox_callback_friend_lossy_packet_per_pktid(tox, handle_rtp_packet, RTP_TYPE_VIDEO);
|
||||
}
|
||||
|
||||
void rtp_stop_receiving(Tox *tox)
|
||||
{
|
||||
// UN-register callback
|
||||
tox_callback_friend_lossy_packet_per_pktid(tox, nullptr, RTP_TYPE_AUDIO);
|
||||
tox_callback_friend_lossy_packet_per_pktid(tox, nullptr, RTP_TYPE_VIDEO);
|
||||
}
|
||||
|
||||
static void rtp_send_piece(const Logger *log, Tox *tox, uint32_t friend_number, const struct RTPHeader *header,
|
||||
const uint8_t *data, uint8_t *rdata, uint16_t length)
|
||||
{
|
||||
rtp_header_pack(rdata + 1, header);
|
||||
memcpy(rdata + 1 + RTP_HEADER_SIZE, data, length);
|
||||
|
||||
Tox_Err_Friend_Custom_Packet error;
|
||||
tox_friend_send_lossy_packet(tox, friend_number,
|
||||
rdata, length + RTP_HEADER_SIZE + 1, &error);
|
||||
|
||||
if (error != TOX_ERR_FRIEND_CUSTOM_PACKET_OK) {
|
||||
char *netstrerror = net_new_strerror(net_error());
|
||||
LOGGER_WARNING(log, "RTP send failed (len: %d)! tox error: %d, net error: %s",
|
||||
length + RTP_HEADER_SIZE + 1, error, netstrerror);
|
||||
net_kill_strerror(netstrerror);
|
||||
}
|
||||
}
|
||||
|
||||
static struct RTPHeader rtp_default_header(const RTPSession *session, uint32_t length, bool is_keyframe)
|
||||
{
|
||||
uint16_t length_safe = (uint16_t)length;
|
||||
|
||||
if (length > UINT16_MAX) {
|
||||
length_safe = UINT16_MAX;
|
||||
}
|
||||
|
||||
m_callback_rtp_packet(session->m, session->friend_number, session->payload_type, nullptr, nullptr);
|
||||
struct RTPHeader header = {0};
|
||||
|
||||
LOGGER_DEBUG(session->m->log, "Stopped receiving on session: %p", (void *)session);
|
||||
return 0;
|
||||
if (is_keyframe) {
|
||||
header.flags |= RTP_KEY_FRAME;
|
||||
}
|
||||
|
||||
if (session->payload_type == RTP_TYPE_VIDEO) {
|
||||
header.flags |= RTP_LARGE_FRAME;
|
||||
}
|
||||
|
||||
header.ve = 2; // this is unused in toxav
|
||||
header.pe = 0;
|
||||
header.xe = 0;
|
||||
header.cc = 0;
|
||||
header.ma = 0;
|
||||
header.pt = session->payload_type % 128;
|
||||
header.sequnum = session->sequnum;
|
||||
Mono_Time *mt = toxav_get_av_mono_time(session->toxav);
|
||||
if (mt != nullptr) {
|
||||
header.timestamp = current_time_monotonic(mt);
|
||||
} else {
|
||||
header.timestamp = 0;
|
||||
}
|
||||
header.ssrc = session->ssrc;
|
||||
header.offset_lower = 0;
|
||||
header.data_length_lower = length_safe;
|
||||
header.data_length_full = length; // without header
|
||||
header.offset_lower = 0;
|
||||
header.offset_full = 0;
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a frame of audio or video data, chunked in @ref RTPMessage instances.
|
||||
* @brief Send a frame of audio or video data, chunked in @ref RTPMessage instances.
|
||||
*
|
||||
* @param session The A/V session to send the data for.
|
||||
* @param data A byte array of length @p length.
|
||||
@ -753,77 +836,27 @@ int rtp_stop_receiving(RTPSession *session)
|
||||
* @param is_keyframe Whether this video frame is a key frame. If it is an
|
||||
* audio frame, this parameter is ignored.
|
||||
*/
|
||||
int rtp_send_data(RTPSession *session, const uint8_t *data, uint32_t length,
|
||||
bool is_keyframe, const Logger *log)
|
||||
int rtp_send_data(const Logger *log, RTPSession *session, const uint8_t *data, uint32_t length,
|
||||
bool is_keyframe)
|
||||
{
|
||||
if (session == nullptr) {
|
||||
LOGGER_ERROR(log, "No session!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct RTPHeader header = {0};
|
||||
|
||||
header.ve = 2; // this is unused in toxav
|
||||
|
||||
header.pe = 0;
|
||||
|
||||
header.xe = 0;
|
||||
|
||||
header.cc = 0;
|
||||
|
||||
header.ma = 0;
|
||||
|
||||
header.pt = session->payload_type % 128;
|
||||
|
||||
header.sequnum = session->sequnum;
|
||||
|
||||
header.timestamp = current_time_monotonic(session->m->mono_time);
|
||||
|
||||
header.ssrc = session->ssrc;
|
||||
|
||||
header.offset_lower = 0;
|
||||
|
||||
// here the highest bits gets stripped anyway, no need to do keyframe bit magic here!
|
||||
header.data_length_lower = length;
|
||||
|
||||
if (session->payload_type == RTP_TYPE_VIDEO) {
|
||||
header.flags = RTP_LARGE_FRAME;
|
||||
}
|
||||
|
||||
uint16_t length_safe = (uint16_t)length;
|
||||
|
||||
if (length > UINT16_MAX) {
|
||||
length_safe = UINT16_MAX;
|
||||
}
|
||||
|
||||
header.data_length_lower = length_safe;
|
||||
header.data_length_full = length; // without header
|
||||
header.offset_lower = 0;
|
||||
header.offset_full = 0;
|
||||
|
||||
if (is_keyframe) {
|
||||
header.flags |= RTP_KEY_FRAME;
|
||||
}
|
||||
|
||||
const uint16_t rdata_size = min_u32(length + RTP_HEADER_SIZE + 1, MAX_CRYPTO_DATA_SIZE);
|
||||
VLA(uint8_t, rdata, rdata_size);
|
||||
memset(rdata, 0, rdata_size);
|
||||
rdata[0] = session->payload_type; // packet id == payload_type
|
||||
|
||||
struct RTPHeader header = rtp_default_header(session, length, is_keyframe);
|
||||
|
||||
if (MAX_CRYPTO_DATA_SIZE > (length + RTP_HEADER_SIZE + 1)) {
|
||||
/*
|
||||
* The length is lesser than the maximum allowed length (including header)
|
||||
* Send the packet in single piece.
|
||||
*/
|
||||
rtp_header_pack(rdata + 1, &header);
|
||||
memcpy(rdata + 1 + RTP_HEADER_SIZE, data, length);
|
||||
|
||||
if (-1 == rtp_send_custom_lossy_packet(session->tox, session->friend_number, rdata, rdata_size)) {
|
||||
char *netstrerror = net_new_strerror(net_error());
|
||||
LOGGER_WARNING(session->m->log, "RTP send failed (len: %u)! net error: %s",
|
||||
rdata_size, netstrerror);
|
||||
net_kill_strerror(netstrerror);
|
||||
}
|
||||
assert(length < UINT16_MAX);
|
||||
rtp_send_piece(log, session->tox, session->friend_number, &header, data, rdata, length);
|
||||
} else {
|
||||
/*
|
||||
* The length is greater than the maximum allowed length (including header)
|
||||
@ -833,16 +866,7 @@ int rtp_send_data(RTPSession *session, const uint8_t *data, uint32_t length,
|
||||
uint16_t piece = MAX_CRYPTO_DATA_SIZE - (RTP_HEADER_SIZE + 1);
|
||||
|
||||
while ((length - sent) + RTP_HEADER_SIZE + 1 > MAX_CRYPTO_DATA_SIZE) {
|
||||
rtp_header_pack(rdata + 1, &header);
|
||||
memcpy(rdata + 1 + RTP_HEADER_SIZE, data + sent, piece);
|
||||
|
||||
if (-1 == rtp_send_custom_lossy_packet(session->tox, session->friend_number,
|
||||
rdata, piece + RTP_HEADER_SIZE + 1)) {
|
||||
char *netstrerror = net_new_strerror(net_error());
|
||||
LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! net error: %s",
|
||||
piece + RTP_HEADER_SIZE + 1, netstrerror);
|
||||
net_kill_strerror(netstrerror);
|
||||
}
|
||||
rtp_send_piece(log, session->tox, session->friend_number, &header, data + sent, rdata, piece);
|
||||
|
||||
sent += piece;
|
||||
header.offset_lower = sent;
|
||||
@ -853,16 +877,7 @@ int rtp_send_data(RTPSession *session, const uint8_t *data, uint32_t length,
|
||||
piece = length - sent;
|
||||
|
||||
if (piece != 0) {
|
||||
rtp_header_pack(rdata + 1, &header);
|
||||
memcpy(rdata + 1 + RTP_HEADER_SIZE, data + sent, piece);
|
||||
|
||||
if (-1 == rtp_send_custom_lossy_packet(session->tox, session->friend_number, rdata,
|
||||
piece + RTP_HEADER_SIZE + 1)) {
|
||||
char *netstrerror = net_new_strerror(net_error());
|
||||
LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! net error: %s",
|
||||
piece + RTP_HEADER_SIZE + 1, netstrerror);
|
||||
net_kill_strerror(netstrerror);
|
||||
}
|
||||
rtp_send_piece(log, session->tox, session->friend_number, &header, data + sent, rdata, piece);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user