2007-05-04 17:11:27 -04:00
/*
* STFU ( S ) ort ( T ) ransportable ( F ) ramed ( U ) tterances
2009-02-04 16:17:44 -05:00
* Copyright ( c ) 2007 Anthony Minessale II < anthm @ freeswitch . org >
2007-05-04 17:11:27 -04:00
*
* Permission is hereby granted , free of charge , to any person
* obtaining a copy of this software and associated documentation
* files ( the " Software " ) , to deal in the Software without
* restriction , including without limitation the rights to use ,
* copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following
* conditions :
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY ,
* WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
* FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE .
*
2010-08-24 14:20:24 -04:00
* THOSE WHO DISAGREE MAY CERTAINLY STFU
2007-05-04 17:11:27 -04:00
*/
# include "stfu.h"
2010-12-13 19:17:11 -05:00
//#define DB_JB 1
2010-12-14 01:15:36 -05:00
# ifndef UINT_MAX
# define UINT_MAX 4294967295U
# endif
2010-12-15 10:39:42 -05:00
# ifndef UINT16_MAX
# define UINT16_MAX 65535
# endif
2007-05-04 19:53:43 -04:00
# ifdef _MSC_VER
/* warning C4706: assignment within conditional expression*/
# pragma warning(disable: 4706)
2010-12-15 11:37:57 -05:00
/* warning C4996: 'strdup': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _strdup. See online help for details. */
# pragma warning(disable:4996)
2007-05-04 19:53:43 -04:00
# endif
2010-12-15 10:39:42 -05:00
# define least1(_z) (_z ? _z : 1)
static int stfu_log_level = 7 ;
2007-05-04 17:11:27 -04:00
struct stfu_queue {
struct stfu_frame * array ;
struct stfu_frame int_frame ;
2010-12-10 18:48:19 -05:00
uint32_t real_array_size ;
2007-05-04 17:11:27 -04:00
uint32_t array_size ;
uint32_t array_len ;
uint32_t wr_len ;
2010-12-10 18:48:19 -05:00
uint32_t last_index ;
int32_t last_jitter ;
2007-05-04 17:11:27 -04:00
} ;
typedef struct stfu_queue stfu_queue_t ;
struct stfu_instance {
struct stfu_queue a_queue ;
struct stfu_queue b_queue ;
2010-12-15 10:39:42 -05:00
struct stfu_queue c_queue ;
2007-05-04 17:11:27 -04:00
struct stfu_queue * in_queue ;
struct stfu_queue * out_queue ;
2010-12-15 10:39:42 -05:00
struct stfu_queue * old_queue ;
2010-11-09 12:49:07 -05:00
struct stfu_frame * last_frame ;
2010-11-17 11:51:14 -05:00
uint32_t cur_ts ;
2010-11-09 12:49:07 -05:00
uint32_t last_wr_ts ;
uint32_t last_rd_ts ;
2010-12-10 18:48:19 -05:00
uint32_t samples_per_packet ;
uint32_t samples_per_second ;
2007-05-04 17:11:27 -04:00
uint32_t miss_count ;
2010-11-09 12:49:07 -05:00
uint32_t max_plc ;
2010-12-10 18:48:19 -05:00
uint32_t qlen ;
uint32_t max_qlen ;
uint32_t orig_qlen ;
uint32_t packet_count ;
uint32_t consecutive_good_count ;
uint32_t consecutive_bad_count ;
uint32_t period_good_count ;
uint32_t period_bad_count ;
uint32_t period_packet_in_count ;
uint32_t period_packet_out_count ;
uint32_t period_missing_count ;
2010-12-15 10:39:42 -05:00
2010-12-10 18:48:19 -05:00
uint32_t period_need_range ;
uint32_t period_need_range_avg ;
uint32_t period_clean_count ;
uint32_t session_clean_count ;
uint32_t session_missing_count ;
uint32_t session_packet_in_count ;
uint32_t session_packet_out_count ;
2010-12-15 10:39:42 -05:00
uint32_t sync_out ;
uint32_t sync_in ;
2010-12-10 18:48:19 -05:00
2010-12-21 16:35:30 -05:00
int32_t ts_offset ;
int32_t ts_drift ;
2011-02-25 13:45:31 -05:00
int32_t max_drift ;
uint32_t drift_dropped_packets ;
uint32_t drift_max_dropped ;
2010-12-10 18:48:19 -05:00
int32_t ts_diff ;
int32_t last_ts_diff ;
int32_t same_ts ;
uint32_t period_time ;
uint32_t decrement_time ;
uint32_t plc_len ;
2010-12-15 10:39:42 -05:00
uint32_t plc_pt ;
uint32_t diff ;
uint32_t diff_total ;
uint8_t ready ;
uint8_t debug ;
2010-12-10 18:48:19 -05:00
2010-12-15 10:39:42 -05:00
char * name ;
2010-12-10 18:48:19 -05:00
stfu_n_call_me_t callback ;
void * udata ;
2007-05-04 17:11:27 -04:00
} ;
2010-12-10 18:48:19 -05:00
static void stfu_n_reset_counters ( stfu_instance_t * i ) ;
2010-12-15 10:39:42 -05:00
static void null_logger ( const char * file , const char * func , int line , int level , const char * fmt , . . . ) ;
static void default_logger ( const char * file , const char * func , int line , int level , const char * fmt , . . . ) ;
stfu_logger_t stfu_log = null_logger ;
2010-12-21 16:35:30 -05:00
int32_t stfu_n_get_drift ( stfu_instance_t * i )
{
return i - > ts_drift ;
}
2010-12-15 10:39:42 -05:00
void stfu_global_set_logger ( stfu_logger_t logger )
{
if ( logger ) {
stfu_log = logger ;
} else {
stfu_log = null_logger ;
}
}
void stfu_global_set_default_logger ( int level )
{
if ( level < 0 | | level > 7 ) {
level = 7 ;
}
stfu_log = default_logger ;
stfu_log_level = level ;
}
2007-05-04 17:11:27 -04:00
2009-09-15 14:45:19 -04:00
static stfu_status_t stfu_n_resize_aqueue ( stfu_queue_t * queue , uint32_t qlen )
{
unsigned char * m ;
2010-12-10 18:48:19 -05:00
if ( qlen < = queue - > real_array_size ) {
queue - > array_size = qlen ;
if ( queue - > array_len > qlen ) {
queue - > array_len = qlen ;
}
} else {
m = realloc ( queue - > array , qlen * sizeof ( struct stfu_frame ) ) ;
assert ( m ) ;
memset ( m + queue - > array_size * sizeof ( struct stfu_frame ) , 0 , ( qlen * sizeof ( struct stfu_frame ) ) - ( queue - > array_size * sizeof ( struct stfu_frame ) ) ) ;
queue - > array = ( struct stfu_frame * ) m ;
queue - > real_array_size = queue - > array_size = qlen ;
2009-09-15 14:45:19 -04:00
}
return STFU_IT_WORKED ;
}
2007-05-04 17:11:27 -04:00
static void stfu_n_init_aqueue ( stfu_queue_t * queue , uint32_t qlen )
{
2010-12-14 01:15:36 -05:00
2007-05-04 17:11:27 -04:00
queue - > array = calloc ( qlen , sizeof ( struct stfu_frame ) ) ;
assert ( queue - > array ! = NULL ) ;
memset ( queue - > array , 0 , sizeof ( struct stfu_frame ) * qlen ) ;
2010-12-10 18:48:19 -05:00
queue - > real_array_size = queue - > array_size = qlen ;
2007-05-04 17:11:27 -04:00
queue - > int_frame . plc = 1 ;
2010-12-10 18:48:19 -05:00
memset ( queue - > int_frame . data , 255 , sizeof ( queue - > int_frame . data ) ) ;
}
void stfu_n_call_me ( stfu_instance_t * i , stfu_n_call_me_t callback , void * udata )
{
i - > callback = callback ;
i - > udata = udata ;
2007-05-04 17:11:27 -04:00
}
void stfu_n_destroy ( stfu_instance_t * * i )
{
stfu_instance_t * ii ;
if ( i & & * i ) {
ii = * i ;
* i = NULL ;
2010-12-15 10:39:42 -05:00
if ( ii - > name ) free ( ii - > name ) ;
2007-05-04 17:11:27 -04:00
free ( ii - > a_queue . array ) ;
free ( ii - > b_queue . array ) ;
2010-12-15 10:39:42 -05:00
free ( ii - > c_queue . array ) ;
2007-05-04 17:11:27 -04:00
free ( ii ) ;
}
}
2010-12-15 10:39:42 -05:00
void stfu_n_debug ( stfu_instance_t * i , const char * name )
{
if ( i - > name ) free ( i - > name ) ;
if ( name ) {
i - > name = strdup ( name ) ;
i - > debug = 1 ;
} else {
i - > name = strdup ( " none " ) ;
i - > debug = 0 ;
}
}
2009-09-15 14:45:19 -04:00
void stfu_n_report ( stfu_instance_t * i , stfu_report_t * r )
{
assert ( i ) ;
2010-12-10 18:48:19 -05:00
r - > qlen = i - > qlen ;
r - > packet_in_count = i - > period_packet_in_count ;
r - > clean_count = i - > period_clean_count ;
r - > consecutive_good_count = i - > consecutive_good_count ;
r - > consecutive_bad_count = i - > consecutive_bad_count ;
2009-09-15 14:45:19 -04:00
}
stfu_status_t stfu_n_resize ( stfu_instance_t * i , uint32_t qlen )
{
stfu_status_t s ;
2010-12-10 18:48:19 -05:00
if ( i - > qlen = = i - > max_qlen ) {
return STFU_IT_FAILED ;
}
if ( i - > max_qlen & & qlen > i - > max_qlen ) {
if ( i - > qlen < i - > max_qlen ) {
qlen = i - > max_qlen ;
} else {
return STFU_IT_FAILED ;
}
}
2009-09-15 14:45:19 -04:00
if ( ( s = stfu_n_resize_aqueue ( & i - > a_queue , qlen ) ) = = STFU_IT_WORKED ) {
s = stfu_n_resize_aqueue ( & i - > b_queue , qlen ) ;
2010-12-15 10:39:42 -05:00
s = stfu_n_resize_aqueue ( & i - > c_queue , qlen ) ;
2010-12-10 18:48:19 -05:00
i - > qlen = qlen ;
i - > max_plc = 5 ;
i - > last_frame = NULL ;
2009-09-15 14:45:19 -04:00
}
return s ;
}
2011-02-25 13:45:31 -05:00
stfu_instance_t * stfu_n_init ( uint32_t qlen , uint32_t max_qlen , uint32_t samples_per_packet , uint32_t samples_per_second , uint32_t max_drift_ms )
2007-05-04 17:11:27 -04:00
{
struct stfu_instance * i ;
i = malloc ( sizeof ( * i ) ) ;
2007-12-18 12:50:39 -05:00
if ( ! i ) {
return NULL ;
}
2007-05-04 17:11:27 -04:00
memset ( i , 0 , sizeof ( * i ) ) ;
2010-12-14 01:15:36 -05:00
2010-12-10 18:48:19 -05:00
i - > qlen = qlen ;
i - > max_qlen = max_qlen ;
i - > orig_qlen = qlen ;
i - > samples_per_packet = samples_per_packet ;
2007-05-04 17:11:27 -04:00
stfu_n_init_aqueue ( & i - > a_queue , qlen ) ;
stfu_n_init_aqueue ( & i - > b_queue , qlen ) ;
2010-12-15 10:39:42 -05:00
stfu_n_init_aqueue ( & i - > c_queue , qlen ) ;
2011-02-25 13:45:31 -05:00
i - > max_drift = ( int32_t ) ( max_drift_ms * ( samples_per_second / 1000 ) * - 1 ) ;
if ( max_drift_ms & & samples_per_packet ) {
i - > drift_max_dropped = ( samples_per_second * 2 ) / samples_per_packet ;
}
2007-05-04 17:11:27 -04:00
i - > in_queue = & i - > a_queue ;
i - > out_queue = & i - > b_queue ;
2010-12-15 10:39:42 -05:00
i - > old_queue = & i - > c_queue ;
i - > name = strdup ( " none " ) ;
2010-12-10 18:48:19 -05:00
i - > max_plc = i - > qlen / 2 ;
2010-11-09 12:49:07 -05:00
2010-12-10 18:48:19 -05:00
i - > samples_per_second = samples_per_second ? samples_per_second : 8000 ;
i - > period_time = ( ( i - > samples_per_second * 20 ) / i - > samples_per_packet ) ;
i - > decrement_time = ( ( i - > samples_per_second * 15 ) / i - > samples_per_packet ) ;
2010-11-09 12:49:07 -05:00
2007-05-04 17:11:27 -04:00
return i ;
}
2010-12-10 18:48:19 -05:00
static void stfu_n_reset_counters ( stfu_instance_t * i )
{
2010-12-15 10:39:42 -05:00
if ( stfu_log ! = null_logger & & i - > debug ) {
stfu_log ( STFU_LOG_EMERG , " %s COUNTER RESET........ \n " , i - > name ) ;
}
2010-12-10 18:48:19 -05:00
if ( i - > callback ) {
i - > callback ( i , i - > udata ) ;
}
i - > consecutive_good_count = 0 ;
i - > consecutive_bad_count = 0 ;
i - > period_good_count = 0 ;
i - > period_clean_count = 0 ;
i - > period_bad_count = 0 ;
i - > period_packet_in_count = 0 ;
i - > period_packet_out_count = 0 ;
i - > period_missing_count = 0 ;
2010-12-15 10:39:42 -05:00
2010-12-10 18:48:19 -05:00
i - > period_need_range = 0 ;
i - > period_need_range_avg = 0 ;
2010-12-15 10:39:42 -05:00
i - > diff = 0 ;
i - > diff_total = 0 ;
2010-12-10 18:48:19 -05:00
}
2007-05-04 21:31:54 -04:00
void stfu_n_reset ( stfu_instance_t * i )
{
2010-12-15 10:39:42 -05:00
if ( stfu_log ! = null_logger & & i - > debug ) {
stfu_log ( STFU_LOG_EMERG , " %s RESET \n " , i - > name ) ;
}
i - > ready = 0 ;
2007-05-04 21:31:54 -04:00
i - > in_queue = & i - > a_queue ;
i - > out_queue = & i - > b_queue ;
2010-12-15 10:39:42 -05:00
i - > old_queue = & i - > c_queue ;
2007-05-04 21:31:54 -04:00
i - > in_queue - > array_len = 0 ;
i - > out_queue - > array_len = 0 ;
i - > out_queue - > wr_len = 0 ;
2010-11-09 12:49:07 -05:00
i - > last_frame = NULL ;
2010-12-10 18:48:19 -05:00
i - > in_queue - > last_jitter = 0 ;
i - > out_queue - > last_jitter = 0 ;
2007-05-04 17:11:27 -04:00
2010-12-15 10:39:42 -05:00
stfu_n_reset_counters ( i ) ;
stfu_n_sync ( i , 1 ) ;
2010-12-10 18:48:19 -05:00
i - > cur_ts = 0 ;
i - > last_wr_ts = 0 ;
i - > last_rd_ts = 0 ;
i - > miss_count = 0 ;
i - > packet_count = 0 ;
2010-12-15 10:39:42 -05:00
2007-05-04 17:11:27 -04:00
}
2010-12-10 18:48:19 -05:00
stfu_status_t stfu_n_sync ( stfu_instance_t * i , uint32_t packets )
2007-05-04 17:11:27 -04:00
{
2010-12-10 18:48:19 -05:00
if ( packets > i - > qlen ) {
stfu_n_reset ( i ) ;
} else {
2010-12-15 10:39:42 -05:00
i - > sync_out = packets ;
i - > sync_in = packets ;
2010-12-10 18:48:19 -05:00
}
return STFU_IT_WORKED ;
2007-05-04 17:11:27 -04:00
}
2010-12-10 18:48:19 -05:00
2010-12-15 10:39:42 -05:00
static void stfu_n_swap ( stfu_instance_t * i )
{
stfu_queue_t * last_in = i - > in_queue , * last_out = i - > out_queue , * last_old = i - > old_queue ;
i - > ready = 1 ;
i - > in_queue = last_out ;
i - > out_queue = last_old ;
i - > old_queue = last_in ;
i - > in_queue - > array_len = 0 ;
i - > out_queue - > wr_len = 0 ;
i - > last_frame = NULL ;
i - > miss_count = 0 ;
i - > in_queue - > last_index = 0 ;
i - > out_queue - > last_index = 0 ;
i - > out_queue - > last_jitter = 0 ;
}
2010-12-21 16:35:30 -05:00
stfu_status_t stfu_n_add_data ( stfu_instance_t * i , uint32_t ts , uint32_t pt , void * data , size_t datalen , uint32_t timer_ts , int last )
2007-05-04 17:11:27 -04:00
{
2010-12-14 01:15:36 -05:00
uint32_t index = 0 ;
2007-05-04 17:11:27 -04:00
stfu_frame_t * frame ;
size_t cplen = 0 ;
2010-12-15 10:39:42 -05:00
int good_ts = 0 ;
2010-12-10 18:48:19 -05:00
if ( ! i - > samples_per_packet & & ts & & i - > last_rd_ts ) {
i - > ts_diff = ts - i - > last_rd_ts ;
if ( i - > last_ts_diff = = i - > ts_diff ) {
if ( + + i - > same_ts = = 5 ) {
i - > samples_per_packet = i - > ts_diff ;
2011-02-25 13:45:31 -05:00
if ( i - > max_drift & & i - > samples_per_packet ) {
i - > drift_max_dropped = ( i - > samples_per_second * 2 ) / i - > samples_per_packet ;
}
2010-12-10 18:48:19 -05:00
}
} else {
i - > same_ts = 0 ;
}
i - > last_ts_diff = i - > ts_diff ;
if ( ! i - > samples_per_packet ) {
i - > last_rd_ts = ts ;
return STFU_IT_FAILED ;
}
}
2011-02-25 13:45:31 -05:00
if ( timer_ts ) {
if ( ts & & ! i - > ts_offset ) {
i - > ts_offset = timer_ts - ts ;
}
i - > ts_drift = ts + ( i - > ts_offset - timer_ts ) ;
2010-12-21 16:35:30 -05:00
2011-03-09 16:17:23 -05:00
if ( i - > ts_offset & & i - > ts_drift > 0 ) {
i - > ts_offset = timer_ts - ts ;
i - > ts_drift = ts + ( i - > ts_offset - timer_ts ) ;
}
2011-02-25 13:45:31 -05:00
if ( i - > max_drift ) {
if ( i - > ts_drift < i - > max_drift ) {
if ( + + i - > drift_dropped_packets < i - > drift_max_dropped ) {
stfu_log ( STFU_LOG_EMERG , " %s TOO LATE !!! %u \n \n \n " , i - > name , ts ) ;
return STFU_ITS_TOO_LATE ;
}
} else {
i - > drift_dropped_packets = 0 ;
}
}
}
2010-12-21 16:35:30 -05:00
2010-12-15 10:39:42 -05:00
if ( i - > sync_in ) {
2010-12-10 18:48:19 -05:00
good_ts = 1 ;
2010-12-15 10:39:42 -05:00
i - > sync_in = 0 ;
} else {
2010-12-10 18:48:19 -05:00
2010-12-15 10:39:42 -05:00
if ( ( ts & & ts = = i - > last_rd_ts + i - > samples_per_packet ) | | ( i - > last_rd_ts > 4294900000 & & ts < 5000 ) ) {
good_ts = 1 ;
}
2010-12-10 18:48:19 -05:00
2010-12-15 10:39:42 -05:00
if ( i - > last_wr_ts ) {
if ( ( ts < = i - > last_wr_ts & & ( i - > last_wr_ts ! = UINT_MAX | | ts = = i - > last_wr_ts ) ) ) {
2010-12-17 17:19:56 -05:00
if ( stfu_log ! = null_logger & & i - > debug ) {
stfu_log ( STFU_LOG_EMERG , " %s TOO LATE !!! %u \n \n \n " , i - > name , ts ) ;
}
2010-12-15 10:39:42 -05:00
if ( i - > in_queue - > array_len < i - > in_queue - > array_size ) {
i - > in_queue - > array_len + + ;
}
return STFU_ITS_TOO_LATE ;
}
}
}
if ( good_ts ) {
2010-12-10 18:48:19 -05:00
i - > period_clean_count + + ;
i - > session_clean_count + + ;
}
i - > period_packet_in_count + + ;
i - > session_packet_in_count + + ;
2010-12-15 10:39:42 -05:00
i - > period_need_range_avg = i - > period_need_range / least1 ( i - > period_missing_count ) ;
2010-12-14 01:15:36 -05:00
2010-12-10 18:48:19 -05:00
if ( i - > period_missing_count > i - > qlen * 2 ) {
2010-12-15 10:39:42 -05:00
if ( stfu_log ! = null_logger & & i - > debug ) {
stfu_log ( STFU_LOG_EMERG , " %s resize %u %u \n " , i - > name , i - > qlen , i - > qlen + 1 ) ;
}
2010-12-10 18:48:19 -05:00
stfu_n_resize ( i , i - > qlen + 1 ) ;
stfu_n_reset_counters ( i ) ;
2010-12-14 01:15:36 -05:00
} else {
if ( i - > qlen > i - > orig_qlen & & ( i - > consecutive_good_count > i - > decrement_time | | i - > period_clean_count > i - > decrement_time ) ) {
stfu_n_resize ( i , i - > qlen - 1 ) ;
stfu_n_reset_counters ( i ) ;
stfu_n_sync ( i , i - > qlen ) ;
}
2010-12-10 18:48:19 -05:00
}
2010-12-15 10:39:42 -05:00
i - > diff = 0 ;
if ( i - > last_wr_ts ) {
if ( ts < 1000 & & i - > last_wr_ts > ( UINT_MAX - 1000 ) ) {
i - > diff = abs ( ( ( UINT_MAX - i - > last_wr_ts ) + ts ) / i - > samples_per_packet ) ;
} else if ( ts ) {
i - > diff = abs ( i - > last_wr_ts - ts ) / i - > samples_per_packet ;
}
}
i - > diff_total + = i - > diff ;
2010-12-10 18:48:19 -05:00
if ( ( i - > period_packet_in_count > i - > period_time ) ) {
2010-12-15 10:39:42 -05:00
uint32_t avg ;
avg = i - > diff_total / least1 ( i - > period_packet_in_count ) ;
2010-12-10 18:48:19 -05:00
i - > period_packet_in_count = 0 ;
if ( i - > period_missing_count = = 0 & & i - > qlen > i - > orig_qlen ) {
stfu_n_resize ( i , i - > qlen - 1 ) ;
stfu_n_sync ( i , i - > qlen ) ;
}
stfu_n_reset_counters ( i ) ;
}
2010-12-15 10:39:42 -05:00
if ( stfu_log ! = null_logger & & i - > debug ) {
2011-03-09 16:17:23 -05:00
stfu_log ( STFU_LOG_EMERG , " I: %s %u/%u i=%u/%u - g:%u/%u c:%u/%u b:%u - %u:%u - %u %d %u %u %d %d %d/%d \n " , i - > name ,
i - > qlen , i - > max_qlen , i - > period_packet_in_count , i - > period_time , i - > consecutive_good_count ,
2010-12-21 16:35:30 -05:00
i - > decrement_time , i - > period_clean_count , i - > decrement_time , i - > consecutive_bad_count ,
ts , ts / i - > samples_per_packet ,
i - > period_missing_count , i - > period_need_range_avg ,
2011-02-25 13:45:31 -05:00
i - > last_wr_ts , ts , i - > diff , i - > diff_total / least1 ( i - > period_packet_in_count ) , i - > ts_drift , i - > max_drift ) ;
2010-12-15 10:39:42 -05:00
}
2007-05-04 17:11:27 -04:00
if ( last | | i - > in_queue - > array_len = = i - > in_queue - > array_size ) {
2010-12-15 10:39:42 -05:00
stfu_n_swap ( i ) ;
2010-12-10 18:48:19 -05:00
}
2007-05-04 17:11:27 -04:00
if ( last ) {
return STFU_IM_DONE ;
}
2008-01-27 20:11:26 -05:00
2010-12-15 10:39:42 -05:00
index = i - > in_queue - > array_len + + ;
2010-12-14 01:15:36 -05:00
assert ( index < i - > in_queue - > array_size ) ;
2007-05-04 17:11:27 -04:00
frame = & i - > in_queue - > array [ index ] ;
2010-12-15 10:39:42 -05:00
if ( i - > in_queue - > array_len = = i - > in_queue - > array_size ) {
stfu_n_swap ( i ) ;
}
2007-05-04 17:11:27 -04:00
if ( ( cplen = datalen ) > sizeof ( frame - > data ) ) {
cplen = sizeof ( frame - > data ) ;
}
2010-11-09 12:49:07 -05:00
i - > last_rd_ts = ts ;
2010-12-10 18:48:19 -05:00
i - > packet_count + + ;
2010-11-09 12:49:07 -05:00
2007-05-04 17:11:27 -04:00
memcpy ( frame - > data , data , cplen ) ;
2010-12-10 18:48:19 -05:00
2010-01-07 19:45:09 -05:00
frame - > pt = pt ;
2007-05-04 17:11:27 -04:00
frame - > ts = ts ;
frame - > dlen = cplen ;
frame - > was_read = 0 ;
return STFU_IT_WORKED ;
}
2010-12-15 10:39:42 -05:00
static int stfu_n_find_any_frame ( stfu_instance_t * in , stfu_queue_t * queue , stfu_frame_t * * r_frame )
2010-12-10 18:48:19 -05:00
{
uint32_t i = 0 ;
stfu_frame_t * frame = NULL ;
assert ( r_frame ) ;
* r_frame = NULL ;
2010-12-15 10:39:42 -05:00
for ( i = 0 ; i < queue - > real_array_size ; i + + ) {
frame = & queue - > array [ i ] ;
if ( ! frame - > was_read ) {
* r_frame = frame ;
queue - > last_index = i ;
frame - > was_read = 1 ;
in - > period_packet_out_count + + ;
in - > session_packet_out_count + + ;
return 1 ;
2010-12-10 18:48:19 -05:00
}
}
return 0 ;
}
2010-12-15 10:39:42 -05:00
static int stfu_n_find_frame ( stfu_instance_t * in , stfu_queue_t * queue , uint32_t ts , stfu_frame_t * * r_frame )
2010-11-09 12:49:07 -05:00
{
uint32_t i = 0 ;
stfu_frame_t * frame = NULL ;
2010-12-15 10:39:42 -05:00
if ( r_frame ) {
* r_frame = NULL ;
}
2010-11-09 12:49:07 -05:00
2010-12-15 10:39:42 -05:00
for ( i = 0 ; i < queue - > array_size ; i + + ) {
2010-11-09 12:49:07 -05:00
frame = & queue - > array [ i ] ;
2010-12-15 10:39:42 -05:00
if ( frame - > ts = = ts ) {
if ( r_frame ) {
* r_frame = frame ;
queue - > last_index = i ;
frame - > was_read = 1 ;
in - > period_packet_out_count + + ;
in - > session_packet_out_count + + ;
}
2010-11-09 12:49:07 -05:00
return 1 ;
}
}
return 0 ;
}
2007-05-04 17:11:27 -04:00
stfu_frame_t * stfu_n_read_a_frame ( stfu_instance_t * i )
{
2010-11-09 12:49:07 -05:00
stfu_frame_t * rframe = NULL ;
2010-12-10 18:48:19 -05:00
int found = 0 ;
2010-12-15 10:39:42 -05:00
if ( ! i - > samples_per_packet ) {
return NULL ;
}
if ( ! i - > ready ) {
if ( stfu_log ! = null_logger & & i - > debug ) {
2011-02-25 13:45:31 -05:00
stfu_log ( STFU_LOG_EMERG , " %s JITTERBUFFER NOT READY: IGNORING FRAME \n " , i - > name ) ;
2010-12-15 10:39:42 -05:00
}
return NULL ;
}
2007-05-04 17:11:27 -04:00
2010-12-15 10:39:42 -05:00
if ( i - > cur_ts = = 0 & & i - > last_wr_ts < 1000 ) {
uint32_t x = 0 ;
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 ;
break ;
}
if ( i - > cur_ts = = 0 ) {
if ( stfu_log ! = null_logger & & i - > debug ) {
2011-02-25 13:45:31 -05:00
stfu_log ( STFU_LOG_EMERG , " %s JITTERBUFFER ERROR: PUNTING \n " , i - > name ) ;
2010-12-15 10:39:42 -05:00
return NULL ;
}
}
}
2010-11-17 11:51:14 -05:00
} else {
2010-12-15 10:39:42 -05:00
i - > cur_ts = i - > cur_ts + i - > samples_per_packet ;
2010-11-17 11:51:14 -05:00
}
2010-12-15 10:39:42 -05:00
found = stfu_n_find_frame ( i , i - > out_queue , i - > cur_ts , & rframe ) ;
if ( found ) {
if ( i - > out_queue - > array_len ) {
i - > out_queue - > array_len - - ;
}
2010-12-10 18:48:19 -05:00
} else {
2010-12-15 10:39:42 -05:00
found = stfu_n_find_frame ( i , i - > in_queue , i - > cur_ts , & rframe ) ;
if ( ! found ) {
found = stfu_n_find_frame ( i , i - > old_queue , i - > cur_ts , & rframe ) ;
2010-12-14 01:15:36 -05:00
}
2010-12-10 18:48:19 -05:00
}
2010-11-17 12:46:20 -05:00
2010-12-15 10:39:42 -05:00
if ( i - > sync_out ) {
if ( ! found ) {
if ( ( found = stfu_n_find_any_frame ( i , i - > out_queue , & rframe ) ) ) {
i - > cur_ts = rframe - > ts ;
}
if ( stfu_log ! = null_logger & & i - > debug ) {
stfu_log ( STFU_LOG_EMERG , " %s SYNC %u %u:%u \n " , i - > name , i - > sync_out , i - > cur_ts , i - > cur_ts / i - > samples_per_packet ) ;
}
}
i - > sync_out = 0 ;
2010-12-10 18:48:19 -05:00
}
2010-12-15 10:39:42 -05:00
if ( ! i - > cur_ts ) {
if ( stfu_log ! = null_logger & & i - > debug ) {
stfu_log ( STFU_LOG_EMERG , " %s NO TS \n " , i - > name ) ;
2010-12-10 18:48:19 -05:00
}
2010-12-15 10:39:42 -05:00
return NULL ;
2010-12-10 18:48:19 -05:00
}
if ( ! found & & i - > samples_per_packet ) {
2010-12-15 11:37:57 -05:00
uint32_t y ;
2010-12-10 18:48:19 -05:00
stfu_frame_t * frame = NULL ;
2010-12-15 10:39:42 -05:00
2010-12-10 18:48:19 -05:00
int32_t delay = i - > last_rd_ts - i - > cur_ts ;
2010-12-10 22:43:03 -05:00
uint32_t need = abs ( i - > last_rd_ts - i - > cur_ts ) / i - > samples_per_packet ;
2010-12-10 18:48:19 -05:00
i - > period_missing_count + + ;
i - > session_missing_count + + ;
i - > period_need_range + = need ;
2010-12-15 10:39:42 -05:00
if ( stfu_log ! = null_logger & & i - > debug ) {
stfu_log ( STFU_LOG_EMERG , " %s MISSING %u:%u %u %u %d %u %d \n " , i - > name ,
i - > cur_ts , i - > cur_ts / i - > samples_per_packet , i - > packet_count , i - > last_rd_ts , delay , i - > qlen , need ) ;
}
2010-12-10 18:48:19 -05:00
if ( i - > packet_count > i - > orig_qlen * 100 & & delay > 0 & & need > i - > qlen & & need < ( i - > qlen + 5 ) ) {
i - > packet_count = 0 ;
}
2010-12-15 10:39:42 -05:00
if ( stfu_log ! = null_logger & & i - > debug ) {
2010-12-16 11:10:15 -05:00
stfu_log ( STFU_LOG_EMERG , " %s " , i - > name ) ;
2010-12-15 10:39:42 -05:00
for ( y = 0 ; y < i - > out_queue - > array_size ; y + + ) {
2010-12-16 11:10:15 -05:00
if ( ( y % 5 ) = = 0 ) stfu_log ( STFU_LOG_EMERG , " \n %s " , i - > name ) ;
2010-12-15 10:39:42 -05:00
frame = & i - > out_queue - > array [ y ] ;
stfu_log ( STFU_LOG_EMERG , " %u:%u \t " , frame - > ts , frame - > ts / i - > samples_per_packet ) ;
}
2010-12-16 11:10:15 -05:00
stfu_log ( STFU_LOG_EMERG , " \n %s " , i - > name ) ;
2010-12-15 10:39:42 -05:00
2010-12-10 18:48:19 -05:00
2010-12-15 10:39:42 -05:00
for ( y = 0 ; y < i - > in_queue - > array_size ; y + + ) {
2010-12-16 11:10:15 -05:00
if ( ( y % 5 ) = = 0 ) stfu_log ( STFU_LOG_EMERG , " \n %s " , i - > name ) ;
2010-12-15 10:39:42 -05:00
frame = & i - > in_queue - > array [ y ] ;
stfu_log ( STFU_LOG_EMERG , " %u:%u \t " , frame - > ts , frame - > ts / i - > samples_per_packet ) ;
}
2010-12-16 11:10:15 -05:00
stfu_log ( STFU_LOG_EMERG , " \n %s \n \n \n " , i - > name ) ;
2010-12-10 18:48:19 -05:00
}
if ( delay < 0 ) {
stfu_n_reset ( i ) ;
return NULL ;
}
}
2010-12-15 10:39:42 -05:00
if ( stfu_log ! = null_logger & & i - > debug ) {
if ( found ) {
stfu_log ( STFU_LOG_EMERG , " %s O: %u:%u %u \n " , i - > name , rframe - > ts , rframe - > ts / i - > samples_per_packet , rframe - > plc ) ;
}
2010-12-10 18:48:19 -05:00
}
if ( found ) {
i - > consecutive_good_count + + ;
i - > period_good_count + + ;
i - > consecutive_bad_count = 0 ;
} else {
i - > consecutive_bad_count + + ;
i - > period_bad_count + + ;
i - > consecutive_good_count = 0 ;
}
if ( found ) {
2010-11-09 12:49:07 -05:00
i - > last_frame = rframe ;
2010-12-15 10:39:42 -05:00
i - > out_queue - > wr_len + + ;
i - > last_wr_ts = rframe - > ts ;
i - > miss_count = 0 ;
2010-12-10 18:48:19 -05:00
if ( rframe - > dlen ) {
i - > plc_len = rframe - > dlen ;
}
2010-12-15 10:39:42 -05:00
i - > plc_pt = rframe - > pt ;
2010-11-09 12:49:07 -05:00
} else {
2010-11-17 11:51:14 -05:00
i - > last_wr_ts = i - > cur_ts ;
2010-11-09 12:49:07 -05:00
rframe = & i - > out_queue - > int_frame ;
2010-12-10 18:48:19 -05:00
rframe - > dlen = i - > plc_len ;
2010-12-15 10:39:42 -05:00
rframe - > pt = i - > plc_pt ;
2010-11-17 11:51:14 -05:00
rframe - > ts = i - > cur_ts ;
2010-12-10 18:48:19 -05:00
i - > miss_count + + ;
2010-12-15 10:39:42 -05:00
if ( stfu_log ! = null_logger & & i - > debug ) {
stfu_log ( STFU_LOG_EMERG , " %s PLC %d %d %ld %u:%u \n " , i - > name ,
i - > miss_count , rframe - > plc , rframe - > dlen , rframe - > ts , rframe - > ts / i - > samples_per_packet ) ;
}
2010-12-10 18:48:19 -05:00
if ( i - > miss_count > i - > max_plc ) {
stfu_n_reset ( i ) ;
2010-11-09 12:49:07 -05:00
rframe = NULL ;
}
}
2007-05-04 17:11:27 -04:00
2010-12-15 10:39:42 -05:00
return rframe ;
2007-05-04 17:11:27 -04:00
}
2010-12-15 10:39:42 -05:00
# ifdef WIN32
# ifndef vsnprintf
# define vsnprintf _vsnprintf
# endif
# endif
int vasprintf ( char * * ret , const char * format , va_list ap ) ;
int stfu_vasprintf ( char * * ret , const char * fmt , va_list ap )
{
# if !defined(WIN32) && !defined(__sun)
return vasprintf ( ret , fmt , ap ) ;
# else
char * buf ;
int len ;
size_t buflen ;
va_list ap2 ;
char * tmp = NULL ;
# ifdef _MSC_VER
# if _MSC_VER >= 1500
/* hack for incorrect assumption in msvc header files for code analysis */
__analysis_assume ( tmp ) ;
# endif
ap2 = ap ;
# else
va_copy ( ap2 , ap ) ;
# endif
len = vsnprintf ( tmp , 0 , fmt , ap2 ) ;
if ( len > 0 & & ( buf = malloc ( ( buflen = ( size_t ) ( len + 1 ) ) ) ) ! = NULL ) {
len = vsnprintf ( buf , buflen , fmt , ap ) ;
* ret = buf ;
} else {
* ret = NULL ;
len = - 1 ;
}
va_end ( ap2 ) ;
return len ;
# endif
}
int stfu_snprintf ( char * buffer , size_t count , const char * fmt , . . . )
{
va_list ap ;
int ret ;
va_start ( ap , fmt ) ;
ret = vsnprintf ( buffer , count - 1 , fmt , ap ) ;
if ( ret < 0 )
buffer [ count - 1 ] = ' \0 ' ;
va_end ( ap ) ;
return ret ;
}
static void null_logger ( const char * file , const char * func , int line , int level , const char * fmt , . . . )
{
if ( file & & func & & line & & level & & fmt ) {
return ;
}
return ;
}
static const char * LEVEL_NAMES [ ] = {
" EMERG " ,
" ALERT " ,
" CRIT " ,
" ERROR " ,
" WARNING " ,
" NOTICE " ,
" INFO " ,
" DEBUG " ,
NULL
} ;
static const char * cut_path ( const char * in )
{
const char * p , * ret = in ;
char delims [ ] = " / \\ " ;
char * i ;
for ( i = delims ; * i ; i + + ) {
p = in ;
while ( ( p = strchr ( p , * i ) ) ! = 0 ) {
ret = + + p ;
}
}
return ret ;
}
static void default_logger ( const char * file , const char * func , int line , int level , const char * fmt , . . . )
{
const char * fp ;
char * data ;
va_list ap ;
int ret ;
if ( level < 0 | | level > 7 ) {
level = 7 ;
}
if ( level > stfu_log_level ) {
return ;
}
fp = cut_path ( file ) ;
va_start ( ap , fmt ) ;
ret = stfu_vasprintf ( & data , fmt , ap ) ;
if ( ret ! = - 1 ) {
fprintf ( stderr , " [%s] %s:%d %s() %s " , LEVEL_NAMES [ level ] , file , line , func , data ) ;
free ( data ) ;
}
va_end ( ap ) ;
}
2008-01-27 20:11:26 -05:00
/* For Emacs:
* Local Variables :
* mode : c
* indent - tabs - mode : nil
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
2008-07-03 15:12:26 -04:00
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 :
2008-01-27 20:11:26 -05:00
*/