diff --git a/libs/stfu/stfu.c b/libs/stfu/stfu.c index 7ca036fc64..f02219cd9e 100644 --- a/libs/stfu/stfu.c +++ b/libs/stfu/stfu.c @@ -69,6 +69,7 @@ struct stfu_instance { struct stfu_queue *old_queue; struct stfu_frame *last_frame; uint32_t cur_ts; + uint16_t cur_seq; uint32_t last_wr_ts; uint32_t last_rd_ts; uint32_t samples_per_packet; @@ -361,6 +362,7 @@ void stfu_n_reset(stfu_instance_t *i) stfu_n_sync(i, 1); i->cur_ts = 0; + i->cur_seq = 0; i->last_wr_ts = 0; i->last_rd_ts = 0; i->miss_count = 0; @@ -650,6 +652,7 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) for (x = 0; x < i->out_queue->array_len; x++) { if (!i->out_queue->array[x].was_read) { i->cur_ts = i->out_queue->array[x].ts; + i->cur_ts = i->out_queue->array[x].seq; break; } if (i->cur_ts == 0) { @@ -661,6 +664,7 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) } } else { i->cur_ts = i->cur_ts + i->samples_per_packet; + i->cur_seq++; } found = stfu_n_find_frame(i, i->out_queue, i->last_wr_ts, i->cur_ts, &rframe); @@ -679,12 +683,14 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) if (found) { i->cur_ts = rframe->ts; + i->cur_seq = rframe->seq; } if (i->sync_out) { if (!found) { if ((found = stfu_n_find_any_frame(i, i->out_queue, &rframe))) { i->cur_ts = rframe->ts; + i->cur_seq = rframe->seq; } if (stfu_log != null_logger && i->debug) { @@ -783,6 +789,7 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) rframe->dlen = i->plc_len; rframe->pt = i->plc_pt; rframe->ts = i->cur_ts; + rframe->seq = i->cur_seq; i->miss_count++; if (stfu_log != null_logger && i->debug) { @@ -799,6 +806,38 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) return rframe; } +int32_t stfu_n_copy_next_frame(stfu_instance_t *jb, uint32_t timestamp, uint16_t seq, uint16_t distance, stfu_frame_t *next_frame) +{ + uint32_t i = 0, j = 0; + stfu_queue_t *queues[] = { jb->out_queue, jb->in_queue, jb->old_queue}; + stfu_queue_t *queue = NULL; + stfu_frame_t *frame = NULL; + + uint32_t target_ts = 0; + + if (!next_frame) return 0; + + target_ts = timestamp + (distance - 1) * jb->samples_per_packet; + + for (i = 0; i < sizeof(queues)/sizeof(queues[0]); i++) { + queue = queues[i]; + + if (!queue) continue; + + for(j = 0; j < queue->array_size; j++) { + frame = &queue->array[j]; + /* FIXME: ts rollover happened? bad luck */ + if (frame->ts > target_ts) { + memcpy(next_frame, frame, sizeof(stfu_frame_t)); + return 1; + } + } + } + + return 0; +} + + #ifdef WIN32 #ifndef vsnprintf #define vsnprintf _vsnprintf @@ -927,7 +966,6 @@ static void default_logger(const char *file, const char *func, int line, int lev } - /* For Emacs: * Local Variables: * mode:c diff --git a/libs/stfu/stfu.h b/libs/stfu/stfu.h index e3d05bcbc1..bc3dd519ba 100644 --- a/libs/stfu/stfu.h +++ b/libs/stfu/stfu.h @@ -191,6 +191,7 @@ stfu_instance_t *stfu_n_init(uint32_t qlen, uint32_t max_qlen, uint32_t samples_ stfu_status_t stfu_n_resize(stfu_instance_t *i, uint32_t qlen); stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint16_t seq, uint32_t pt, void *data, size_t datalen, uint32_t timer_ts, int last); stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i); +int32_t stfu_n_copy_next_frame(stfu_instance_t *jb, uint32_t timestamp, uint16_t seq, uint16_t distance, stfu_frame_t *next_frame); void stfu_n_reset(stfu_instance_t *i); stfu_status_t stfu_n_sync(stfu_instance_t *i, uint32_t packets); void stfu_n_call_me(stfu_instance_t *i, stfu_n_call_me_t callback, void *udata); diff --git a/src/mod/codecs/mod_silk/Makefile b/src/mod/codecs/mod_silk/Makefile index 68ea756954..23d7811ee7 100644 --- a/src/mod/codecs/mod_silk/Makefile +++ b/src/mod/codecs/mod_silk/Makefile @@ -4,6 +4,7 @@ SILK_BUILDDIR=$(switch_builddir)/libs/silk LOCAL_CFLAGS=-I$(SILK_DIR)/src -I$(SILK_DIR)/interface SILK_LA=$(SILK_BUILDDIR)/.libs/libSKP_SILK_SDK.la LOCAL_LIBADD=$(SILK_LA) +LOCAL_OBJS=$(BASE)/libs/stfu/stfu.o include $(BASE)/build/modmake.rules $(SILK_LA): $(SILK_DIR)/.update diff --git a/src/mod/codecs/mod_silk/mod_silk.c b/src/mod/codecs/mod_silk/mod_silk.c index af32332de2..922c86d06b 100644 --- a/src/mod/codecs/mod_silk/mod_silk.c +++ b/src/mod/codecs/mod_silk/mod_silk.c @@ -31,6 +31,7 @@ */ #include "switch.h" +#include "stfu.h" #include "SKP_Silk_SDK_API.h" SWITCH_MODULE_LOAD_FUNCTION(mod_silk_load); @@ -321,23 +322,43 @@ static switch_status_t switch_silk_decode(switch_codec_t *codec, SKP_int16 ret, len; int16_t *target = decoded_data; switch_core_session_t *session = codec->session; - stfu_instance_t *jb; + stfu_instance_t *jb = NULL; + + SKP_int lost_flag = (*flag & SFF_PLC); + stfu_frame_t next_frame; + + SKP_uint8 recbuff[STFU_DATALEN]; + SKP_int16 reclen; + int32_t found_frame; + switch_bool_t did_lbrr = SWITCH_FALSE; *decoded_data_len = 0; - if (session) { - jb = switch_core_session_get_jb(session, SWITCH_MEDIA_TYPE_AUDIO); - } - - if (jb) { - /* to allow compile */ - jb = NULL; + if (lost_flag) { + if (session) { + jb = switch_core_session_get_jb(session, SWITCH_MEDIA_TYPE_AUDIO); + } + if (jb && codec && codec->cur_frame) { + for (int i = 1; i <= MAX_LBRR_DELAY; i++) { + found_frame = stfu_n_copy_next_frame(jb, codec->cur_frame->timestamp, codec->cur_frame->seq, i, &next_frame); + if (found_frame) { + SKP_Silk_SDK_search_for_LBRR(next_frame.data, next_frame.dlen, i, (SKP_uint8*) &recbuff, &reclen); + if (reclen) { + encoded_data = &recbuff; + encoded_data_len = reclen; + lost_flag = SKP_FALSE; + did_lbrr = SWITCH_TRUE; + break; + } + } + } + } } do { ret = SKP_Silk_SDK_Decode(context->dec_state, &context->decoder_object, - ((*flag & SFF_PLC)), + lost_flag, encoded_data, encoded_data_len, target, @@ -345,6 +366,8 @@ static switch_status_t switch_silk_decode(switch_codec_t *codec, if (ret){ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SKP_Silk_Decode returned %d!\n", ret); printSilkError(ret); + /* if FEC was activated, we can ignore bit errors*/ + if (! (ret == SKP_SILK_DEC_PAYLOAD_ERROR && did_lbrr)) return SWITCH_STATUS_FALSE; }