Begin adding full support for GOOG-REMB\nFix iOS 'broken pipe' issue when UDP sockets are invalidated by the OS
This commit is contained in:
parent
295de8efda
commit
7908865936
|
@ -58,7 +58,15 @@ typedef struct tdav_session_av_s
|
|||
|
||||
tmedia_srtp_type_t srtp_type;
|
||||
tmedia_srtp_mode_t srtp_mode;
|
||||
|
||||
struct {
|
||||
uint64_t count_last_time;
|
||||
uint64_t count;
|
||||
} bytes_in;
|
||||
struct {
|
||||
uint64_t count_last_time;
|
||||
uint64_t count;
|
||||
} bytes_out;
|
||||
uint64_t time_last_frame_loss_report; // from jb
|
||||
int32_t bandwidth_max_upload_kbps;
|
||||
int32_t bandwidth_max_download_kbps;
|
||||
int32_t fps;
|
||||
|
|
|
@ -164,6 +164,8 @@ static int tdav_codec_vp8_set(tmedia_codec_t* self, const tmedia_param_t* param)
|
|||
else {
|
||||
TMEDIA_CODEC(vp8)->bandwidth_max_upload = max_bw_new;
|
||||
}
|
||||
vp8->encoder.cfg.rc_target_bitrate = TSK_CLAMP(0, vp8->encoder.cfg.rc_target_bitrate, TMEDIA_CODEC(vp8)->bandwidth_max_upload);
|
||||
TSK_DEBUG_INFO("New target bitrate = %d kbps", vp8->encoder.cfg.rc_target_bitrate);
|
||||
reconf = tsk_true;
|
||||
}
|
||||
else if (tsk_striequals(param->key, "bandwidth-max-upload")) {
|
||||
|
|
|
@ -765,6 +765,9 @@ int tdav_session_av_stop(tdav_session_av_t* self)
|
|||
}
|
||||
}
|
||||
|
||||
self->bytes_in.count_last_time = self->bytes_out.count_last_time = 0;
|
||||
self->bytes_in.count = self->bytes_out.count = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) 2010-2014 Mamadou DIOP.
|
||||
* Copyright (C) 2011-2014 Doubango Telecom.
|
||||
*
|
||||
*
|
||||
* This file is part of Open Source Doubango Framework.
|
||||
*
|
||||
* DOUBANGO is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* DOUBANGO is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with DOUBANGO.
|
||||
*
|
||||
*/
|
||||
* Copyright (C) 2010-2014 Mamadou DIOP.
|
||||
* Copyright (C) 2011-2014 Doubango Telecom.
|
||||
*
|
||||
*
|
||||
* This file is part of Open Source Doubango Framework.
|
||||
*
|
||||
* DOUBANGO is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* DOUBANGO is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with DOUBANGO.
|
||||
*
|
||||
*/
|
||||
|
||||
/**@file tdav_session_video.c
|
||||
* @brief Video Session plugin.
|
||||
*
|
||||
*/
|
||||
* @brief Video Session plugin.
|
||||
*
|
||||
*/
|
||||
#include "tinydav/video/tdav_session_video.h"
|
||||
#include "tinydav/video/tdav_converter_video.h"
|
||||
#include "tinydav/video/jb/tdav_video_jb.h"
|
||||
|
@ -70,69 +70,79 @@
|
|||
#define TDAV_SESSION_VIDEO_PKT_LOSS_MEDIUM 22
|
||||
#define TDAV_SESSION_VIDEO_PKT_LOSS_HIGH 63
|
||||
|
||||
#if !defined(TDAV_SESSION_VIDEO_PKT_LOSS_NO_REPORT_BEFORE_INCREASING_BW)
|
||||
# define TDAV_SESSION_VIDEO_PKT_LOSS_NO_REPORT_BEFORE_INCREASING_BW 5000 // millis
|
||||
#endif
|
||||
|
||||
// The maximum number of pakcet loss allowed
|
||||
#define TDAV_SESSION_VIDEO_PKT_LOSS_MAX_COUNT_TO_REQUEST_FIR 50
|
||||
|
||||
#if !defined (TDAV_GOOG_REMB_FULL_SUPPORT)
|
||||
# define TDAV_GOOG_REMB_FULL_SUPPORT 0
|
||||
#endif
|
||||
|
||||
static const tmedia_codec_action_t __action_encode_idr = tmedia_codec_action_encode_idr;
|
||||
static const tmedia_codec_action_t __action_encode_bw_up = tmedia_codec_action_bw_up;
|
||||
static const tmedia_codec_action_t __action_encode_bw_down = tmedia_codec_action_bw_down;
|
||||
|
||||
// FIXME: lock ?
|
||||
#define _tdav_session_video_codec_set(__self, key, value) \
|
||||
#define _tdav_session_video_codec_set(__self, __key, __value) \
|
||||
{ \
|
||||
static tmedia_param_t* __param = tsk_null; \
|
||||
if(!__param){ \
|
||||
__param = tmedia_param_create(tmedia_pat_set, \
|
||||
tmedia_video, \
|
||||
tmedia_ppt_codec, \
|
||||
tmedia_pvt_int32, \
|
||||
"action", \
|
||||
(void*)&value); \
|
||||
} \
|
||||
if((__self)->encoder.codec && __param){ \
|
||||
/*tsk_mutex_lock((__self)->encoder.h_mutex);*/ \
|
||||
if(TDAV_SESSION_AV(__self)->producer && TDAV_SESSION_AV(__self)->producer->encoder.codec_id == (__self)->encoder.codec->id) { /* Whether the producer ourput encoded frames */ \
|
||||
tmedia_producer_set(TDAV_SESSION_AV(__self)->producer, __param); \
|
||||
} \
|
||||
else { \
|
||||
tmedia_codec_set((tmedia_codec_t*)(__self)->encoder.codec, __param); \
|
||||
static tmedia_param_t* __param = tsk_null; \
|
||||
if(!__param){ \
|
||||
__param = tmedia_param_create(tmedia_pat_set, \
|
||||
tmedia_video, \
|
||||
tmedia_ppt_codec, \
|
||||
tmedia_pvt_int32, \
|
||||
__key, \
|
||||
(void*)&__value); \
|
||||
} \
|
||||
/*tsk_mutex_unlock((__self)->encoder.h_mutex);*/ \
|
||||
} \
|
||||
/* TSK_OBJECT_SAFE_FREE(param); */ \
|
||||
if((__self)->encoder.codec && __param){ \
|
||||
/*tsk_mutex_lock((__self)->encoder.h_mutex);*/ \
|
||||
if(TDAV_SESSION_AV(__self)->producer && TDAV_SESSION_AV(__self)->producer->encoder.codec_id == (__self)->encoder.codec->id) { /* Whether the producer ourput encoded frames */ \
|
||||
tmedia_producer_set(TDAV_SESSION_AV(__self)->producer, __param); \
|
||||
} \
|
||||
else { \
|
||||
tmedia_codec_set((tmedia_codec_t*)(__self)->encoder.codec, __param); \
|
||||
} \
|
||||
/*tsk_mutex_unlock((__self)->encoder.h_mutex);*/ \
|
||||
} \
|
||||
/* TSK_OBJECT_SAFE_FREE(param); */ \
|
||||
}
|
||||
|
||||
#define _tdav_session_video_remote_requested_idr(__self, __ssrc_media) { \
|
||||
uint64_t __now = tsk_time_now(); \
|
||||
tsk_bool_t too_close = tsk_false; \
|
||||
if((__now - (__self)->avpf.last_fir_time) > TDAV_SESSION_VIDEO_AVPF_FIR_HONOR_INTERVAL_MIN){ /* guard to avoid sending too many FIR */ \
|
||||
_tdav_session_video_codec_set((__self), "action", __action_encode_idr); \
|
||||
}else { too_close = tsk_true; TSK_DEBUG_INFO("***IDR request tooo close(%llu ms)...ignoring****", (__now - (__self)->avpf.last_fir_time)); } \
|
||||
if((__self)->cb_rtcpevent.func){ \
|
||||
(__self)->cb_rtcpevent.func((__self)->cb_rtcpevent.context, tmedia_rtcp_event_type_fir, (__ssrc_media)); \
|
||||
} \
|
||||
if (!too_close) { /* if too close don't update "last_fir_time" to "now" to be sure interval will increase */ \
|
||||
(__self)->avpf.last_fir_time = __now; \
|
||||
} \
|
||||
uint64_t __now = tsk_time_now(); \
|
||||
tsk_bool_t too_close = tsk_false; \
|
||||
if((__now - (__self)->avpf.last_fir_time) > TDAV_SESSION_VIDEO_AVPF_FIR_HONOR_INTERVAL_MIN){ /* guard to avoid sending too many FIR */ \
|
||||
_tdav_session_video_codec_set((__self), "action", __action_encode_idr); \
|
||||
}else { too_close = tsk_true; TSK_DEBUG_INFO("***IDR request tooo close(%llu ms)...ignoring****", (__now - (__self)->avpf.last_fir_time)); } \
|
||||
if((__self)->cb_rtcpevent.func){ \
|
||||
(__self)->cb_rtcpevent.func((__self)->cb_rtcpevent.context, tmedia_rtcp_event_type_fir, (__ssrc_media)); \
|
||||
} \
|
||||
if (!too_close) { /* if too close don't update "last_fir_time" to "now" to be sure interval will increase */ \
|
||||
(__self)->avpf.last_fir_time = __now; \
|
||||
} \
|
||||
}
|
||||
#define _tdav_session_video_local_request_idr(_session, _reason, _ssrc) \
|
||||
{ \
|
||||
tdav_session_av_t* _base = (tdav_session_av_t*)_session; \
|
||||
if ((_base)->avpf_mode_neg || (_base)->is_fb_fir_neg) { \
|
||||
/*return*/ trtp_manager_signal_frame_corrupted((_base)->rtp_manager, _ssrc); \
|
||||
} \
|
||||
else if ((_session)->rfc5168_cb.fun) { \
|
||||
/*return*/ (_session)->rfc5168_cb.fun((_session)->rfc5168_cb.usrdata, (_session), (_reason), tmedia_session_rfc5168_cmd_picture_fast_update); \
|
||||
tdav_session_av_t* _base = (tdav_session_av_t*)_session; \
|
||||
if ((_base)->avpf_mode_neg || (_base)->is_fb_fir_neg) { \
|
||||
/*return*/ trtp_manager_signal_frame_corrupted((_base)->rtp_manager, _ssrc); \
|
||||
} \
|
||||
else if ((_session)->rfc5168_cb.fun) { \
|
||||
/*return*/ (_session)->rfc5168_cb.fun((_session)->rfc5168_cb.usrdata, (_session), (_reason), tmedia_session_rfc5168_cmd_picture_fast_update); \
|
||||
} \
|
||||
}
|
||||
#define _tdav_session_video_bw_up(__self) _tdav_session_video_codec_set(__self, "action", __action_encode_bw_up)
|
||||
#define _tdav_session_video_bw_down(__self) _tdav_session_video_codec_set(__self, "action", __action_encode_bw_down)
|
||||
#define _tdav_session_video_bw_kbps(__self, __bw_kbps) _tdav_session_video_codec_set(__self, "bw_kbps", __bw_kbps)
|
||||
|
||||
|
||||
#define _tdav_session_video_reset_loss_prob(__self) \
|
||||
{ \
|
||||
(__self)->encoder.pkt_loss_level = tdav_session_video_pkt_loss_level_low; \
|
||||
(__self)->encoder.pkt_loss_prob_bad = TDAV_SESSION_VIDEO_PKT_LOSS_PROB_BAD; \
|
||||
(__self)->encoder.pkt_loss_prob_good = TDAV_SESSION_VIDEO_PKT_LOSS_PROB_GOOD; \
|
||||
(__self)->encoder.pkt_loss_level = tdav_session_video_pkt_loss_level_low; \
|
||||
(__self)->encoder.pkt_loss_prob_bad = TDAV_SESSION_VIDEO_PKT_LOSS_PROB_BAD; \
|
||||
(__self)->encoder.pkt_loss_prob_good = TDAV_SESSION_VIDEO_PKT_LOSS_PROB_GOOD; \
|
||||
}
|
||||
|
||||
static int _tdav_session_video_set_defaults(tdav_session_video_t* self);
|
||||
|
@ -227,12 +237,20 @@ static int tdav_session_video_raw_cb(const tmedia_video_encode_result_xt* result
|
|||
s = trtp_manager_send_rtp_packet(base->rtp_manager, packet, tsk_false); // encrypt and send data
|
||||
++base->rtp_manager->rtp.seq_num; // seq_num must be incremented here (before the bail) because already used by SRTP context
|
||||
if(s < TRTP_RTP_HEADER_MIN_SIZE) {
|
||||
TSK_DEBUG_ERROR("Failed to send packet with seqnum=%u. %u expected but only %u sent", (unsigned)packet->header->seq_num, (unsigned)packet->payload.size, (unsigned)s);
|
||||
goto bail;
|
||||
// without audio session iOS "audio" background mode is useless and UDP sockets will be closed: e.g. GE's video-only sessions
|
||||
#if TDAV_UNDER_IPHONE
|
||||
if (tnet_geterrno() == TNET_ERROR_BROKENPIPE) {
|
||||
TSK_DEBUG_INFO("iOS UDP pipe is broken (restoration is progress): failed to send packet with seqnum=%u. %u expected but only %u sent", (unsigned)packet->header->seq_num, (unsigned)packet->payload.size, (unsigned)s);
|
||||
}
|
||||
#endif /* TDAV_UNDER_IPHONE */
|
||||
TSK_DEBUG_ERROR("Failed to send packet with seqnum=%u. %u expected but only %u sent", (unsigned)packet->header->seq_num, (unsigned)packet->payload.size, (unsigned)s);
|
||||
// save data expected to be sent in order to honor RTCP-NACK requests
|
||||
s = base->rtp_manager->rtp.serial_buffer.index;
|
||||
}
|
||||
|
||||
rtp_hdr_size = TRTP_RTP_HEADER_MIN_SIZE + (packet->header->csrc_count << 2);
|
||||
// Save packet
|
||||
if(base->avpf_mode_neg){
|
||||
if (base->avpf_mode_neg && (s > TRTP_RTP_HEADER_MIN_SIZE)) {
|
||||
trtp_rtp_packet_t* packet_avpf = tsk_object_ref(packet);
|
||||
// when SRTP is used, "serial_buffer" will contains the encoded buffer with both RTP header and payload
|
||||
// Hack the RTP packet payload to point to the the SRTP data instead of unencrypted ptr
|
||||
|
@ -285,7 +303,7 @@ static int tdav_session_video_raw_cb(const tmedia_video_encode_result_xt* result
|
|||
}
|
||||
#if 0
|
||||
// Send RED Packet
|
||||
if(ret == 0 && video->red.codec){
|
||||
if (ret == 0 && video->red.codec) {
|
||||
// don't need to lock as the buffer is never used by other codecs
|
||||
tsk_size_t red_pay_size = video->red.codec->plugin->encode(
|
||||
video->red.codec,
|
||||
|
@ -302,7 +320,7 @@ static int tdav_session_video_raw_cb(const tmedia_video_encode_result_xt* result
|
|||
}
|
||||
#endif
|
||||
}
|
||||
else{
|
||||
else {
|
||||
TSK_DEBUG_ERROR("Failed to create packet");
|
||||
}
|
||||
}
|
||||
|
@ -404,7 +422,7 @@ static int tdav_session_video_producer_enc_cb(const void* callback_data, const v
|
|||
#define PRODUCER_OUTPUT_FIXSIZE (base->producer->video.chroma != tmedia_chroma_mjpeg) // whether the output data has a fixed size/length
|
||||
#define PRODUCER_OUTPUT_RAW (base->producer->encoder.codec_id == tmedia_codec_id_none) // Otherwise, frames from the producer are already encoded
|
||||
#define PRODUCER_SIZE_CHANGED ((video->conv.producerWidth && video->conv.producerWidth != base->producer->video.width) || (video->conv.producerHeight && video->conv.producerHeight != base->producer->video.height) \
|
||||
|| (video->conv.xProducerSize && (video->conv.xProducerSize != size && PRODUCER_OUTPUT_FIXSIZE)))
|
||||
|| (video->conv.xProducerSize && (video->conv.xProducerSize != size && PRODUCER_OUTPUT_FIXSIZE)))
|
||||
#define ENCODED_NEED_FLIP (TMEDIA_CODEC_VIDEO(codec_encoder)->out.flip)
|
||||
#define ENCODED_NEED_RESIZE (base->producer->video.width != TMEDIA_CODEC_VIDEO(codec_encoder)->out.width || base->producer->video.height != TMEDIA_CODEC_VIDEO(codec_encoder)->out.height)
|
||||
#define PRODUCED_FRAME_NEED_ROTATION (base->producer->video.rotation != 0)
|
||||
|
@ -483,7 +501,7 @@ static int tdav_session_video_producer_enc_cb(const void* callback_data, const v
|
|||
/* Never called, see tdav_session_video_raw_cb() */
|
||||
trtp_manager_send_rtp(base->rtp_manager, video->encoder.buffer, out_size, 6006, tsk_true, tsk_true);
|
||||
}
|
||||
bail:
|
||||
bail:
|
||||
TSK_OBJECT_SAFE_FREE(codec_encoder);
|
||||
}
|
||||
else {
|
||||
|
@ -539,6 +557,7 @@ static int tdav_session_video_rtp_cb(const void* callback_data, const trtp_rtp_p
|
|||
// RTCP callback (Network -> This)
|
||||
static int tdav_session_video_rtcp_cb(const void* callback_data, const trtp_rtcp_packet_t* packet)
|
||||
{
|
||||
int ret = 0;
|
||||
const trtp_rtcp_report_psfb_t* psfb;
|
||||
const trtp_rtcp_report_rtpfb_t* rtpfb;
|
||||
const trtp_rtcp_rblocks_L_t* blocks = tsk_null;
|
||||
|
@ -555,13 +574,14 @@ static int tdav_session_video_rtcp_cb(const void* callback_data, const trtp_rtcp
|
|||
if(!(block = item->data)) continue;
|
||||
if(base->rtp_manager->rtp.ssrc.local == block->ssrc){
|
||||
tdav_session_video_pkt_loss_level_t pkt_loss_level = tdav_session_video_pkt_loss_level_low;
|
||||
TSK_DEBUG_INFO("RTCP pkt loss fraction=%d", block->fraction);
|
||||
if(block->fraction > TDAV_SESSION_VIDEO_PKT_LOSS_HIGH) pkt_loss_level = tdav_session_video_pkt_loss_level_high;
|
||||
else if(block->fraction > TDAV_SESSION_VIDEO_PKT_LOSS_MEDIUM) pkt_loss_level = tdav_session_video_pkt_loss_level_medium;
|
||||
if(pkt_loss_level == tdav_session_video_pkt_loss_level_high || (pkt_loss_level > video->encoder.pkt_loss_level)){ // high or low -> medium
|
||||
if (pkt_loss_level == tdav_session_video_pkt_loss_level_high || (pkt_loss_level > video->encoder.pkt_loss_level)){ // high or low -> medium
|
||||
video->encoder.pkt_loss_level = pkt_loss_level;
|
||||
if(video->encoder.pkt_loss_prob_bad-- <= 0){
|
||||
int32_t new_pkt_loss_fact = TSK_CLAMP(TDAV_SESSION_VIDEO_PKT_LOSS_FACT_MIN, (video->encoder.pkt_loss_fact + 1), TDAV_SESSION_VIDEO_PKT_LOSS_FACT_MAX);
|
||||
if(video->encoder.pkt_loss_fact != new_pkt_loss_fact){
|
||||
if (video->encoder.pkt_loss_fact != new_pkt_loss_fact) {
|
||||
TSK_DEBUG_INFO("Downgrade bandwidth %d->%d", video->encoder.pkt_loss_fact, new_pkt_loss_fact);
|
||||
video->encoder.pkt_loss_fact = new_pkt_loss_fact;
|
||||
_tdav_session_video_bw_down(video);
|
||||
|
@ -570,9 +590,9 @@ static int tdav_session_video_rtcp_cb(const void* callback_data, const trtp_rtcp
|
|||
}
|
||||
}
|
||||
else{
|
||||
if(video->encoder.pkt_loss_prob_good-- <= 0){
|
||||
if (video->encoder.pkt_loss_prob_good-- <= 0) {
|
||||
int32_t new_pkt_loss_fact = TSK_CLAMP(TDAV_SESSION_VIDEO_PKT_LOSS_FACT_MIN, (video->encoder.pkt_loss_fact - 1), TDAV_SESSION_VIDEO_PKT_LOSS_FACT_MAX);
|
||||
if(video->encoder.pkt_loss_fact != new_pkt_loss_fact){
|
||||
if (video->encoder.pkt_loss_fact != new_pkt_loss_fact) {
|
||||
TSK_DEBUG_INFO("Upgrade bandwidth %d->%d", video->encoder.pkt_loss_fact, new_pkt_loss_fact);
|
||||
video->encoder.pkt_loss_fact = new_pkt_loss_fact;
|
||||
_tdav_session_video_bw_up(video);
|
||||
|
@ -609,10 +629,60 @@ static int tdav_session_video_rtcp_cb(const void* callback_data, const trtp_rtcp
|
|||
}
|
||||
case trtp_rtcp_psfb_fci_type_afb:
|
||||
{
|
||||
if(psfb->afb.type == trtp_rtcp_psfb_afb_type_remb){
|
||||
uint32_t bandwidth = ((psfb->afb.remb.mantissa << psfb->afb.remb.exp) / 1024);
|
||||
TSK_DEBUG_INFO("Receiving RTCP-AFB-REMB (%u), exp=%u, mantissa=%u, bandwidth = %ukbps", ((const trtp_rtcp_report_fb_t*)psfb)->ssrc_media, psfb->afb.remb.exp, psfb->afb.remb.mantissa, bandwidth);
|
||||
if (psfb->afb.type == trtp_rtcp_psfb_afb_type_remb) {
|
||||
uint32_t bandwidth_up_reported_kpbs = ((psfb->afb.remb.mantissa << psfb->afb.remb.exp) / 1024);
|
||||
TSK_DEBUG_INFO("Receiving RTCP-AFB-REMB (%u), exp=%u, mantissa=%u, bandwidth = %ukbps, congestion_ctrl_enabled=%s", ((const trtp_rtcp_report_fb_t*)psfb)->ssrc_media, psfb->afb.remb.exp, psfb->afb.remb.mantissa, bandwidth_up_reported_kpbs, base->congestion_ctrl_enabled ? "yes" : "no");
|
||||
#if TDAV_GOOG_REMB_FULL_SUPPORT
|
||||
if (base->congestion_ctrl_enabled) {
|
||||
uint32_t remb_upload_kbps = 0;
|
||||
tsk_bool_t remb_ok = tsk_false;
|
||||
uint64_t bytes_count_now;
|
||||
uint64_t bytes_count_out;
|
||||
static uint64_t* bytes_count_in_ptr_null = tsk_null;
|
||||
|
||||
if ((ret = trtp_manager_get_bytes_count(base->rtp_manager, bytes_count_in_ptr_null, &bytes_count_out)) == 0) {
|
||||
uint64_t duration;
|
||||
bytes_count_now = tsk_time_now();
|
||||
duration = (bytes_count_now - base->bytes_out.count_last_time);
|
||||
remb_ok = (base->bytes_out.count_last_time != 0 && duration > 0);
|
||||
if (remb_ok) {
|
||||
remb_upload_kbps = (int32_t)((((bytes_count_out - base->bytes_out.count) * 8 * 1000) / 1024) / duration);
|
||||
TSK_DEBUG_INFO("remb_upload_kbps=%u, bandwidth_up_reported_kpbs=%u", remb_upload_kbps, bandwidth_up_reported_kpbs);
|
||||
}
|
||||
base->bytes_out.count_last_time = bytes_count_now;
|
||||
base->bytes_out.count = bytes_count_out;
|
||||
}
|
||||
if (remb_ok) {
|
||||
int32_t pkt_loss_percent = bandwidth_up_reported_kpbs >= remb_upload_kbps ? 0 : ((remb_upload_kbps - bandwidth_up_reported_kpbs) / remb_upload_kbps) * 100;
|
||||
TSK_DEBUG_INFO("GOO-REMB: pkt_loss_percent=%d", pkt_loss_percent);
|
||||
if (pkt_loss_percent > 5) {
|
||||
// more than 5% pkt loss
|
||||
TSK_DEBUG_WARN("pkt_loss_percent(%u) > 5%%, using lower bw(%d)", pkt_loss_percent, bandwidth_up_reported_kpbs);
|
||||
_tdav_session_video_bw_kbps(video, bandwidth_up_reported_kpbs);
|
||||
}
|
||||
else if (pkt_loss_percent == 0) {
|
||||
#if 0
|
||||
// no pkt loss --> increase bw
|
||||
int32_t target_bw_max_upload_kbps = base->bandwidth_max_upload_kbps; // user-defined (guard), INT_MAX if not defined
|
||||
if (video->encoder.codec) {
|
||||
target_bw_max_upload_kbps = TSK_MIN(
|
||||
tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(video->encoder.codec)->out.width, TMEDIA_CODEC_VIDEO(video->encoder.codec)->out.height, TMEDIA_CODEC_VIDEO(video->encoder.codec)->out.fps),
|
||||
target_bw_max_upload_kbps);
|
||||
}
|
||||
if (target_bw_max_upload_kbps > remb_upload_kbps + ((remb_upload_kbps / 100) * 20)) {
|
||||
// target (best) bw is 20% less than what we're sending --> increase by 5%
|
||||
uint32_t new_upload_kbps = remb_upload_kbps + ((remb_upload_kbps / 100) * 5);
|
||||
TSK_DEBUG_INFO("current upload bw is too low, increasing from %u to %u", remb_upload_kbps, new_upload_kbps);
|
||||
_tdav_session_video_bw_kbps(video, new_upload_kbps);
|
||||
}
|
||||
#endif /* 0 */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#else
|
||||
// for now we just don't respect the requested bandwidth
|
||||
#endif /* TDAV_GOOG_REMB_FULL_SUPPORT */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -680,7 +750,7 @@ static int tdav_session_video_rtcp_cb(const void* callback_data, const trtp_rtcp
|
|||
}// switch
|
||||
}// while(rtcp-pkt)
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _tdav_session_video_set_defaults(tdav_session_video_t* self)
|
||||
|
@ -720,10 +790,12 @@ static int _tdav_session_video_jb_cb(const tdav_video_jb_cb_data_xt* data)
|
|||
}
|
||||
case tdav_video_jb_cb_data_type_tmfr:
|
||||
{
|
||||
base->time_last_frame_loss_report = tsk_time_now();
|
||||
_tdav_session_video_local_request_idr(session, "TMFR", data->ssrc);
|
||||
}
|
||||
case tdav_video_jb_cb_data_type_fl:
|
||||
{
|
||||
base->time_last_frame_loss_report = tsk_time_now();
|
||||
if(data->fl.count > TDAV_SESSION_VIDEO_PKT_LOSS_MAX_COUNT_TO_REQUEST_FIR){
|
||||
_tdav_session_video_local_request_idr(session, "TMFR", data->ssrc);
|
||||
}
|
||||
|
@ -803,7 +875,7 @@ static int _tdav_session_video_decode(tdav_session_video_t* self, const trtp_rtp
|
|||
|
||||
tsk_safeobj_lock(base);
|
||||
|
||||
if(self->started && base->consumer && base->consumer->is_started){
|
||||
if (self->started && base->consumer && base->consumer->is_started) {
|
||||
tsk_size_t out_size, _size;
|
||||
const void* _buffer;
|
||||
tdav_session_video_t* video = (tdav_session_video_t*)base;
|
||||
|
@ -929,28 +1001,60 @@ static int _tdav_session_video_decode(tdav_session_video_t* self, const trtp_rtp
|
|||
// - congestion control is enabled and
|
||||
// - fps changed or
|
||||
// - first frame or
|
||||
// - approximately every 5 minutes (300 = 60 * 5)
|
||||
if(base->congestion_ctrl_enabled && base->rtp_manager && (self->fps_changed || self->decoder.codec_decoded_frames_count == 0 || ((self->decoder.codec_decoded_frames_count % (TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.fps * 300)) == 0))){
|
||||
// - approximately every 1 seconds (1 = 1 * 1)
|
||||
if (base->congestion_ctrl_enabled && base->rtp_manager && (self->fps_changed || self->decoder.codec_decoded_frames_count == 0 || ((self->decoder.codec_decoded_frames_count % (TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.fps * 1)) == 0))){
|
||||
int32_t bandwidth_max_upload_kbps = base->bandwidth_max_upload_kbps;
|
||||
int32_t bandwidth_max_download_kbps = base->bandwidth_max_download_kbps;
|
||||
int32_t bandwidth_max_download_kbps = base->bandwidth_max_download_kbps; // user-defined (guard), INT_MAX if not defined
|
||||
// bandwidth already computed in start() but the decoded video size was not correct and based on the SDP negotiation
|
||||
bandwidth_max_download_kbps = TSK_MIN(
|
||||
tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.width, TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.height, TMEDIA_CODEC_VIDEO(self->decoder.codec)->in.fps),
|
||||
bandwidth_max_download_kbps);
|
||||
if(self->encoder.codec){
|
||||
if (self->encoder.codec) {
|
||||
bandwidth_max_upload_kbps = TSK_MIN(
|
||||
tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(self->encoder.codec)->out.width, TMEDIA_CODEC_VIDEO(self->encoder.codec)->out.height, TMEDIA_CODEC_VIDEO(self->encoder.codec)->out.fps),
|
||||
bandwidth_max_upload_kbps);
|
||||
}
|
||||
|
||||
#if TDAV_GOOG_REMB_FULL_SUPPORT
|
||||
{
|
||||
tsk_bool_t remb_ok = tsk_false;
|
||||
int32_t remb_download_kbps = 0;
|
||||
uint64_t now = 0;
|
||||
uint64_t bytes_count_in;
|
||||
static uint64_t* bytes_count_out_ptr_null = tsk_null;
|
||||
if ((ret = trtp_manager_get_bytes_count(base->rtp_manager, &bytes_count_in, bytes_count_out_ptr_null)) == 0) {
|
||||
uint64_t duration;
|
||||
now = tsk_time_now();
|
||||
duration = (now - base->bytes_in.count_last_time);
|
||||
remb_ok = (base->bytes_in.count_last_time != 0 && duration > 0);
|
||||
if (remb_ok) {
|
||||
remb_download_kbps = (int32_t)((((bytes_count_in - base->bytes_in.count) * 8 * 1000) / 1024) / duration);
|
||||
TSK_DEBUG_INFO("remb_download_kbps=%d", remb_download_kbps);
|
||||
}
|
||||
base->bytes_in.count_last_time = now;
|
||||
base->bytes_in.count = bytes_count_in;
|
||||
}
|
||||
if (remb_ok) {
|
||||
// if "remb_ok" is true then "now" has a valid value
|
||||
if ((now - base->time_last_frame_loss_report) > TDAV_SESSION_VIDEO_PKT_LOSS_NO_REPORT_BEFORE_INCREASING_BW) {
|
||||
TSK_DEBUG_INFO("No pakt loss since %d millis ... adding 5%% to the estimated max bandwidth", TDAV_SESSION_VIDEO_PKT_LOSS_NO_REPORT_BEFORE_INCREASING_BW);
|
||||
remb_download_kbps += (remb_download_kbps / 100) * 5; // add 5% to the estimated bandwidth
|
||||
}
|
||||
// CLAMP is used to make sure we will not report more than what the user defined as max values even if the estimated values are higher
|
||||
bandwidth_max_download_kbps = TSK_CLAMP(0, remb_download_kbps, bandwidth_max_download_kbps);
|
||||
}
|
||||
}
|
||||
#endif /* TDAV_GOOG_REMB_FULL_SUPPORT */
|
||||
|
||||
self->fps_changed = tsk_false; // reset
|
||||
TSK_DEBUG_INFO("video with congestion control enabled: max_bw_up=%d kpbs, max_bw_down=%d kpbs", bandwidth_max_upload_kbps, bandwidth_max_download_kbps);
|
||||
ret = trtp_manager_set_app_bandwidth_max(base->rtp_manager, bandwidth_max_upload_kbps, bandwidth_max_download_kbps);
|
||||
TSK_DEBUG_INFO("video with congestion control enabled: max_bw_up(unused)=%d kpbs, max_bw_down=%d kpbs", bandwidth_max_upload_kbps, bandwidth_max_download_kbps);
|
||||
ret = trtp_manager_set_app_bandwidth_max(base->rtp_manager, bandwidth_max_upload_kbps/* unused */, bandwidth_max_download_kbps);
|
||||
}
|
||||
// inc() frame count and consume decoded video
|
||||
++self->decoder.codec_decoded_frames_count;
|
||||
ret = tmedia_consumer_consume(base->consumer, _buffer, _size, __rtp_header);
|
||||
}
|
||||
else if(!base->consumer || !base->consumer->is_started){
|
||||
else if (!base->consumer || !base->consumer->is_started) {
|
||||
TSK_DEBUG_INFO("Consumer not started (is_null=%d)", !base->consumer);
|
||||
}
|
||||
|
||||
|
@ -1112,7 +1216,6 @@ static int tdav_session_video_start(tmedia_session_t* self)
|
|||
tsk_mutex_lock(video->encoder.h_mutex);
|
||||
TSK_OBJECT_SAFE_FREE(video->encoder.codec);
|
||||
video->encoder.codec = tsk_object_ref((tsk_object_t*)codec);
|
||||
|
||||
// initialize the encoder using user-defined values
|
||||
if ((ret = tdav_session_av_init_encoder(base, video->encoder.codec))) {
|
||||
TSK_DEBUG_ERROR("Failed to initialize the encoder [%s] codec", video->encoder.codec->plugin->desc);
|
||||
|
@ -1219,6 +1322,36 @@ static int tdav_session_video_set_ro(tmedia_session_t* self, const tsdp_header_M
|
|||
return ret;
|
||||
}
|
||||
|
||||
// Check if "RTCP-NACK" and "RTC-FIR" are supported
|
||||
{
|
||||
const tmedia_codec_t* codec;
|
||||
base->is_fb_fir_neg = base->is_fb_nack_neg = base->is_fb_googremb_neg = tsk_false;
|
||||
if ((codec = tdav_session_av_get_best_neg_codec(base))) {
|
||||
// a=rtcp-fb:* ccm fir
|
||||
// a=rtcp-fb:* nack
|
||||
// a=rtcp-fb:* goog-remb
|
||||
char attr_fir[256], attr_nack[256], attr_goog_remb[256];
|
||||
int index = 0;
|
||||
const tsdp_header_A_t* A;
|
||||
|
||||
sprintf(attr_fir, "%s ccm fir", codec->neg_format);
|
||||
sprintf(attr_nack, "%s nack", codec->neg_format);
|
||||
sprintf(attr_goog_remb, "%s goog-remb", codec->neg_format);
|
||||
|
||||
while ((A = tsdp_header_M_findA_at(m, "rtcp-fb", index++))) {
|
||||
if (!base->is_fb_fir_neg) {
|
||||
base->is_fb_fir_neg = (tsk_striequals(A->value, "* ccm fir") || tsk_striequals(A->value, attr_fir));
|
||||
}
|
||||
if (!base->is_fb_nack_neg) {
|
||||
base->is_fb_nack_neg = (tsk_striequals(A->value, "* nack") || tsk_striequals(A->value, attr_nack));
|
||||
}
|
||||
if (!base->is_fb_googremb_neg) {
|
||||
base->is_fb_googremb_neg = (tsk_striequals(A->value, "* goog-remb") || tsk_striequals(A->value, attr_goog_remb));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
// set callbacks
|
||||
ret = _tdav_session_video_set_callbacks(self);
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2010-2011 Mamadou Diop.
|
||||
*
|
||||
* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
|
||||
* Copyright (C) 2010-2015 Mamadou DIOP
|
||||
*
|
||||
* This file is part of Open Source Doubango Framework.
|
||||
*
|
||||
|
@ -25,8 +23,5 @@
|
|||
* http://tools.ietf.org/html/draft-ietf-mmusic-ice-19
|
||||
* http://tools.ietf.org/html/draft-ietf-mmusic-ice-tcp-08
|
||||
*
|
||||
* @author Mamadou Diop <diopmamadou(at)doubango.org>
|
||||
*
|
||||
|
||||
*/
|
||||
#include "tnet_ice.h"
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2010-2011 Mamadou Diop.
|
||||
*
|
||||
* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
|
||||
* Copyright (C) 2010-2015 Mamadou DIOP
|
||||
*
|
||||
* This file is part of Open Source Doubango Framework.
|
||||
*
|
||||
|
@ -25,9 +23,6 @@
|
|||
* http://tools.ietf.org/html/draft-ietf-mmusic-ice-19
|
||||
* http://tools.ietf.org/html/draft-ietf-mmusic-ice-tcp-08
|
||||
*
|
||||
* @author Mamadou Diop <diopmamadou(at)doubango.org>
|
||||
*
|
||||
|
||||
*/
|
||||
#ifndef TNET_ICE_H
|
||||
#define TNET_ICE_H
|
||||
|
|
|
@ -997,6 +997,26 @@ int tnet_ice_ctx_send_turn_rtcp(struct tnet_ice_ctx_s* self, const void* data, t
|
|||
: _tnet_ice_ctx_send_turn_raw(self, self->turn.ss_nominated_rtcp, self->turn.peer_id_rtcp, data, size);
|
||||
}
|
||||
|
||||
int tnet_ice_ctx_turn_get_bytes_count(const struct tnet_ice_ctx_s* self, uint64_t* bytes_in, uint64_t* bytes_out)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!self) {
|
||||
TSK_DEBUG_ERROR("Invalid parameter");
|
||||
return -1;
|
||||
}
|
||||
ret = tnet_turn_session_get_bytes_count(self->turn.ss_nominated_rtp, bytes_in, bytes_out);
|
||||
if (ret == 0 && !self->use_rtcpmux) {
|
||||
uint64_t _bytes_in, _bytes_out;
|
||||
ret = tnet_turn_session_get_bytes_count(self->turn.ss_nominated_rtcp, &_bytes_in, &_bytes_out);
|
||||
if (ret == 0) {
|
||||
if (bytes_in) *bytes_in += _bytes_in;
|
||||
if (bytes_out) *bytes_out += _bytes_out;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* tnet_ice_ctx_get_ufrag(const struct tnet_ice_ctx_s* self)
|
||||
{
|
||||
return (self && self->ufrag) ? self->ufrag : tsk_null;
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Doubango Telecom <http://www.doubango.org>.
|
||||
*
|
||||
* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
|
||||
* Copyright (C) 2012-2015 Doubango Telecom <http://www.doubango.org>.
|
||||
*
|
||||
* This file is part of Open Source Doubango Framework.
|
||||
*
|
||||
|
@ -22,7 +20,6 @@
|
|||
|
||||
/**@file tnet_ice_ctx.h
|
||||
* @brief Interactive Connectivity Establishment (ICE) implementation as per RFC 5245.
|
||||
* @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
|
||||
*/
|
||||
|
||||
#ifndef TNET_ICE_CTX_H
|
||||
|
@ -100,6 +97,7 @@ TINYNET_API int tnet_ice_ctx_recv_stun_message(struct tnet_ice_ctx_s* self, cons
|
|||
TINYNET_API int tnet_ice_ctx_send_turn_rtp(struct tnet_ice_ctx_s* self, const void* data, tsk_size_t size);
|
||||
TINYNET_API int tnet_ice_ctx_send_turn_rtcp(struct tnet_ice_ctx_s* self, const void* data, tsk_size_t size);
|
||||
|
||||
TINYNET_API int tnet_ice_ctx_turn_get_bytes_count(const struct tnet_ice_ctx_s* self, uint64_t* bytes_in, uint64_t* bytes_out);
|
||||
TINYNET_API const char* tnet_ice_ctx_get_ufrag(const struct tnet_ice_ctx_s* self);
|
||||
TINYNET_API const char* tnet_ice_ctx_get_pwd(const struct tnet_ice_ctx_s* self);
|
||||
|
||||
|
|
|
@ -251,6 +251,42 @@ int tnet_socket_send_stream(tnet_socket_t* self, const void* data, tsk_size_t si
|
|||
return (int)tnet_sockfd_send(self->fd, data, size, 0);
|
||||
}
|
||||
|
||||
/**@ingroup tnet_socket_group
|
||||
* @retval Zero if succeed and nonzero error code otherwise.
|
||||
*/
|
||||
int tnet_socket_handle_brokenpipe(tnet_socket_t* self)
|
||||
{
|
||||
int ret;
|
||||
tnet_fd_t fd_old, fd_new;
|
||||
if (!self || !TNET_SOCKET_TYPE_IS_DGRAM(self->type)) { // Must be UDP
|
||||
TSK_DEBUG_ERROR("Invalid parameter");
|
||||
return -1;
|
||||
}
|
||||
fd_old = self->fd;
|
||||
fd_new = TNET_INVALID_FD;
|
||||
|
||||
// close old fd
|
||||
ret = tnet_sockfd_close(&self->fd);
|
||||
// try to create an fd binding to the same address
|
||||
if ((ret = tnet_sockfd_init(self->ip, self->port, self->type, &fd_new)) != 0) {
|
||||
TNET_PRINT_LAST_ERROR("Find to bind to %s:%d", self->ip, self->port);
|
||||
// TODO: Create completly new socket?
|
||||
return ret;
|
||||
}
|
||||
#if TNET_UNDER_IPHONE || TNET_UNDER_IPHONE_SIMULATOR
|
||||
/* disable SIGPIPE signal */
|
||||
{
|
||||
int yes = 1;
|
||||
if (setsockopt(fd_new, SOL_SOCKET, SO_NOSIGPIPE, (char*)&yes, sizeof(int))){
|
||||
TNET_PRINT_LAST_ERROR("setsockopt(%d, SO_NOSIGPIPE) have failed", fd_new);
|
||||
}
|
||||
}
|
||||
#endif /* TNET_UNDER_IPHONE || TNET_UNDER_IPHONE_SIMULATOR */
|
||||
TSK_DEBUG_INFO("Broken pipe result for {%s:%d}: %d -> %d", self->ip, self->port, fd_old, fd_new);
|
||||
self->fd = fd_new;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**@ingroup tnet_socket_group
|
||||
* Closes a socket.
|
||||
* @param sock The socket to close.
|
||||
|
|
|
@ -190,6 +190,7 @@ typedef tsk_list_t tnet_sockets_L_t; /**< List of @ref tnet_socket_t elements. *
|
|||
TINYNET_API tnet_socket_t* tnet_socket_create_2(const char*host, tnet_port_t port, tnet_socket_type_t type, tsk_bool_t nonblocking, tsk_bool_t bindsocket);
|
||||
TINYNET_API tnet_socket_t* tnet_socket_create(const char* host, tnet_port_t port, tnet_socket_type_t type);
|
||||
TINYNET_API int tnet_socket_send_stream(tnet_socket_t* self, const void* data, tsk_size_t size);
|
||||
TINYNET_API int tnet_socket_handle_brokenpipe(tnet_socket_t* self);
|
||||
|
||||
TINYNET_GEXTERN const tsk_object_def_t *tnet_socket_def_t;
|
||||
|
||||
|
|
|
@ -723,6 +723,17 @@ tnet_fd_t tnet_transport_get_master_fd(const tnet_transport_handle_t *handle)
|
|||
return ((const tnet_transport_t *)handle)->master ? ((const tnet_transport_t *)handle)->master->fd : TNET_INVALID_FD;
|
||||
}
|
||||
|
||||
int tnet_transport_get_bytes_count(const tnet_transport_handle_t *handle, uint64_t* bytes_in, uint64_t* bytes_out)
|
||||
{
|
||||
if (!handle){
|
||||
TSK_DEBUG_ERROR("Invalid parameter");
|
||||
return -1;
|
||||
}
|
||||
if (bytes_in) *bytes_in = ((const tnet_transport_t *)handle)->bytes_in;
|
||||
if (bytes_out) *bytes_out = ((const tnet_transport_t *)handle)->bytes_out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects a socket.
|
||||
* @param handle The transport to use to connect() the socket. The new socket will be managed by this transport.
|
||||
|
|
|
@ -41,8 +41,6 @@ TNET_BEGIN_DECLS
|
|||
|
||||
#define TNET_TRANSPORT_CB_F(callback) ((tnet_transport_cb_f)callback)
|
||||
|
||||
typedef void tnet_transport_handle_t;
|
||||
|
||||
typedef enum tnet_transport_event_type_e
|
||||
{
|
||||
event_data,
|
||||
|
@ -51,6 +49,7 @@ typedef enum tnet_transport_event_type_e
|
|||
event_removed,
|
||||
event_connected,
|
||||
event_accepted,
|
||||
event_brokenpipe, // iOS: UDP sockets closed, to be restored now that the app is on foreground
|
||||
|
||||
event_dtls_handshake_started,
|
||||
event_dtls_handshake_succeed,
|
||||
|
@ -121,6 +120,7 @@ TINYNET_API int tnet_transport_dtls_get_handshakingdata(tnet_transport_handle_t*
|
|||
|
||||
TINYNET_API tnet_socket_type_t tnet_transport_get_type(const tnet_transport_handle_t *handle);
|
||||
TINYNET_API tnet_fd_t tnet_transport_get_master_fd(const tnet_transport_handle_t *handle);
|
||||
TINYNET_API int tnet_transport_get_bytes_count(const tnet_transport_handle_t *handle, uint64_t* bytes_in, uint64_t* bytes_out);
|
||||
TINYNET_API int tnet_transport_shutdown(tnet_transport_handle_t* handle);
|
||||
|
||||
typedef struct tnet_transport_s
|
||||
|
@ -138,6 +138,9 @@ typedef struct tnet_transport_s
|
|||
tsk_object_t *context;
|
||||
tsk_bool_t prepared;
|
||||
|
||||
uint64_t bytes_out;
|
||||
uint64_t bytes_in;
|
||||
|
||||
//unsigned connected:1;
|
||||
void* mainThreadId[1];
|
||||
|
||||
|
|
|
@ -490,7 +490,7 @@ bail:
|
|||
tsk_size_t tnet_transport_sendto(const tnet_transport_handle_t *handle, tnet_fd_t from, const struct sockaddr *to, const void* buf, tsk_size_t size)
|
||||
{
|
||||
tnet_transport_t *transport = (tnet_transport_t*)handle;
|
||||
int numberOfBytesSent = 0;
|
||||
int numberOfBytesSent = 0, ret;
|
||||
|
||||
if (!transport) {
|
||||
TSK_DEBUG_ERROR("Invalid server handle");
|
||||
|
@ -502,9 +502,17 @@ tsk_size_t tnet_transport_sendto(const tnet_transport_handle_t *handle, tnet_fd_
|
|||
goto bail;
|
||||
}
|
||||
|
||||
if ((numberOfBytesSent = (int)sendto(from, buf, size, 0, to, tnet_get_sockaddr_size(to))) < size) {
|
||||
TNET_PRINT_LAST_ERROR("sendto have failed");
|
||||
goto bail;
|
||||
while (numberOfBytesSent < size && (ret = (int)sendto(from, buf, size, 0, to, tnet_get_sockaddr_size(to))) >= 0) {
|
||||
numberOfBytesSent += ret;
|
||||
}
|
||||
if (numberOfBytesSent < size) {
|
||||
if (tnet_geterrno() == TNET_ERROR_BROKENPIPE) {
|
||||
TSK_DEBUG_INFO("UDP socket with fd=%d returned EPIPE...alerting the sender with 'event_brokenpipe' event", from);
|
||||
TSK_RUNNABLE_ENQUEUE(transport, event_brokenpipe, transport->callback_data, from);
|
||||
}
|
||||
else {
|
||||
TNET_PRINT_LAST_ERROR("sendto(fd=%d) have failed", from);
|
||||
}
|
||||
}
|
||||
|
||||
bail:
|
||||
|
|
|
@ -237,6 +237,7 @@ tsk_size_t tnet_transport_send(const tnet_transport_handle_t *handle, tnet_fd_t
|
|||
}
|
||||
|
||||
bail:
|
||||
transport->bytes_out += numberOfBytesSent;
|
||||
return numberOfBytesSent;
|
||||
}
|
||||
|
||||
|
@ -261,6 +262,7 @@ tsk_size_t tnet_transport_sendto(const tnet_transport_handle_t *handle, tnet_fd_
|
|||
}
|
||||
|
||||
bail:
|
||||
transport->bytes_out += numberOfBytesSent;
|
||||
return numberOfBytesSent;
|
||||
}
|
||||
|
||||
|
@ -811,6 +813,7 @@ void *tnet_transport_mainthread(void *param)
|
|||
}
|
||||
|
||||
if(len > 0){
|
||||
transport->bytes_in += len;
|
||||
e = tnet_transport_event_create(event_data, transport->callback_data, active_socket->fd);
|
||||
e->data = buffer, buffer = tsk_null;
|
||||
e->size = len;
|
||||
|
|
|
@ -285,6 +285,7 @@ try_again:
|
|||
}
|
||||
|
||||
bail:
|
||||
transport->bytes_out += sent;
|
||||
return sent;
|
||||
}
|
||||
|
||||
|
@ -312,6 +313,7 @@ tsk_size_t tnet_transport_sendto(const tnet_transport_handle_t *handle, tnet_fd_
|
|||
}
|
||||
|
||||
bail:
|
||||
transport->bytes_out += numberOfBytesSent;
|
||||
return numberOfBytesSent;
|
||||
}
|
||||
|
||||
|
@ -739,6 +741,7 @@ void* TSK_STDCALL tnet_transport_mainthread(void *param)
|
|||
else
|
||||
{
|
||||
tnet_transport_event_t* e = tnet_transport_event_create(event_data, transport->callback_data, active_socket->fd);
|
||||
transport->bytes_in += wsaBuffer.len;
|
||||
e->data = wsaBuffer.buf;
|
||||
e->size = wsaBuffer.len;
|
||||
e->remote_addr = remote_addr;
|
||||
|
|
|
@ -77,6 +77,8 @@ typedef char tnet_ip_t[INET6_ADDRSTRLEN];
|
|||
typedef uint8_t tnet_mac_address[6];
|
||||
typedef unsigned char tnet_fingerprint_t[TNET_FINGERPRINT_MAX + 1];
|
||||
|
||||
typedef void tnet_transport_handle_t;
|
||||
|
||||
typedef tsk_list_t tnet_interfaces_L_t; /**< List of @ref tnet_interface_t elements*/
|
||||
typedef tsk_list_t tnet_addresses_L_t; /**< List of @ref tnet_address_t elements*/
|
||||
|
||||
|
@ -132,6 +134,7 @@ static const char* TNET_DTLS_HASH_NAMES[TNET_DTLS_HASH_TYPE_MAX] =
|
|||
# define TNET_ERROR_INTR WSAEINTR
|
||||
# define TNET_ERROR_ISCONN WSAEISCONN
|
||||
# define TNET_ERROR_EAGAIN TNET_ERROR_WOULDBLOCK /* WinSock FIX */
|
||||
# define TNET_ERROR_BROKENPIPE WSAECONNABORTED
|
||||
# if (TNET_UNDER_WINDOWS_RT || TNET_UNDER_WINDOWS_CE) /* gai_strerrorA() links against FormatMessageA which is not allowed on the store */
|
||||
# if !defined (WC_ERR_INVALID_CHARS)
|
||||
# define WC_ERR_INVALID_CHARS 0
|
||||
|
@ -163,6 +166,7 @@ static const char* TNET_DTLS_HASH_NAMES[TNET_DTLS_HASH_TYPE_MAX] =
|
|||
# define TNET_ERROR_INTR EINTR
|
||||
# define TNET_ERROR_ISCONN EISCONN
|
||||
# define TNET_ERROR_EAGAIN EAGAIN
|
||||
# define TNET_ERROR_BROKENPIPE EPIPE
|
||||
# define tnet_gai_strerror gai_strerror
|
||||
#endif
|
||||
#define TNET_INVALID_FD TNET_INVALID_SOCKET
|
||||
|
|
|
@ -1804,14 +1804,14 @@ int tnet_sockfd_sendto(tnet_fd_t fd, const struct sockaddr *to, const void* buf,
|
|||
#endif
|
||||
if (ret <= 0) {
|
||||
if (tnet_geterrno() == TNET_ERROR_WOULDBLOCK) {
|
||||
TSK_DEBUG_INFO("SendUdp() - WouldBlock. Retrying...");
|
||||
TSK_DEBUG_INFO("SendUdp(fd=%d) - WouldBlock. Retrying...", fd);
|
||||
if (try_guard--) {
|
||||
tsk_thread_sleep(10);
|
||||
goto try_again;
|
||||
}
|
||||
}
|
||||
else {
|
||||
TNET_PRINT_LAST_ERROR("sendto() failed");
|
||||
TNET_PRINT_LAST_ERROR("sendto(fd=%d) failed", fd);
|
||||
}
|
||||
goto bail;
|
||||
}
|
||||
|
|
|
@ -780,6 +780,15 @@ int tnet_turn_session_get_req_transport(const struct tnet_turn_session_s* pc_sel
|
|||
return 0;
|
||||
}
|
||||
|
||||
int tnet_turn_session_get_bytes_count(const struct tnet_turn_session_s* pc_self, uint64_t* bytes_in, uint64_t* bytes_out)
|
||||
{
|
||||
if (!pc_self) {
|
||||
TSK_DEBUG_ERROR("Invalid parameter");
|
||||
return -1;
|
||||
}
|
||||
return tnet_transport_get_bytes_count(pc_self->p_transport, bytes_in, bytes_out);
|
||||
}
|
||||
|
||||
int tnet_turn_session_createpermission(struct tnet_turn_session_s* p_self, const char* pc_peer_addr, uint16_t u_peer_port, tnet_turn_peer_id_t* pu_id)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -2022,6 +2031,22 @@ static int _tnet_turn_session_transport_layer_process_cb(const tnet_transport_ev
|
|||
switch(e->type){
|
||||
case event_data:
|
||||
break;
|
||||
case event_brokenpipe:
|
||||
tsk_safeobj_lock(p_ss);
|
||||
if (p_ss->p_lcl_sock && e->local_fd == p_ss->p_lcl_sock->fd) {
|
||||
tnet_fd_t broken_fd = e->local_fd;
|
||||
tsk_bool_t registered_fd = !!tnet_transport_have_socket(p_ss->p_transport, broken_fd);
|
||||
if (registered_fd) {
|
||||
tnet_transport_remove_socket(p_ss->p_transport, &broken_fd);
|
||||
}
|
||||
if (tnet_socket_handle_brokenpipe(p_ss->p_lcl_sock) == 0) {
|
||||
if (registered_fd) {
|
||||
tnet_transport_add_socket(p_ss->p_transport, p_ss->p_lcl_sock->fd, p_ss->p_lcl_sock->type, tsk_false/* do not take ownership */, tsk_true/* only Meaningful for tls*/, tsk_null);
|
||||
}
|
||||
}
|
||||
}
|
||||
tsk_safeobj_unlock(p_ss);
|
||||
return 0;
|
||||
case event_connected:
|
||||
if (p_ss->p_lcl_sock && p_ss->p_lcl_sock->fd == e->local_fd) {
|
||||
tsk_safeobj_lock(p_ss);
|
||||
|
|
|
@ -87,6 +87,7 @@ TINYNET_API int tnet_turn_session_get_socket_local(struct tnet_turn_session_s* p
|
|||
TINYNET_API int tnet_turn_session_get_state_createperm(const struct tnet_turn_session_s* pc_self, tnet_turn_peer_id_t u_peer_id, enum tnet_stun_state_e *pe_state);
|
||||
TINYNET_API int tnet_turn_session_get_state_connbind(const struct tnet_turn_session_s* pc_self, tnet_turn_peer_id_t u_peer_id, enum tnet_stun_state_e *pe_state);
|
||||
TINYNET_API int tnet_turn_session_get_req_transport(const struct tnet_turn_session_s* pc_self, enum tnet_turn_transport_e *pe_transport);
|
||||
TINYNET_API int tnet_turn_session_get_bytes_count(const struct tnet_turn_session_s* pc_self, uint64_t* bytes_in, uint64_t* bytes_out);
|
||||
TINYNET_API int tnet_turn_session_createpermission(struct tnet_turn_session_s* p_self, const char* pc_peer_addr, uint16_t u_peer_port, tnet_turn_peer_id_t* pu_peer_id);
|
||||
TINYNET_API int tnet_turn_session_deletepermission(struct tnet_turn_session_s* p_self, tnet_turn_peer_id_t u_peer_id);
|
||||
TINYNET_API int tnet_turn_session_chanbind(struct tnet_turn_session_s* p_self, tnet_turn_peer_id_t u_peer_id);
|
||||
|
|
|
@ -41,6 +41,7 @@ TRTP_BEGIN_DECLS
|
|||
struct trtp_rtcp_packet_s;
|
||||
struct trtp_rtp_packet_s;
|
||||
struct tnet_ice_ctx_s;
|
||||
struct tnet_transport_s;
|
||||
|
||||
typedef int (*trtp_rtcp_cb_f)(const void* callback_data, const struct trtp_rtcp_packet_s* packet);
|
||||
|
||||
|
@ -60,6 +61,10 @@ int trtp_rtcp_session_signal_pkt_loss(struct trtp_rtcp_session_s* self, uint32_t
|
|||
int trtp_rtcp_session_signal_frame_corrupted(struct trtp_rtcp_session_s* self, uint32_t ssrc_media);
|
||||
int trtp_rtcp_session_signal_jb_error(struct trtp_rtcp_session_s* self, uint32_t ssrc_media);
|
||||
|
||||
tnet_fd_t trtp_rtcp_session_get_local_fd(const struct trtp_rtcp_session_s* self);
|
||||
int trtp_rtcp_session_set_local_fd(struct trtp_rtcp_session_s* self, tnet_fd_t local_fd);
|
||||
int trtp_rtcp_session_set_net_transport(struct trtp_rtcp_session_s* self, struct tnet_transport_s* transport);
|
||||
|
||||
TRTP_END_DECLS
|
||||
|
||||
#endif /* TINYMEDIA_RTCP_SESSION_H */
|
||||
|
|
|
@ -106,6 +106,7 @@ typedef struct trtp_manager_s
|
|||
struct{
|
||||
void* ptr;
|
||||
tsk_size_t size;
|
||||
tsk_size_t index;
|
||||
} serial_buffer;
|
||||
} rtp;
|
||||
|
||||
|
@ -211,6 +212,7 @@ TINYRTP_API int trtp_manager_set_proxy_info(trtp_manager_t* self, enum tnet_prox
|
|||
TINYRTP_API int trtp_manager_start(trtp_manager_t* self);
|
||||
TINYRTP_API tsk_size_t trtp_manager_send_rtp(trtp_manager_t* self, const void* data, tsk_size_t size, uint32_t duration, tsk_bool_t marker, tsk_bool_t last_packet);
|
||||
TINYRTP_API tsk_size_t trtp_manager_send_rtp_packet(trtp_manager_t* self, const struct trtp_rtp_packet_s* packet, tsk_bool_t bypass_encrypt);
|
||||
TINYRTP_API int trtp_manager_get_bytes_count(trtp_manager_t* self, uint64_t* bytes_in, uint64_t* bytes_out);
|
||||
TINYRTP_API tsk_size_t trtp_manager_send_rtp_raw(trtp_manager_t* self, const void* data, tsk_size_t size);
|
||||
TINYRTP_API int trtp_manager_set_app_bandwidth_max(trtp_manager_t* self, int32_t bw_upload_kbps, int32_t bw_download_kbps);
|
||||
TINYRTP_API int trtp_manager_signal_pkt_loss(trtp_manager_t* self, uint32_t ssrc_media, const uint16_t* seq_nums, tsk_size_t count);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
#include "ice/tnet_ice_ctx.h"
|
||||
#include "turn/tnet_turn_session.h"
|
||||
#include "tnet_transport.h"
|
||||
|
||||
#include "tnet_utils.h"
|
||||
|
||||
|
@ -268,8 +269,9 @@ typedef struct trtp_rtcp_session_s
|
|||
|
||||
tsk_bool_t is_started;
|
||||
tnet_fd_t local_fd;
|
||||
struct tnet_transport_s* transport; // not starter -> do not stop
|
||||
const struct sockaddr * remote_addr;
|
||||
struct tnet_ice_ctx_s* ice_ctx;
|
||||
struct tnet_ice_ctx_s* ice_ctx; // not starter -> do not stop
|
||||
tsk_bool_t is_ice_turn_active;
|
||||
|
||||
const void* callback_data;
|
||||
|
@ -355,8 +357,9 @@ static tsk_object_t* trtp_rtcp_session_dtor(tsk_object_t * self)
|
|||
TSK_OBJECT_SAFE_FREE(session->sources);
|
||||
TSK_OBJECT_SAFE_FREE(session->source_local);
|
||||
TSK_OBJECT_SAFE_FREE(session->sdes);
|
||||
TSK_OBJECT_SAFE_FREE(session->ice_ctx);
|
||||
TSK_OBJECT_SAFE_FREE(session->ice_ctx); // not starter -> do not stop
|
||||
TSK_FREE(session->cname);
|
||||
TSK_OBJECT_SAFE_FREE(session->transport); // not starter -> do not stop
|
||||
// release the handle for the global timer manager
|
||||
tsk_timer_mgr_global_unref(&session->timer.handle_global);
|
||||
|
||||
|
@ -765,6 +768,36 @@ int trtp_rtcp_session_signal_jb_error(struct trtp_rtcp_session_s* self, uint32_t
|
|||
return trtp_rtcp_session_signal_frame_corrupted(self, ssrc_media);
|
||||
}
|
||||
|
||||
tnet_fd_t trtp_rtcp_session_get_local_fd(const struct trtp_rtcp_session_s* self)
|
||||
{
|
||||
if (!self) {
|
||||
TSK_DEBUG_ERROR("Invalid parameter");
|
||||
return TNET_INVALID_FD;
|
||||
}
|
||||
return self->local_fd;
|
||||
}
|
||||
|
||||
int trtp_rtcp_session_set_local_fd(struct trtp_rtcp_session_s* self, tnet_fd_t local_fd)
|
||||
{
|
||||
if (!self) {
|
||||
TSK_DEBUG_ERROR("Invalid parameter");
|
||||
return -1;
|
||||
}
|
||||
self->local_fd = local_fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int trtp_rtcp_session_set_net_transport(struct trtp_rtcp_session_s* self, struct tnet_transport_s* transport)
|
||||
{
|
||||
if (!self) {
|
||||
TSK_DEBUG_ERROR("Invalid parameter");
|
||||
return -1;
|
||||
}
|
||||
TSK_OBJECT_SAFE_FREE(self->transport);
|
||||
self->transport = tsk_object_ref(transport);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static tsk_bool_t _trtp_rtcp_session_have_source(trtp_rtcp_session_t* self, uint32_t ssrc)
|
||||
{
|
||||
tsk_list_item_t* item;
|
||||
|
@ -925,9 +958,9 @@ static tsk_size_t _trtp_rtcp_session_send_raw(trtp_rtcp_session_t* self, const v
|
|||
ret = (tnet_ice_ctx_send_turn_rtcp(self->ice_ctx, data, size) == 0) ? size : 0; // returns #0 if ok
|
||||
}
|
||||
else {
|
||||
if (tnet_sockfd_sendto(self->local_fd, self->remote_addr, data, size) == size){ // returns number of sent bytes
|
||||
ret = size;
|
||||
}
|
||||
ret = self->transport
|
||||
? tnet_transport_sendto(self->transport, self->local_fd, self->remote_addr, data, size)
|
||||
: tnet_sockfd_sendto(self->local_fd, self->remote_addr, data, size);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -93,6 +93,38 @@ static int _trtp_transport_layer_cb(const tnet_transport_event_t* e)
|
|||
{
|
||||
return _trtp_manager_recv_data(manager, e->data, e->size, e->local_fd, &e->remote_addr);
|
||||
}
|
||||
case event_brokenpipe:
|
||||
{
|
||||
tsk_safeobj_lock(manager);
|
||||
tnet_fd_t broken_fd = e->local_fd;
|
||||
tnet_socket_t* socket = tsk_null;
|
||||
tsk_bool_t is_rtcp_socket = tsk_false;
|
||||
|
||||
if (manager->transport && manager->transport->master && manager->transport->master->fd == broken_fd) {
|
||||
socket = manager->transport->master;
|
||||
}
|
||||
else if (manager->rtcp.local_socket && manager->rtcp.local_socket->fd == broken_fd) {
|
||||
socket = manager->rtcp.local_socket;
|
||||
is_rtcp_socket = tsk_true;
|
||||
}
|
||||
if (socket) {
|
||||
tsk_bool_t registered_fd = !!tnet_transport_have_socket(manager->transport, broken_fd);
|
||||
if (registered_fd) {
|
||||
tnet_transport_remove_socket(manager->transport, &broken_fd); // broken_fd=-1
|
||||
broken_fd = e->local_fd; // restore
|
||||
}
|
||||
if (tnet_socket_handle_brokenpipe(socket) == 0) {
|
||||
if (registered_fd) {
|
||||
tnet_transport_add_socket(manager->transport, socket->fd, socket->type, tsk_false/* do not take ownership */, tsk_true/* only Meaningful for tls*/, tsk_null);
|
||||
}
|
||||
if (manager->rtcp.session && trtp_rtcp_session_get_local_fd(manager->rtcp.session) == broken_fd) {
|
||||
trtp_rtcp_session_set_local_fd(manager->rtcp.session, socket->fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
tsk_safeobj_unlock(manager);
|
||||
return 0;
|
||||
}
|
||||
#if HAVE_SRTP
|
||||
/* DTLS - SRTP events */
|
||||
case event_dtls_handshake_succeed:
|
||||
|
@ -457,10 +489,17 @@ static int _trtp_manager_recv_data(const trtp_manager_t* self, const uint8_t* da
|
|||
err_status_t status;
|
||||
if(self->srtp_ctx_neg_remote){
|
||||
if((status = srtp_unprotect(self->srtp_ctx_neg_remote->rtp.session, (void*)data_ptr, (int*)&data_size)) != err_status_ok){
|
||||
if (status == err_status_replay_fail) {
|
||||
// replay (because of RTCP-NACK nothing to worry about)
|
||||
TSK_DEBUG_INFO("srtp_unprotect(RTP) returned 'err_status_replay_fail'");
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
TSK_DEBUG_ERROR("srtp_unprotect(RTP) failed with error code=%d, seq_num=%u", (int)status, (data_size > 4 ? tnet_ntohs_2(&data_ptr[2]) : 0x0000));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if((packet_rtp = trtp_rtp_packet_deserialize(data_ptr, data_size))){
|
||||
// update remote SSRC based on received RTP packet
|
||||
|
@ -1463,6 +1502,7 @@ int trtp_manager_start(trtp_manager_t* self)
|
|||
if(self->rtcp.session){
|
||||
ret = trtp_rtcp_session_set_callback(self->rtcp.session, self->rtcp.cb.fun, self->rtcp.cb.usrdata);
|
||||
ret = trtp_rtcp_session_set_app_bandwidth_max(self->rtcp.session, self->app_bw_max_upload, self->app_bw_max_download);
|
||||
ret = trtp_rtcp_session_set_net_transport(self->rtcp.session, self->transport);
|
||||
if((ret = trtp_rtcp_session_start(self->rtcp.session, local_rtcp_fd, (const struct sockaddr *)&self->rtcp.remote_addr))){
|
||||
TSK_DEBUG_ERROR("Failed to start RTCP session");
|
||||
goto bail;
|
||||
|
@ -1569,6 +1609,9 @@ tsk_size_t trtp_manager_send_rtp_packet(trtp_manager_t* self, const struct trtp_
|
|||
|
||||
tsk_safeobj_lock(self);
|
||||
|
||||
// reset index
|
||||
self->rtp.serial_buffer.index = 0;
|
||||
|
||||
/* check if transport is started */
|
||||
if(!self->is_started || !self->transport || !self->transport->master){
|
||||
TSK_DEBUG_WARN("RTP engine not ready yet");
|
||||
|
@ -1598,7 +1641,7 @@ tsk_size_t trtp_manager_send_rtp_packet(trtp_manager_t* self, const struct trtp_
|
|||
}
|
||||
|
||||
/* serialize and send over the network */
|
||||
if((ret = (int)trtp_rtp_packet_serialize_to(packet, self->rtp.serial_buffer.ptr, xsize))){
|
||||
if ((ret = (int)trtp_rtp_packet_serialize_to(packet, self->rtp.serial_buffer.ptr, xsize))) {
|
||||
void* data_ptr = self->rtp.serial_buffer.ptr;
|
||||
int data_size = ret;
|
||||
#if HAVE_SRTP
|
||||
|
@ -1610,6 +1653,7 @@ tsk_size_t trtp_manager_send_rtp_packet(trtp_manager_t* self, const struct trtp_
|
|||
}
|
||||
}
|
||||
#endif
|
||||
self->rtp.serial_buffer.index = data_size; // update index
|
||||
if (/* number of bytes sent */(ret = (int)trtp_manager_send_rtp_raw(self, data_ptr, data_size)) > 0) {
|
||||
// forward packet to the RTCP session
|
||||
if (self->rtcp.session) {
|
||||
|
@ -1642,12 +1686,35 @@ tsk_size_t trtp_manager_send_rtp_raw(trtp_manager_t* self, const void* data, tsk
|
|||
ret = (tnet_ice_ctx_send_turn_rtp(self->ice_ctx, data, size) == 0) ? size : 0; // returns #0 if ok
|
||||
}
|
||||
else {
|
||||
#if 1
|
||||
ret = tnet_transport_sendto(self->transport, self->transport->master->fd, (const struct sockaddr *)&self->rtp.remote_addr, data, size); // returns number of sent bytes
|
||||
#else
|
||||
ret = tnet_sockfd_sendto(self->transport->master->fd, (const struct sockaddr *)&self->rtp.remote_addr, data, size); // returns number of sent bytes
|
||||
#endif
|
||||
}
|
||||
tsk_safeobj_unlock(self);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int trtp_manager_get_bytes_count(trtp_manager_t* self, uint64_t* bytes_in, uint64_t* bytes_out)
|
||||
{
|
||||
if (!self) {
|
||||
TSK_DEBUG_ERROR("Invalid parameter");
|
||||
return -1;
|
||||
}
|
||||
if (!self->is_started) {
|
||||
TSK_DEBUG_INFO("trtp_manager_get_bytes_count() called before starting RTP manager... returning zeros");
|
||||
if (bytes_in) *bytes_in = 0;
|
||||
if (bytes_out) *bytes_out = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (self->is_ice_turn_active) {
|
||||
return tnet_ice_ctx_turn_get_bytes_count(self->ice_ctx, bytes_in, bytes_out);
|
||||
}
|
||||
return tnet_transport_get_bytes_count(self->transport, bytes_in, bytes_out);
|
||||
}
|
||||
|
||||
int trtp_manager_set_app_bandwidth_max(trtp_manager_t* self, int32_t bw_upload_kbps, int32_t bw_download_kbps)
|
||||
{
|
||||
if(self){
|
||||
|
@ -1660,6 +1727,7 @@ int trtp_manager_set_app_bandwidth_max(trtp_manager_t* self, int32_t bw_upload_k
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int trtp_manager_signal_pkt_loss(trtp_manager_t* self, uint32_t ssrc_media, const uint16_t* seq_nums, tsk_size_t count)
|
||||
{
|
||||
if(self && self->rtcp.session){
|
||||
|
@ -1667,6 +1735,7 @@ int trtp_manager_signal_pkt_loss(trtp_manager_t* self, uint32_t ssrc_media, cons
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int trtp_manager_signal_frame_corrupted(trtp_manager_t* self, uint32_t ssrc_media)
|
||||
{
|
||||
if(self && self->rtcp.session){
|
||||
|
@ -1713,6 +1782,7 @@ int trtp_manager_stop(trtp_manager_t* self)
|
|||
// Stop the RTCP session first (will send BYE)
|
||||
if(self->rtcp.session){
|
||||
ret = trtp_rtcp_session_stop(self->rtcp.session);
|
||||
ret = trtp_rtcp_session_set_net_transport(self->rtcp.session, tsk_null);
|
||||
}
|
||||
|
||||
// Free transport to force next call to start() to create new one with new sockets
|
||||
|
|
Loading…
Reference in New Issue