diff --git a/Makefile.am b/Makefile.am index a672871d5e..ef9a2ef712 100644 --- a/Makefile.am +++ b/Makefile.am @@ -57,6 +57,7 @@ src/switch_ivr.c \ src/switch_stun.c\ src/switch_log.c\ src/switch_xml.c\ +libs/stfu/stfu.c\ libs/libteletone/src/libteletone_detect.c\ libs/libteletone/src/libteletone_generate.c @@ -95,6 +96,7 @@ libs/libteletone/src/libteletone.h CORE_CFLAGS = `$(switch_srcdir)/libs/apr/apr-1-config --cflags --cppflags --includes` CORE_CFLAGS += `$(switch_srcdir)/libs/apr-util/apu-1-config --includes` +CORE_CFLAGS += -I$(switch_srcdir)/libs/stfu CORE_CFLAGS += -I$(switch_srcdir)/libs/sqlite CORE_CFLAGS += -I$(switch_srcdir)/libs/pcre CORE_CFLAGS += -I$(switch_srcdir)/libs/srtp/include diff --git a/conf/default_context.xml b/conf/default_context.xml index 047d2c3637..7b8b2688a5 100644 --- a/conf/default_context.xml +++ b/conf/default_context.xml @@ -53,6 +53,7 @@ + diff --git a/libs/stfu/stfu.c b/libs/stfu/stfu.c index 326fabb985..08683a99fa 100644 --- a/libs/stfu/stfu.c +++ b/libs/stfu/stfu.c @@ -163,7 +163,6 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, void *data, size_ cplen = sizeof(frame->data); } - memcpy(frame->data, data, cplen); frame->ts = ts; frame->dlen = cplen; @@ -185,7 +184,9 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) if (i->running) { should_have = i->last_ts + i->interval; - } + } else { + should_have = i->out_queue->array[0].ts; + } for(index = 0; index < i->out_queue->array_len; index++) { if (i->out_queue->array[index].was_read) { @@ -220,11 +221,12 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) i->miss_count++; - if (i->miss_count > 10) { + if (i->miss_count > 10 || i->in_queue->array_len == i->in_queue->array_size ) { i->out_queue->wr_len = i->out_queue->array_len; i->last_ts = should_have = frame->ts; return NULL; } + i->last_ts = should_have; rframe = &i->out_queue->int_frame; rframe->dlen = i->out_queue->array[i->out_queue->last_index].dlen; @@ -248,6 +250,7 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) i->last_ts = rframe->ts; rframe->was_read = 1; i->running = 1; + i->miss_count = 0; } return rframe; diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index 3cfcd8a154..224a932e9e 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -165,6 +165,14 @@ SWITCH_DECLARE(void) switch_rtp_destroy(switch_rtp_t **rtp_session); */ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_ice(switch_rtp_t *rtp_session, char *login, char *rlogin); +/*! + \brief Acvite a jitter buffer on an RTP session + \param rtp_session the rtp session + \param queue_frames the number of frames to delay + \return SWITCH_STATUS_SUCCESS +*/ +SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *rtp_session, uint32_t queue_frames); + /*! \brief Set an RTP Flag \param rtp_session the RTP session diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 8733214065..27885a061d 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -589,16 +589,18 @@ typedef enum { \brief Frame Flags
-SFF_CNG       = (1 <<  0) - Frame represents comfort noise
-SFF_RAW_RTP   = (1 <<  1) - Frame has raw rtp accessible
-SFF_RTP_HEADER = (1 << 2) - Get the rtp header from the frame header
+SFF_CNG        = (1 <<  0) - Frame represents comfort noise
+SFF_RAW_RTP    = (1 <<  1) - Frame has raw rtp accessible
+SFF_RTP_HEADER = (1 << 2)  - Get the rtp header from the frame header
+SFF_PLC        = (1 << 3)  - Frame has generated PLC data
 
*/ typedef enum { SFF_NONE = 0, SFF_CNG = (1 << 0), SFF_RAW_RTP = (1 << 1), - SFF_RTP_HEADER = (1 << 2) + SFF_RTP_HEADER = (1 << 2), + SFF_PLC = (1 << 3) } switch_frame_flag_t; diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 99076bc908..d7a3f5e18d 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -949,6 +949,23 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt) switch_channel_get_name(switch_core_session_get_channel(tech_pvt->session)), vad_in ? "in" : "", vad_out ? "out" : ""); } + if ((val = switch_channel_get_variable(channel, "jitterbuffer_msec"))) { + int len = atoi(val); + + if (len < 100 || len > 1000) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Jitterbuffer spec [%d] myst be between 100 and 1000\n", len); + } else { + int qlen; + + qlen = len / (tech_pvt->read_codec.implementation->microseconds_per_frame / 1000); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Setting Jitterbuffer to %dms (%d frames)\n", len, qlen); + switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen); + } + } + + + if (tech_pvt->te) { switch_rtp_set_telephony_event(tech_pvt->rtp_session, tech_pvt->te); } diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 05e5295025..12ac302411 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -42,7 +42,7 @@ #undef inline #include #include - +#include "stfu.h" #define MAX_KEY_LEN 64 #define rtp_header_len 12 #define RTP_START_PORT 16384 @@ -164,6 +164,7 @@ struct switch_rtp { uint8_t ready; uint8_t cn; switch_time_t last_time; + stfu_instance_t *jb; }; static int global_init = 0; @@ -586,6 +587,13 @@ SWITCH_DECLARE(void) switch_rtp_set_cng_pt(switch_rtp_t *rtp_session, switch_pay } +SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *rtp_session, uint32_t queue_frames) +{ + rtp_session->jb = stfu_n_init(queue_frames); + + return SWITCH_STATUS_SUCCESS; +} + SWITCH_DECLARE(switch_status_t) switch_rtp_activate_ice(switch_rtp_t *rtp_session, char *login, char *rlogin) { char ice_user[80]; @@ -632,6 +640,10 @@ SWITCH_DECLARE(void) switch_rtp_destroy(switch_rtp_t **rtp_session) switch_mutex_lock((*rtp_session)->flag_mutex); + if ((*rtp_session)->jb) { + stfu_n_destroy(&(*rtp_session)->jb); + } + if ((*rtp_session)->dtmf_data.dtmf_buffer) { switch_buffer_destroy(&(*rtp_session)->dtmf_data.dtmf_buffer); } @@ -821,6 +833,24 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ return -1; } + if (rtp_session->jb && bytes) { + stfu_frame_t *frame; + + stfu_n_eat(rtp_session->jb, ntohl(rtp_session->recv_msg.header.ts), rtp_session->recv_msg.body, bytes - rtp_header_len); + if ((frame = stfu_n_read_a_frame(rtp_session->jb))) { + memcpy(rtp_session->recv_msg.body, frame->data, frame->dlen); + if (frame->plc) { + *flags |= SFF_PLC; + } + bytes = frame->dlen + rtp_header_len; + rtp_session->recv_msg.header.ts = htonl(frame->ts); + } else { + bytes = 0; + continue; + } + + } + if (!bytes && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_BREAK)) { switch_clear_flag_locked(rtp_session, SWITCH_RTP_FLAG_BREAK); @@ -907,6 +937,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ bytes = sbytes; } + if (status == SWITCH_STATUS_BREAK || bytes == 0) { if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_DATAWAIT)) { if (rtp_session->ms_per_packet) { @@ -996,6 +1027,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ continue; } + break; }