diff options
Diffstat (limited to 'tinyDAV/src/t140/tdav_session_t140.c')
-rwxr-xr-x | tinyDAV/src/t140/tdav_session_t140.c | 1842 |
1 files changed, 917 insertions, 925 deletions
diff --git a/tinyDAV/src/t140/tdav_session_t140.c b/tinyDAV/src/t140/tdav_session_t140.c index cd4b17c..9c9d653 100755 --- a/tinyDAV/src/t140/tdav_session_t140.c +++ b/tinyDAV/src/t140/tdav_session_t140.c @@ -1,18 +1,18 @@ /* * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> -* +* * 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. * @@ -38,7 +38,7 @@ #include <limits.h> #define T140_BLOCKS_MAX_COUNT 20 /* number of blocks to buffer for packet loss detection and reordering */ -#define T140_BLOCK_MAX_TRANSMIT_COUNT 4 /* maximum number of times to retransmit a bloc when RED is ON */ +#define T140_BLOCK_MAX_TRANSMIT_COUNT 4 /* maximum number of times to retransmit a bloc when RED is ON */ #define T140_ZERO_WIDTH_NO_BREAK_SPACE 0xEFBBBF /* send at the begining of the T.140 session */ #define T140_BACKSPACE 0x08 @@ -59,29 +59,27 @@ #define T140_WAIT_FOR_BUFFERING 300 /* Time to wait for buffering (T.140 blocks forming) */ #define T140_WAIT_FOR_IDLE 10000 /* Time to wait before entering in IDLE state */ -static const char zero_width_no_break_space[3] = -{ - (T140_ZERO_WIDTH_NO_BREAK_SPACE >> 16) & 0xFF, - (T140_ZERO_WIDTH_NO_BREAK_SPACE >> 8) & 0xFF, - T140_ZERO_WIDTH_NO_BREAK_SPACE & 0xFF +static const char zero_width_no_break_space[3] = { + (T140_ZERO_WIDTH_NO_BREAK_SPACE >> 16) & 0xFF, + (T140_ZERO_WIDTH_NO_BREAK_SPACE >> 8) & 0xFF, + T140_ZERO_WIDTH_NO_BREAK_SPACE & 0xFF }; -typedef struct t140_block_s -{ - TSK_DECLARE_OBJECT; - - uint8_t pt; - uint16_t seq_num; - uint32_t timestamp; - uint32_t transmit_count; // number of times this block have been transmitted - // whether the block have been forwarded to the end user for UI display or sent through the RTP channel - tsk_bool_t delivered; - // whether the block contains data skipped because too late - tsk_bool_t too_late; - struct{ - uint8_t* ptr; - tsk_size_t size; - }data; +typedef struct t140_block_s { + TSK_DECLARE_OBJECT; + + uint8_t pt; + uint16_t seq_num; + uint32_t timestamp; + uint32_t transmit_count; // number of times this block have been transmitted + // whether the block have been forwarded to the end user for UI display or sent through the RTP channel + tsk_bool_t delivered; + // whether the block contains data skipped because too late + tsk_bool_t too_late; + struct { + uint8_t* ptr; + tsk_size_t size; + } data; } t140_block_t; #define T140_BLOCK(self) ((t140_block_t*)(self)) @@ -117,827 +115,820 @@ static int tdav_session_t140_send_data(tmedia_session_t* self, enum tmedia_t140_ static int tdav_session_t140_set(tmedia_session_t* self, const tmedia_param_t* param) { - int ret = 0; - tdav_session_t140_t* t140; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(tdav_session_av_set(TDAV_SESSION_AV(self), param) == tsk_true){ - return 0; - } - - t140 = (tdav_session_t140_t*)self; - - if(param->plugin_type == tmedia_ppt_consumer){ - TSK_DEBUG_ERROR("Not expected consumer(%s)", param->key); - } - else if(param->plugin_type == tmedia_ppt_producer){ - TSK_DEBUG_ERROR("Not expected producer_set(%s)", param->key); - } - else{ - TSK_DEBUG_ERROR("Not expected producer_set(%s)", param->key); - } - - return ret; + int ret = 0; + tdav_session_t140_t* t140; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(tdav_session_av_set(TDAV_SESSION_AV(self), param) == tsk_true) { + return 0; + } + + t140 = (tdav_session_t140_t*)self; + + if(param->plugin_type == tmedia_ppt_consumer) { + TSK_DEBUG_ERROR("Not expected consumer(%s)", param->key); + } + else if(param->plugin_type == tmedia_ppt_producer) { + TSK_DEBUG_ERROR("Not expected producer_set(%s)", param->key); + } + else { + TSK_DEBUG_ERROR("Not expected producer_set(%s)", param->key); + } + + return ret; } static int tdav_session_t140_get(tmedia_session_t* self, tmedia_param_t* param) { - if(!self || !param){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(tdav_session_av_get(TDAV_SESSION_AV(self), param) == tsk_true){ - return 0; - } - - TSK_DEBUG_ERROR("(%s) not expected param key for plugin_type=%d", param->key, param->plugin_type); - return -2; + if(!self || !param) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(tdav_session_av_get(TDAV_SESSION_AV(self), param) == tsk_true) { + return 0; + } + + TSK_DEBUG_ERROR("(%s) not expected param key for plugin_type=%d", param->key, param->plugin_type); + return -2; } static int tdav_session_t140_prepare(tmedia_session_t* self) { - tdav_session_av_t* base = (tdav_session_av_t*)(self); - int ret; + tdav_session_av_t* base = (tdav_session_av_t*)(self); + int ret; - if((ret = tdav_session_av_prepare(base))){ - TSK_DEBUG_ERROR("tdav_session_av_prepare(t140) failed"); - return ret; - } + if((ret = tdav_session_av_prepare(base))) { + TSK_DEBUG_ERROR("tdav_session_av_prepare(t140) failed"); + return ret; + } - if(base->rtp_manager){ - ret = trtp_manager_set_rtp_callback(base->rtp_manager, _tdav_session_t140_rtp_cb, base); - } + if(base->rtp_manager) { + ret = trtp_manager_set_rtp_callback(base->rtp_manager, _tdav_session_t140_rtp_cb, base); + } - return ret; + return ret; } static int tdav_session_t140_start(tmedia_session_t* self) { - int ret; - tdav_session_t140_t* t140; - const tmedia_codec_t* best_codec; - tdav_session_av_t* base; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - t140 = (tdav_session_t140_t*)self; - base = (tdav_session_av_t*)self; - - if(!(best_codec = tdav_session_av_get_best_neg_codec(base))){ - TSK_DEBUG_ERROR("No codec matched"); - return -2; - } - - TSK_OBJECT_SAFE_FREE(t140->encoder.codec); - t140->encoder.codec = tsk_object_ref((tsk_object_t*)best_codec); - - if((ret = tdav_session_av_start(base, best_codec))){ - TSK_DEBUG_ERROR("tdav_session_av_start(t140) failed"); - return ret; - } - - if((ret = tsk_timer_manager_start(t140->h_timer)) != 0){ - TSK_DEBUG_ERROR("Failed to start the timer"); - return ret; - } - - if(base->rtp_manager){ - int pt; - t140->encoder.payload_type = t140->encoder.codec->neg_format ? atoi(t140->encoder.codec->neg_format) : atoi(t140->encoder.codec->format); - pt = base->red.codec ? - ( base->red.codec->neg_format ? atoi(base->red.codec->neg_format) : atoi(base->red.codec->format) ) : - ( t140->encoder.payload_type ); - trtp_manager_set_payload_type(base->rtp_manager, pt); - } - - t140->decoder.last_seq_num = -1; - - t140->started = (ret == 0); - - if(t140->started){ - t140->encoder.timer_idle.timeout = T140_WAIT_FOR_IDLE; - t140->encoder.timer_buffering.timeout = T140_WAIT_FOR_BUFFERING; - t140->encoder.timer_idle.id = tsk_timer_manager_schedule(t140->h_timer, t140->encoder.timer_idle.timeout, _tdav_session_t140_timer_cb, t140); - TSK_DEBUG_INFO("T.140 - Start IDLE timer"); - } - - return ret; + int ret; + tdav_session_t140_t* t140; + const tmedia_codec_t* best_codec; + tdav_session_av_t* base; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + t140 = (tdav_session_t140_t*)self; + base = (tdav_session_av_t*)self; + + if(!(best_codec = tdav_session_av_get_best_neg_codec(base))) { + TSK_DEBUG_ERROR("No codec matched"); + return -2; + } + + TSK_OBJECT_SAFE_FREE(t140->encoder.codec); + t140->encoder.codec = tsk_object_ref((tsk_object_t*)best_codec); + + if((ret = tdav_session_av_start(base, best_codec))) { + TSK_DEBUG_ERROR("tdav_session_av_start(t140) failed"); + return ret; + } + + if((ret = tsk_timer_manager_start(t140->h_timer)) != 0) { + TSK_DEBUG_ERROR("Failed to start the timer"); + return ret; + } + + if(base->rtp_manager) { + int pt; + t140->encoder.payload_type = t140->encoder.codec->neg_format ? atoi(t140->encoder.codec->neg_format) : atoi(t140->encoder.codec->format); + pt = base->red.codec ? + ( base->red.codec->neg_format ? atoi(base->red.codec->neg_format) : atoi(base->red.codec->format) ) : + ( t140->encoder.payload_type ); + trtp_manager_set_payload_type(base->rtp_manager, pt); + } + + t140->decoder.last_seq_num = -1; + + t140->started = (ret == 0); + + if(t140->started) { + t140->encoder.timer_idle.timeout = T140_WAIT_FOR_IDLE; + t140->encoder.timer_buffering.timeout = T140_WAIT_FOR_BUFFERING; + t140->encoder.timer_idle.id = tsk_timer_manager_schedule(t140->h_timer, t140->encoder.timer_idle.timeout, _tdav_session_t140_timer_cb, t140); + TSK_DEBUG_INFO("T.140 - Start IDLE timer"); + } + + return ret; } static int tdav_session_t140_pause(tmedia_session_t* self) { - return 0; + return 0; } static int tdav_session_t140_stop(tmedia_session_t* self) { - int ret; - ret = tsk_timer_manager_stop(TDAV_SESSION_T140(self)->h_timer); - ret = tdav_session_av_stop(TDAV_SESSION_AV(self)); - TSK_OBJECT_SAFE_FREE(TDAV_SESSION_T140(self)->encoder.codec); - TSK_OBJECT_SAFE_FREE(TDAV_SESSION_T140(self)->decoder.codec); - TDAV_SESSION_T140(self)->started = tsk_false; - return ret; + int ret; + ret = tsk_timer_manager_stop(TDAV_SESSION_T140(self)->h_timer); + ret = tdav_session_av_stop(TDAV_SESSION_AV(self)); + TSK_OBJECT_SAFE_FREE(TDAV_SESSION_T140(self)->encoder.codec); + TSK_OBJECT_SAFE_FREE(TDAV_SESSION_T140(self)->decoder.codec); + TDAV_SESSION_T140(self)->started = tsk_false; + return ret; } static const tsdp_header_M_t* tdav_session_t140_get_lo(tmedia_session_t* self) { - tsk_bool_t updated = tsk_false; - const tsdp_header_M_t* ret; - tdav_session_av_t* base = TDAV_SESSION_AV(self); - - - if(!(ret = tdav_session_av_get_lo(base, &updated))){ - TSK_DEBUG_ERROR("tdav_session_av_get_lo(t140) failed"); - return tsk_null; - } - - if(updated){ - tsk_safeobj_lock(base); - TSK_OBJECT_SAFE_FREE(TDAV_SESSION_T140(self)->encoder.codec); - tsk_safeobj_unlock(base); - } - - return ret; + tsk_bool_t updated = tsk_false; + const tsdp_header_M_t* ret; + tdav_session_av_t* base = TDAV_SESSION_AV(self); + + + if(!(ret = tdav_session_av_get_lo(base, &updated))) { + TSK_DEBUG_ERROR("tdav_session_av_get_lo(t140) failed"); + return tsk_null; + } + + if(updated) { + tsk_safeobj_lock(base); + TSK_OBJECT_SAFE_FREE(TDAV_SESSION_T140(self)->encoder.codec); + tsk_safeobj_unlock(base); + } + + return ret; } static int tdav_session_t140_set_ro(tmedia_session_t* self, const tsdp_header_M_t* ro) { - int ret; - tsk_bool_t updated = tsk_false; - tdav_session_av_t* base = TDAV_SESSION_AV(self); - - if((ret = tdav_session_av_set_ro(base, ro, &updated))){ - TSK_DEBUG_ERROR("tdav_session_av_set_ro(t140) failed"); - return ret; - } - - if(updated){ - tsk_safeobj_lock(base); - TSK_OBJECT_SAFE_FREE(TDAV_SESSION_T140(self)->encoder.codec); - tsk_safeobj_unlock(base); - } - - return ret; + int ret; + tsk_bool_t updated = tsk_false; + tdav_session_av_t* base = TDAV_SESSION_AV(self); + + if((ret = tdav_session_av_set_ro(base, ro, &updated))) { + TSK_DEBUG_ERROR("tdav_session_av_set_ro(t140) failed"); + return ret; + } + + if(updated) { + tsk_safeobj_lock(base); + TSK_OBJECT_SAFE_FREE(TDAV_SESSION_T140(self)->encoder.codec); + tsk_safeobj_unlock(base); + } + + return ret; } static int tdav_session_t140_set_ondata_cbfn(tmedia_session_t* self, const void* context, tmedia_session_t140_ondata_cb_f func) { - tdav_session_t140_t* t140 = (tdav_session_t140_t*)self; - tdav_session_av_t* base = (tdav_session_av_t*)self; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - t140->cb_ondata.context = context; - t140->cb_ondata.func = func; - - if(base->consumer){ - return tdav_consumer_t140_set_ondata_cbfn(TDAV_CONSUMER_T140(base->consumer), context, func); - } - return -2; + tdav_session_t140_t* t140 = (tdav_session_t140_t*)self; + tdav_session_av_t* base = (tdav_session_av_t*)self; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + t140->cb_ondata.context = context; + t140->cb_ondata.func = func; + + if(base->consumer) { + return tdav_consumer_t140_set_ondata_cbfn(TDAV_CONSUMER_T140(base->consumer), context, func); + } + return -2; } static int tdav_session_t140_send_data(tmedia_session_t* self, enum tmedia_t140_data_type_e data_type, const void* data_ptr, unsigned data_size) { - tdav_session_av_t* base = (tdav_session_av_t*)self; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(base->producer){ - return tdav_producer_send_data(TDAV_PRODUCER_T140(base->producer), data_type, data_ptr, data_size); - } - return -2; + tdav_session_av_t* base = (tdav_session_av_t*)self; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(base->producer) { + return tdav_producer_send_data(TDAV_PRODUCER_T140(base->producer), data_type, data_ptr, data_size); + } + return -2; } // RTP/RTCP callback (From the network to the consumer) static int _tdav_session_t140_rtp_cb(const void* callback_data, const struct trtp_rtp_packet_s* packet) { - tdav_session_t140_t* t140 = (tdav_session_t140_t*)callback_data; - tdav_session_av_t* base = (tdav_session_av_t*)callback_data; - - if(!t140 || !packet || !packet->header){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(!t140->started || !base->consumer){ - TSK_DEBUG_ERROR("Not ready yet"); - return -1; - } - - if(packet->header->payload_type == base->red.payload_type){ - //static void* __red_buffer_ptr = tsk_null; // Never used - //static tsk_size_t __red_buffer_size = 0; // Never used - if(!base->red.codec){ - TSK_DEBUG_ERROR("No RED codec could be found"); - return -2; - } - // Decode RED data - /* base->red.codec->plugin->decode( - base->red.codec, - (packet->payload.data ? packet->payload.data : packet->payload.data_const), packet->payload.size, - &__red_buffer_ptr, &__red_buffer_size, - packet->header - ); - return 0; - */ - _tdav_session_t140_recv_red(t140, packet); - } - else{ - tsk_size_t out_size; - // Find the codec to use to decode the RTP payload - if(!t140->decoder.codec || t140->decoder.payload_type != packet->header->payload_type){ - tsk_istr_t format; - TSK_OBJECT_SAFE_FREE(t140->decoder.codec); - tsk_itoa(packet->header->payload_type, &format); - if(!(t140->decoder.codec = tmedia_codec_find_by_format(TMEDIA_SESSION(t140)->neg_codecs, format)) || !t140->decoder.codec->plugin || !t140->decoder.codec->plugin->decode){ - TSK_DEBUG_ERROR("%s is not a valid payload for this session", format); - return -2; - } - t140->decoder.payload_type = packet->header->payload_type; - } - - // Open codec if not already done - if(!TMEDIA_CODEC(t140->decoder.codec)->opened){ - int ret; - tsk_safeobj_lock(base); - if((ret = tmedia_codec_open(t140->decoder.codec))){ - tsk_safeobj_unlock(base); - TSK_OBJECT_SAFE_FREE(t140->decoder.codec); - TSK_DEBUG_ERROR("Failed to open [%s] codec", t140->decoder.codec->plugin->desc); - return ret; - } - tsk_safeobj_unlock(base); - } - // Decode data - out_size = t140->decoder.codec->plugin->decode(t140->decoder.codec, packet->payload.data, packet->payload.size, &t140->decoder.buffer, &t140->decoder.buffer_size, packet->header); - if(out_size){ - _tdav_session_t140_recv_raw(t140, t140->decoder.buffer, out_size); - } - } - - return 0; + tdav_session_t140_t* t140 = (tdav_session_t140_t*)callback_data; + tdav_session_av_t* base = (tdav_session_av_t*)callback_data; + + if(!t140 || !packet || !packet->header) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(!t140->started || !base->consumer) { + TSK_DEBUG_ERROR("Not ready yet"); + return -1; + } + + if(packet->header->payload_type == base->red.payload_type) { + //static void* __red_buffer_ptr = tsk_null; // Never used + //static tsk_size_t __red_buffer_size = 0; // Never used + if(!base->red.codec) { + TSK_DEBUG_ERROR("No RED codec could be found"); + return -2; + } + // Decode RED data + /* base->red.codec->plugin->decode( + base->red.codec, + (packet->payload.data ? packet->payload.data : packet->payload.data_const), packet->payload.size, + &__red_buffer_ptr, &__red_buffer_size, + packet->header + ); + return 0; + */ + _tdav_session_t140_recv_red(t140, packet); + } + else { + tsk_size_t out_size; + // Find the codec to use to decode the RTP payload + if(!t140->decoder.codec || t140->decoder.payload_type != packet->header->payload_type) { + tsk_istr_t format; + TSK_OBJECT_SAFE_FREE(t140->decoder.codec); + tsk_itoa(packet->header->payload_type, &format); + if(!(t140->decoder.codec = tmedia_codec_find_by_format(TMEDIA_SESSION(t140)->neg_codecs, format)) || !t140->decoder.codec->plugin || !t140->decoder.codec->plugin->decode) { + TSK_DEBUG_ERROR("%s is not a valid payload for this session", format); + return -2; + } + t140->decoder.payload_type = packet->header->payload_type; + } + + // Open codec if not already done + if(!TMEDIA_CODEC(t140->decoder.codec)->opened) { + int ret; + tsk_safeobj_lock(base); + if((ret = tmedia_codec_open(t140->decoder.codec))) { + tsk_safeobj_unlock(base); + TSK_OBJECT_SAFE_FREE(t140->decoder.codec); + TSK_DEBUG_ERROR("Failed to open [%s] codec", t140->decoder.codec->plugin->desc); + return ret; + } + tsk_safeobj_unlock(base); + } + // Decode data + out_size = t140->decoder.codec->plugin->decode(t140->decoder.codec, packet->payload.data, packet->payload.size, &t140->decoder.buffer, &t140->decoder.buffer_size, packet->header); + if(out_size) { + _tdav_session_t140_recv_raw(t140, t140->decoder.buffer, out_size); + } + } + + return 0; } // Producer callback (From the producer to the network). Will encode() data before sending static int _tdav_session_t140_producer_enc_cb(const void* callback_data, const void* buffer, tsk_size_t size) { - int ret = 0; - - tdav_session_t140_t* t140 = (tdav_session_t140_t*)callback_data; - tdav_session_av_t* base = (tdav_session_av_t*)callback_data; - - if(!t140){ - TSK_DEBUG_ERROR("Null session"); - return 0; - } - - if(t140->started && base->rtp_manager && base->rtp_manager->is_started && t140->encoder.codec){ - /* encode */ - //tsk_size_t out_size = 0; - - if(!base->rtp_manager->is_started){ - TSK_DEBUG_ERROR("Not started"); - return 0; - } - - // Open codec if not already done - if(!t140->encoder.codec->opened){ - tsk_safeobj_lock(base); - if((ret = tmedia_codec_open(t140->encoder.codec))){ - tsk_safeobj_unlock(base); - TSK_DEBUG_ERROR("Failed to open [%s] codec", t140->encoder.codec->plugin->desc); - return -4; - } - tsk_safeobj_unlock(base); - } - - ret = _tdav_session_t140_save_outgoing_data(t140, buffer, size); - - // start buffering timer if not already done - if(!TSK_TIMER_ID_IS_VALID(t140->encoder.timer_buffering.id)){ - TSK_DEBUG_INFO("T.140 - Schedule buffering timer"); - t140->encoder.timer_buffering.id = tsk_timer_manager_schedule(t140->h_timer, t140->encoder.timer_buffering.timeout, _tdav_session_t140_timer_cb, t140); - } - - //if((t140->encoder.codec = tsk_object_ref(t140->encoder.codec))){ /* Thread safeness (SIP reINVITE or UPDATE could update the encoder) */ - //out_size = t140->encoder.codec->plugin->encode(t140->encoder.codec, buffer, size, &t140->encoder.buffer, &t140->encoder.buffer_size); - //if(out_size){ - // trtp_manager_send_rtp(base->rtp_manager, t140->encoder.buffer, out_size, TMEDIA_CODEC_PCM_FRAME_SIZE(t140->encoder.codec), tsk_false/*Marker*/, tsk_true/*lastPacket*/); - //} - //tsk_object_unref(t140->encoder.codec); - //} - } - return ret; + int ret = 0; + + tdav_session_t140_t* t140 = (tdav_session_t140_t*)callback_data; + tdav_session_av_t* base = (tdav_session_av_t*)callback_data; + + if(!t140) { + TSK_DEBUG_ERROR("Null session"); + return 0; + } + + if(t140->started && base->rtp_manager && base->rtp_manager->is_started && t140->encoder.codec) { + /* encode */ + //tsk_size_t out_size = 0; + + if(!base->rtp_manager->is_started) { + TSK_DEBUG_ERROR("Not started"); + return 0; + } + + // Open codec if not already done + if(!t140->encoder.codec->opened) { + tsk_safeobj_lock(base); + if((ret = tmedia_codec_open(t140->encoder.codec))) { + tsk_safeobj_unlock(base); + TSK_DEBUG_ERROR("Failed to open [%s] codec", t140->encoder.codec->plugin->desc); + return -4; + } + tsk_safeobj_unlock(base); + } + + ret = _tdav_session_t140_save_outgoing_data(t140, buffer, size); + + // start buffering timer if not already done + if(!TSK_TIMER_ID_IS_VALID(t140->encoder.timer_buffering.id)) { + TSK_DEBUG_INFO("T.140 - Schedule buffering timer"); + t140->encoder.timer_buffering.id = tsk_timer_manager_schedule(t140->h_timer, t140->encoder.timer_buffering.timeout, _tdav_session_t140_timer_cb, t140); + } + + //if((t140->encoder.codec = tsk_object_ref(t140->encoder.codec))){ /* Thread safeness (SIP reINVITE or UPDATE could update the encoder) */ + //out_size = t140->encoder.codec->plugin->encode(t140->encoder.codec, buffer, size, &t140->encoder.buffer, &t140->encoder.buffer_size); + //if(out_size){ + // trtp_manager_send_rtp(base->rtp_manager, t140->encoder.buffer, out_size, TMEDIA_CODEC_PCM_FRAME_SIZE(t140->encoder.codec), tsk_false/*Marker*/, tsk_true/*lastPacket*/); + //} + //tsk_object_unref(t140->encoder.codec); + //} + } + return ret; } // save data before sending (when timer fires) static int _tdav_session_t140_save_outgoing_data(tdav_session_t140_t* self, const void* data_ptr, tsk_size_t data_size) { - tdav_session_av_t* base = (tdav_session_av_t*)self; + tdav_session_av_t* base = (tdav_session_av_t*)self; - if(!self || !data_ptr || !data_size){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if(!self || !data_ptr || !data_size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - tsk_safeobj_lock(base); + tsk_safeobj_lock(base); - T140_RESIZE_BUFFER(self->encoder.buffer, self->encoder.buffer_size, (self->encoder.buffer_idx + data_size)); - if(self->encoder.buffer && self->encoder.buffer_size){ - memcpy(&((uint8_t*)self->encoder.buffer)[self->encoder.buffer_idx], data_ptr, data_size); - self->encoder.buffer_idx += data_size; - } + T140_RESIZE_BUFFER(self->encoder.buffer, self->encoder.buffer_size, (self->encoder.buffer_idx + data_size)); + if(self->encoder.buffer && self->encoder.buffer_size) { + memcpy(&((uint8_t*)self->encoder.buffer)[self->encoder.buffer_idx], data_ptr, data_size); + self->encoder.buffer_idx += data_size; + } - tsk_safeobj_unlock(base); + tsk_safeobj_unlock(base); - return 0; + return 0; } // encapsulated data for sending static tsk_size_t _tdav_session_t140_encap_red(tdav_session_t140_t* self, void** out_data_ptr, tsk_size_t* out_data_size, tsk_bool_t *last_data) { - tdav_session_av_t* base = (tdav_session_av_t*)self; - t140_block_t* block, *block_curr = tsk_null; - t140_block_t* red_blocks[T140_BLOCK_MAX_TRANSMIT_COUNT] = { tsk_null }; - tsk_size_t red_blocks_idx, idx, red_blocks_size, red_blocks_hdrs_size; - tsk_list_item_t* item; - uint16_t rtp_seq_num; - uint32_t* pout_data_ptr32; - uint8_t* pout_data_ptr8; - static const uint32_t max_transmit_count = T140_BLOCK_MAX_TRANSMIT_COUNT; - - if(!self || !base->rtp_manager || !out_data_ptr || !out_data_size || !last_data){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - - *last_data = tsk_false; - - tsk_safeobj_lock(base); - tsk_list_lock(self->encoder.blocks); - - // cancel IDLE timer - if(TSK_TIMER_ID_IS_VALID(self->encoder.timer_idle.id)){ - tsk_timer_manager_cancel(self->h_timer, self->encoder.timer_idle.id); - self->encoder.timer_idle.id = TSK_INVALID_TIMER_ID; - TSK_DEBUG_INFO("T.140 - Cancel IDLE timer"); - } - - rtp_seq_num = base->rtp_manager->rtp.seq_num; - - if(self->encoder.buffer && self->encoder.buffer_idx){ - block_curr = _tdav_session_t140_block_create(self->encoder.payload_type, rtp_seq_num, 0, tsk_false, self->encoder.buffer, self->encoder.buffer_idx); - self->encoder.buffer_idx = 0; - } - - // build RED blocks - red_blocks_idx = 0; - tsk_list_foreach(item, self->encoder.blocks){ - if(!(block = item->data) || (block->transmit_count + 1) >= T140_BLOCK_MAX_TRANSMIT_COUNT){ - continue; - } - - if(block->seq_num <= rtp_seq_num && (idx = (rtp_seq_num - block->seq_num)) < T140_BLOCK_MAX_TRANSMIT_COUNT){ - ++block->transmit_count; // increment transmission count - red_blocks[(T140_BLOCK_MAX_TRANSMIT_COUNT - idx - 1)] = block; // backwards counting - ++red_blocks_idx; - } - - if((red_blocks_idx + 1) >= T140_BLOCK_MAX_TRANSMIT_COUNT){ - break; - } - } - - // compute RED blocks size - red_blocks_hdrs_size = ((T140_BLOCK_MAX_TRANSMIT_COUNT - 1) << 2) + 1; - red_blocks_size = red_blocks_hdrs_size; - for(idx = 0; idx < T140_BLOCK_MAX_TRANSMIT_COUNT; ++idx){ - if(red_blocks[idx] && red_blocks[idx]->data.ptr && red_blocks[idx]->data.size){ - red_blocks_size += red_blocks[idx]->data.size; - } - } - if(block_curr && block_curr->data.ptr && block_curr->data.size){ - red_blocks_size += block_curr->data.size; - } - - // resize output buffer - T140_RESIZE_BUFFER(*out_data_ptr, *out_data_size, red_blocks_size); - if(!*out_data_ptr) { - red_blocks_size = 0; - goto bail; - } - - // compute RED headers - pout_data_ptr32 = (uint32_t*)*out_data_ptr; - for(idx = 0; idx < T140_BLOCK_MAX_TRANSMIT_COUNT; ++idx){ - if((idx + 1) == T140_BLOCK_MAX_TRANSMIT_COUNT){ // last header ? - *((uint8_t*)&pout_data_ptr32[idx]) = (self->encoder.payload_type & 0x7F); // F=0 | PT - } - else{ - pout_data_ptr32[idx] = tnet_htonl( - ( (0x80 | (self->encoder.payload_type & 0x7F)) << 24 ) | // F=1 | PT - ( 0x0000 << 8 ) | // imestamp offset - ( red_blocks[idx] ? (red_blocks[idx]->data.size & 0xFF) : 0x00 ) // block length - ); - } - } - - // compute RED data - pout_data_ptr8 = &((uint8_t*)*out_data_ptr)[red_blocks_hdrs_size]; - for(idx = 0; idx < T140_BLOCK_MAX_TRANSMIT_COUNT; ++idx){ - if(red_blocks[idx] && red_blocks[idx]->data.ptr && red_blocks[idx]->data.size){ - memcpy(pout_data_ptr8, red_blocks[idx]->data.ptr, red_blocks[idx]->data.size); - pout_data_ptr8 += red_blocks[idx]->data.size; - } - } - if(block_curr && block_curr->data.ptr && block_curr->data.size){ - memcpy(pout_data_ptr8, block_curr->data.ptr, block_curr->data.size); - pout_data_ptr8 += block_curr->data.size; - } - - if((*last_data = (red_blocks_hdrs_size == red_blocks_size))){ - // no data available -> clear items, send empty block, schedule idle timer, cancel buffering timer - if(TSK_TIMER_ID_IS_VALID(self->encoder.timer_buffering.id)){ - tsk_timer_manager_cancel(self->h_timer, self->encoder.timer_buffering.id); - self->encoder.timer_buffering.id = TSK_INVALID_TIMER_ID; - TSK_DEBUG_INFO("T.140 - Cancel buffering timer"); - } - self->encoder.timer_idle.id = tsk_timer_manager_schedule(self->h_timer, self->encoder.timer_idle.timeout, _tdav_session_t140_timer_cb, self); - TSK_DEBUG_INFO("T.140 - Schedule IDLE timer"); - tsk_list_clear_items(self->encoder.blocks); - } - else{ - // clean up all blocks retransmitted more than max times - while(tsk_list_remove_item_by_pred(self->encoder.blocks, _tdav_session_t140_pred_block_with_transmit_count_more_than_or_equal, &max_transmit_count)) ; - } + tdav_session_av_t* base = (tdav_session_av_t*)self; + t140_block_t* block, *block_curr = tsk_null; + t140_block_t* red_blocks[T140_BLOCK_MAX_TRANSMIT_COUNT] = { tsk_null }; + tsk_size_t red_blocks_idx, idx, red_blocks_size, red_blocks_hdrs_size; + tsk_list_item_t* item; + uint16_t rtp_seq_num; + uint32_t* pout_data_ptr32; + uint8_t* pout_data_ptr8; + static const uint32_t max_transmit_count = T140_BLOCK_MAX_TRANSMIT_COUNT; + + if(!self || !base->rtp_manager || !out_data_ptr || !out_data_size || !last_data) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + *last_data = tsk_false; + + tsk_safeobj_lock(base); + tsk_list_lock(self->encoder.blocks); + + // cancel IDLE timer + if(TSK_TIMER_ID_IS_VALID(self->encoder.timer_idle.id)) { + tsk_timer_manager_cancel(self->h_timer, self->encoder.timer_idle.id); + self->encoder.timer_idle.id = TSK_INVALID_TIMER_ID; + TSK_DEBUG_INFO("T.140 - Cancel IDLE timer"); + } + + rtp_seq_num = base->rtp_manager->rtp.seq_num; + + if(self->encoder.buffer && self->encoder.buffer_idx) { + block_curr = _tdav_session_t140_block_create(self->encoder.payload_type, rtp_seq_num, 0, tsk_false, self->encoder.buffer, self->encoder.buffer_idx); + self->encoder.buffer_idx = 0; + } + + // build RED blocks + red_blocks_idx = 0; + tsk_list_foreach(item, self->encoder.blocks) { + if(!(block = item->data) || (block->transmit_count + 1) >= T140_BLOCK_MAX_TRANSMIT_COUNT) { + continue; + } + + if(block->seq_num <= rtp_seq_num && (idx = (rtp_seq_num - block->seq_num)) < T140_BLOCK_MAX_TRANSMIT_COUNT) { + ++block->transmit_count; // increment transmission count + red_blocks[(T140_BLOCK_MAX_TRANSMIT_COUNT - idx - 1)] = block; // backwards counting + ++red_blocks_idx; + } + + if((red_blocks_idx + 1) >= T140_BLOCK_MAX_TRANSMIT_COUNT) { + break; + } + } + + // compute RED blocks size + red_blocks_hdrs_size = ((T140_BLOCK_MAX_TRANSMIT_COUNT - 1) << 2) + 1; + red_blocks_size = red_blocks_hdrs_size; + for(idx = 0; idx < T140_BLOCK_MAX_TRANSMIT_COUNT; ++idx) { + if(red_blocks[idx] && red_blocks[idx]->data.ptr && red_blocks[idx]->data.size) { + red_blocks_size += red_blocks[idx]->data.size; + } + } + if(block_curr && block_curr->data.ptr && block_curr->data.size) { + red_blocks_size += block_curr->data.size; + } + + // resize output buffer + T140_RESIZE_BUFFER(*out_data_ptr, *out_data_size, red_blocks_size); + if(!*out_data_ptr) { + red_blocks_size = 0; + goto bail; + } + + // compute RED headers + pout_data_ptr32 = (uint32_t*)*out_data_ptr; + for(idx = 0; idx < T140_BLOCK_MAX_TRANSMIT_COUNT; ++idx) { + if((idx + 1) == T140_BLOCK_MAX_TRANSMIT_COUNT) { // last header ? + *((uint8_t*)&pout_data_ptr32[idx]) = (self->encoder.payload_type & 0x7F); // F=0 | PT + } + else { + pout_data_ptr32[idx] = tnet_htonl( + ( (0x80 | (self->encoder.payload_type & 0x7F)) << 24 ) | // F=1 | PT + ( 0x0000 << 8 ) | // imestamp offset + ( red_blocks[idx] ? (red_blocks[idx]->data.size & 0xFF) : 0x00 ) // block length + ); + } + } + + // compute RED data + pout_data_ptr8 = &((uint8_t*)*out_data_ptr)[red_blocks_hdrs_size]; + for(idx = 0; idx < T140_BLOCK_MAX_TRANSMIT_COUNT; ++idx) { + if(red_blocks[idx] && red_blocks[idx]->data.ptr && red_blocks[idx]->data.size) { + memcpy(pout_data_ptr8, red_blocks[idx]->data.ptr, red_blocks[idx]->data.size); + pout_data_ptr8 += red_blocks[idx]->data.size; + } + } + if(block_curr && block_curr->data.ptr && block_curr->data.size) { + memcpy(pout_data_ptr8, block_curr->data.ptr, block_curr->data.size); + pout_data_ptr8 += block_curr->data.size; + } + + if((*last_data = (red_blocks_hdrs_size == red_blocks_size))) { + // no data available -> clear items, send empty block, schedule idle timer, cancel buffering timer + if(TSK_TIMER_ID_IS_VALID(self->encoder.timer_buffering.id)) { + tsk_timer_manager_cancel(self->h_timer, self->encoder.timer_buffering.id); + self->encoder.timer_buffering.id = TSK_INVALID_TIMER_ID; + TSK_DEBUG_INFO("T.140 - Cancel buffering timer"); + } + self->encoder.timer_idle.id = tsk_timer_manager_schedule(self->h_timer, self->encoder.timer_idle.timeout, _tdav_session_t140_timer_cb, self); + TSK_DEBUG_INFO("T.140 - Schedule IDLE timer"); + tsk_list_clear_items(self->encoder.blocks); + } + else { + // clean up all blocks retransmitted more than max times + while(tsk_list_remove_item_by_pred(self->encoder.blocks, _tdav_session_t140_pred_block_with_transmit_count_more_than_or_equal, &max_transmit_count)) ; + } bail: - if(block_curr){ - _tdav_session_t140_blocks_add(self->encoder.blocks, &self->encoder.blocks_count, &block_curr, INT_MAX); - TSK_OBJECT_SAFE_FREE(block_curr); - } - tsk_list_unlock(self->encoder.blocks); - tsk_safeobj_unlock(base); - - return red_blocks_size; + if(block_curr) { + _tdav_session_t140_blocks_add(self->encoder.blocks, &self->encoder.blocks_count, &block_curr, INT_MAX); + TSK_OBJECT_SAFE_FREE(block_curr); + } + tsk_list_unlock(self->encoder.blocks); + tsk_safeobj_unlock(base); + + return red_blocks_size; } // decode data from RTP channel static int _tdav_session_t140_recv_red(tdav_session_t140_t* self, const struct trtp_rtp_packet_s* packet) { - const uint8_t* pdata; - const uint8_t* red_hdr; - tsk_size_t red_hdrs_count, i, in_size; - tsk_bool_t last, block_add; - uint8_t F, pt; - int32_t pkt_loss_start = -1, pkt_loss_count, seq_num; - uint16_t timestamp_offset, block_length; - - if(!self || !packet || !packet->header || !(packet->payload.data || packet->payload.data_const) || (packet->payload.size < TDAV_CODEC_RED_MIN_PKT_SIZE)){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - pdata = red_hdr = packet->payload.data ? packet->payload.data : packet->payload.data_const; - in_size = packet->payload.size; - - if((F = (pdata[0] & 0x80)) == 0){ - i = 1; - red_hdrs_count = 1; - } - else{ - for(i = 0, red_hdrs_count = 0; i < in_size; i+= 4, ++red_hdrs_count){ - if((F = (pdata[i] & 0x80)) == 0){ ++i; ++red_hdrs_count; break; } - } - } - - if(i == in_size){ - TSK_DEBUG_INFO("T.140 - Empty block"); - return 0; - } - - pdata += i; - in_size -= i; - if(self->decoder.last_seq_num != -1 && (self->decoder.last_seq_num + 1) != packet->header->seq_num){ - pkt_loss_start = (self->decoder.last_seq_num + 1); - pkt_loss_count = (packet->header->seq_num - pkt_loss_start); - TSK_DEBUG_INFO("T.140 - Packet loss[curr=%d, loss_start=%d, loss_count=%d]", packet->header->seq_num, pkt_loss_start, pkt_loss_count); - } - - for(i = 0, block_add = tsk_false; i < red_hdrs_count; ++i, block_add = tsk_false){ - last = (i == (red_hdrs_count - 1)); - F = (red_hdr[0] & 0x80); - pt = (red_hdr[0] & 0x7F); - if(last || !F){ - /* - 0 1 2 3 4 5 6 7 + const uint8_t* pdata; + const uint8_t* red_hdr; + tsk_size_t red_hdrs_count, i, in_size; + tsk_bool_t last, block_add; + uint8_t F, pt; + int32_t pkt_loss_start = -1, pkt_loss_count, seq_num; + uint16_t timestamp_offset, block_length; + + if(!self || !packet || !packet->header || !(packet->payload.data || packet->payload.data_const) || (packet->payload.size < TDAV_CODEC_RED_MIN_PKT_SIZE)) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + pdata = red_hdr = packet->payload.data ? packet->payload.data : packet->payload.data_const; + in_size = packet->payload.size; + + if((F = (pdata[0] & 0x80)) == 0) { + i = 1; + red_hdrs_count = 1; + } + else { + for(i = 0, red_hdrs_count = 0; i < in_size; i+= 4, ++red_hdrs_count) { + if((F = (pdata[i] & 0x80)) == 0) { + ++i; + ++red_hdrs_count; + break; + } + } + } + + if(i == in_size) { + TSK_DEBUG_INFO("T.140 - Empty block"); + return 0; + } + + pdata += i; + in_size -= i; + if(self->decoder.last_seq_num != -1 && (self->decoder.last_seq_num + 1) != packet->header->seq_num) { + pkt_loss_start = (self->decoder.last_seq_num + 1); + pkt_loss_count = (packet->header->seq_num - pkt_loss_start); + TSK_DEBUG_INFO("T.140 - Packet loss[curr=%d, loss_start=%d, loss_count=%d]", packet->header->seq_num, pkt_loss_start, pkt_loss_count); + } + + for(i = 0, block_add = tsk_false; i < red_hdrs_count; ++i, block_add = tsk_false) { + last = (i == (red_hdrs_count - 1)); + F = (red_hdr[0] & 0x80); + pt = (red_hdr[0] & 0x7F); + if(last || !F) { + /* + 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ |0| Block PT | +-+-+-+-+-+-+-+-+ - */ - block_length = (uint16_t)in_size; - seq_num = packet->header->seq_num; - timestamp_offset = 0; - block_add = tsk_true; - } - else{ - /* - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |1| block PT=7 | timestamp offset | block length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - seq_num = (int32_t)(packet->header->seq_num - (red_hdrs_count - 1 - i)); // inferred by counting backwards - block_add = (pkt_loss_start != -1 && (seq_num <= pkt_loss_start && pkt_loss_start >= seq_num)); - timestamp_offset = ((red_hdr[1] << 8) | red_hdr[2]) >> 2; - block_length = ((red_hdr[2] & 0x03) << 8) | red_hdr[3]; - /* block_add &= (block_length > 0); */ // take empty block to avoid scheduling pkt loss timer - if(pkt_loss_start != -1){ - TSK_DEBUG_INFO("retransmit seq_num=%d, takken=%d", seq_num, block_add); - } - if(block_length > in_size){ - TSK_DEBUG_ERROR("Invalid 'block length'"); - break; - } - red_hdr += 4; - } - - if(block_add && !_tdav_session_t140_blocks_has_seqnum(self->decoder.blocks, seq_num)){ - t140_block_t* block = _tdav_session_t140_block_create( - pt, - seq_num, - (packet->header->timestamp + timestamp_offset), - tsk_false, - pdata, - block_length); - _tdav_session_t140_blocks_add(self->decoder.blocks, &self->decoder.blocks_count, &block, T140_BLOCKS_MAX_COUNT); - TSK_OBJECT_SAFE_FREE(block); - } - - - pdata += block_length; - in_size -= block_length; - } - - self->decoder.last_seq_num = packet->header->seq_num; - - return _tdav_session_t140_decode_and_deliver_blocks(self, tsk_false); + */ + block_length = (uint16_t)in_size; + seq_num = packet->header->seq_num; + timestamp_offset = 0; + block_add = tsk_true; + } + else { + /* + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |1| block PT=7 | timestamp offset | block length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + seq_num = (int32_t)(packet->header->seq_num - (red_hdrs_count - 1 - i)); // inferred by counting backwards + block_add = (pkt_loss_start != -1 && (seq_num <= pkt_loss_start && pkt_loss_start >= seq_num)); + timestamp_offset = ((red_hdr[1] << 8) | red_hdr[2]) >> 2; + block_length = ((red_hdr[2] & 0x03) << 8) | red_hdr[3]; + /* block_add &= (block_length > 0); */ // take empty block to avoid scheduling pkt loss timer + if(pkt_loss_start != -1) { + TSK_DEBUG_INFO("retransmit seq_num=%d, takken=%d", seq_num, block_add); + } + if(block_length > in_size) { + TSK_DEBUG_ERROR("Invalid 'block length'"); + break; + } + red_hdr += 4; + } + + if(block_add && !_tdav_session_t140_blocks_has_seqnum(self->decoder.blocks, seq_num)) { + t140_block_t* block = _tdav_session_t140_block_create( + pt, + seq_num, + (packet->header->timestamp + timestamp_offset), + tsk_false, + pdata, + block_length); + _tdav_session_t140_blocks_add(self->decoder.blocks, &self->decoder.blocks_count, &block, T140_BLOCKS_MAX_COUNT); + TSK_OBJECT_SAFE_FREE(block); + } + + + pdata += block_length; + in_size -= block_length; + } + + self->decoder.last_seq_num = packet->header->seq_num; + + return _tdav_session_t140_decode_and_deliver_blocks(self, tsk_false); } static int _tdav_session_t140_recv_raw(tdav_session_t140_t* self, const void* data_ptr, tsk_size_t data_size) { - tsk_size_t i, j, cmd_extra_len, utf8_start, utf8_end; - tsk_bool_t is_cmd; - enum tmedia_t140_data_type_e cmd_type; - const uint8_t* _data_ptr = (const uint8_t*)data_ptr; - - if(!self || !data_ptr || !data_size){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - for(i = 0, j = 0, is_cmd = tsk_false, cmd_extra_len = 0; i < data_size; ++i, is_cmd = tsk_false, cmd_extra_len = 0){ - switch(_data_ptr[i]){ - case T140_BACKSPACE: - { - TSK_DEBUG_INFO("T.140 - BACKSPACE"); - is_cmd = tsk_true; - cmd_type = tmedia_t140_data_type_backspace; - break; - } - case T140_ESC: - { - TSK_DEBUG_INFO("T.140 - ESC"); - is_cmd = tsk_true; - cmd_type = tmedia_t140_data_type_esc; - break; - } - case T140_LF: - { - TSK_DEBUG_INFO("T.140 - LF"); - is_cmd = tsk_true; - cmd_type = tmedia_t140_data_type_lf; - break; - } - case T140_CR: - { - if((i + 1) < data_size && _data_ptr[i + 1] == T140_LF){ - // CR_LF - TSK_DEBUG_INFO("T.140 - CRLF"); - cmd_extra_len = 1; - is_cmd = tsk_true; - cmd_type = tmedia_t140_data_type_cr_lf; - } - else{ - // CR - TSK_DEBUG_INFO("T.140 - CR"); - is_cmd = tsk_true; - cmd_type = tmedia_t140_data_type_cr; - } - break; - } - case T140_BELL: - { - TSK_DEBUG_INFO("T.140 - BELL"); - is_cmd = tsk_true; - cmd_type = tmedia_t140_data_type_bell; - break; - } - case T140_SOS: - { - TSK_DEBUG_INFO("T.140 - SOS"); - is_cmd = tsk_true; - cmd_type = tmedia_t140_data_type_sos; - break; - } - case T140_STRING_TERM: - { - TSK_DEBUG_INFO("T.140 - ST"); - is_cmd = tsk_true; - cmd_type = tmedia_t140_data_type_string_term; - break; - } - case (T140_LOSS_CHAR_CHAR >> 8): - { - if((i + 1) < data_size && _data_ptr[i + 1] == (T140_LOSS_CHAR_CHAR & 0xFF)){ - TSK_DEBUG_INFO("T.140 - LOSS_CHAR_CHAR"); - cmd_extra_len = 1; - is_cmd = tsk_true; - cmd_type = tmedia_t140_data_type_loss_char_char; - } - break; - } - case T140_GRAPHIC_START: - { - TSK_DEBUG_INFO("T.140 - GRAPHIC_START"); - is_cmd = tsk_true; - cmd_type = tmedia_t140_data_type_graphic_start; - break; - } - case T140_GRAPHIC_END: - { - TSK_DEBUG_INFO("T.140 - GRAPHIC_END"); - is_cmd = tsk_true; - cmd_type = tmedia_t140_data_type_graphic_end; - break; - } - // case (T140_ZERO_WIDTH_NO_BREAK_SPACE >> 16): - // case (T140_LOSS_UTF8 >> 16): - case 0xEF: - { - if((i + 2) < data_size && _data_ptr[i + 1] == ((T140_ZERO_WIDTH_NO_BREAK_SPACE >> 8) & 0xFF) && _data_ptr[i + 2] == (T140_ZERO_WIDTH_NO_BREAK_SPACE & 0xFF)){ - TSK_DEBUG_INFO("T.140 - ZERO_WIDTH_NO_BREAK_SPACE"); - cmd_extra_len = 2; - is_cmd = tsk_true; - cmd_type = tmedia_t140_data_type_zero_width_no_break_space; - } - else if((i + 2) < data_size && _data_ptr[i + 1] == ((T140_LOSS_UTF8 >> 8) & 0xFF) && _data_ptr[i + 2] == (T140_LOSS_UTF8 & 0xFF)){ - TSK_DEBUG_INFO("T.140 - LOSS_UTF8"); - cmd_extra_len = 2; - is_cmd = tsk_true; - cmd_type = tmedia_t140_data_type_loss_utf8; - } - break; - } - }//switch - - if(is_cmd || ((i + 1) >= data_size)){ - utf8_start = j; - utf8_end = utf8_start + ( (j < i || (j == i && !is_cmd)) ? (i - j + 1) : 0 ); - if(utf8_start < utf8_end){ // there is utf8 data to deliver - _tdav_session_t140_consume_data(self, tmedia_t140_data_type_utf8, &_data_ptr[utf8_start], (utf8_end - utf8_start)); - } - if(is_cmd){ // there is cmd data to deliver - i += cmd_extra_len; - _tdav_session_t140_consume_data(self, cmd_type, tsk_null, 0); - } - j = i; - } - }// for - - return 0; + tsk_size_t i, j, cmd_extra_len, utf8_start, utf8_end; + tsk_bool_t is_cmd; + enum tmedia_t140_data_type_e cmd_type; + const uint8_t* _data_ptr = (const uint8_t*)data_ptr; + + if(!self || !data_ptr || !data_size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + for(i = 0, j = 0, is_cmd = tsk_false, cmd_extra_len = 0; i < data_size; ++i, is_cmd = tsk_false, cmd_extra_len = 0) { + switch(_data_ptr[i]) { + case T140_BACKSPACE: { + TSK_DEBUG_INFO("T.140 - BACKSPACE"); + is_cmd = tsk_true; + cmd_type = tmedia_t140_data_type_backspace; + break; + } + case T140_ESC: { + TSK_DEBUG_INFO("T.140 - ESC"); + is_cmd = tsk_true; + cmd_type = tmedia_t140_data_type_esc; + break; + } + case T140_LF: { + TSK_DEBUG_INFO("T.140 - LF"); + is_cmd = tsk_true; + cmd_type = tmedia_t140_data_type_lf; + break; + } + case T140_CR: { + if((i + 1) < data_size && _data_ptr[i + 1] == T140_LF) { + // CR_LF + TSK_DEBUG_INFO("T.140 - CRLF"); + cmd_extra_len = 1; + is_cmd = tsk_true; + cmd_type = tmedia_t140_data_type_cr_lf; + } + else { + // CR + TSK_DEBUG_INFO("T.140 - CR"); + is_cmd = tsk_true; + cmd_type = tmedia_t140_data_type_cr; + } + break; + } + case T140_BELL: { + TSK_DEBUG_INFO("T.140 - BELL"); + is_cmd = tsk_true; + cmd_type = tmedia_t140_data_type_bell; + break; + } + case T140_SOS: { + TSK_DEBUG_INFO("T.140 - SOS"); + is_cmd = tsk_true; + cmd_type = tmedia_t140_data_type_sos; + break; + } + case T140_STRING_TERM: { + TSK_DEBUG_INFO("T.140 - ST"); + is_cmd = tsk_true; + cmd_type = tmedia_t140_data_type_string_term; + break; + } + case (T140_LOSS_CHAR_CHAR >> 8): { + if((i + 1) < data_size && _data_ptr[i + 1] == (T140_LOSS_CHAR_CHAR & 0xFF)) { + TSK_DEBUG_INFO("T.140 - LOSS_CHAR_CHAR"); + cmd_extra_len = 1; + is_cmd = tsk_true; + cmd_type = tmedia_t140_data_type_loss_char_char; + } + break; + } + case T140_GRAPHIC_START: { + TSK_DEBUG_INFO("T.140 - GRAPHIC_START"); + is_cmd = tsk_true; + cmd_type = tmedia_t140_data_type_graphic_start; + break; + } + case T140_GRAPHIC_END: { + TSK_DEBUG_INFO("T.140 - GRAPHIC_END"); + is_cmd = tsk_true; + cmd_type = tmedia_t140_data_type_graphic_end; + break; + } + // case (T140_ZERO_WIDTH_NO_BREAK_SPACE >> 16): + // case (T140_LOSS_UTF8 >> 16): + case 0xEF: { + if((i + 2) < data_size && _data_ptr[i + 1] == ((T140_ZERO_WIDTH_NO_BREAK_SPACE >> 8) & 0xFF) && _data_ptr[i + 2] == (T140_ZERO_WIDTH_NO_BREAK_SPACE & 0xFF)) { + TSK_DEBUG_INFO("T.140 - ZERO_WIDTH_NO_BREAK_SPACE"); + cmd_extra_len = 2; + is_cmd = tsk_true; + cmd_type = tmedia_t140_data_type_zero_width_no_break_space; + } + else if((i + 2) < data_size && _data_ptr[i + 1] == ((T140_LOSS_UTF8 >> 8) & 0xFF) && _data_ptr[i + 2] == (T140_LOSS_UTF8 & 0xFF)) { + TSK_DEBUG_INFO("T.140 - LOSS_UTF8"); + cmd_extra_len = 2; + is_cmd = tsk_true; + cmd_type = tmedia_t140_data_type_loss_utf8; + } + break; + } + }//switch + + if(is_cmd || ((i + 1) >= data_size)) { + utf8_start = j; + utf8_end = utf8_start + ( (j < i || (j == i && !is_cmd)) ? (i - j + 1) : 0 ); + if(utf8_start < utf8_end) { // there is utf8 data to deliver + _tdav_session_t140_consume_data(self, tmedia_t140_data_type_utf8, &_data_ptr[utf8_start], (utf8_end - utf8_start)); + } + if(is_cmd) { // there is cmd data to deliver + i += cmd_extra_len; + _tdav_session_t140_consume_data(self, cmd_type, tsk_null, 0); + } + j = i; + } + }// for + + return 0; } static int _tdav_session_t140_decode_and_deliver_blocks(tdav_session_t140_t* self, tsk_bool_t called_from_timer) { - tdav_session_av_t* base = (tdav_session_av_t*)self; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - tsk_safeobj_lock(base); - tsk_list_lock(self->decoder.blocks); - - if(!called_from_timer && _tdav_session_t140_blocks_has_gap(self->decoder.blocks)){ - self->decoder.timer_pkt_loss.timeout = (base->red.codec ? T140_WAIT_FOR_MISSING_PKT_RED_ON : T140_WAIT_FOR_MISSING_PKT_RED_OFF); - self->decoder.timer_pkt_loss.id = tsk_timer_manager_schedule(self->h_timer, self->decoder.timer_pkt_loss.timeout, _tdav_session_t140_timer_cb, self); - } - else{ - const tsk_list_item_t* item; - const t140_block_t* block; - - tsk_list_foreach(item, self->decoder.blocks){ - if(!(block = (const t140_block_t*)item->data) || block->delivered || block->too_late){ - continue; - } - if(block->data.ptr && block->data.size){ - _tdav_session_t140_recv_raw(self, block->data.ptr, block->data.size); - } - ((t140_block_t*)block)->delivered = tsk_true; - } - } - - tsk_list_unlock(self->decoder.blocks); - tsk_safeobj_unlock(base); - - return 0; + tdav_session_av_t* base = (tdav_session_av_t*)self; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + tsk_safeobj_lock(base); + tsk_list_lock(self->decoder.blocks); + + if(!called_from_timer && _tdav_session_t140_blocks_has_gap(self->decoder.blocks)) { + self->decoder.timer_pkt_loss.timeout = (base->red.codec ? T140_WAIT_FOR_MISSING_PKT_RED_ON : T140_WAIT_FOR_MISSING_PKT_RED_OFF); + self->decoder.timer_pkt_loss.id = tsk_timer_manager_schedule(self->h_timer, self->decoder.timer_pkt_loss.timeout, _tdav_session_t140_timer_cb, self); + } + else { + const tsk_list_item_t* item; + const t140_block_t* block; + + tsk_list_foreach(item, self->decoder.blocks) { + if(!(block = (const t140_block_t*)item->data) || block->delivered || block->too_late) { + continue; + } + if(block->data.ptr && block->data.size) { + _tdav_session_t140_recv_raw(self, block->data.ptr, block->data.size); + } + ((t140_block_t*)block)->delivered = tsk_true; + } + } + + tsk_list_unlock(self->decoder.blocks); + tsk_safeobj_unlock(base); + + return 0; } static int _tdav_session_t140_consume_data(tdav_session_t140_t* self, enum tmedia_t140_data_type_e data_type, const void *data_ptr, tsk_size_t data_size) { - tdav_session_av_t* base = (tdav_session_av_t*)self; - if(!self || !base->consumer){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - T140_RESIZE_BUFFER(self->decoder.consumer_buffer, self->decoder.consumer_buffer_size, (data_size + 4)); - if(self->decoder.consumer_buffer){ - *((int32_t*)self->decoder.consumer_buffer) = data_type; - if(data_ptr && data_size){ - memcpy(&((uint8_t*)self->decoder.consumer_buffer)[4], data_ptr, data_size); - } - tmedia_consumer_consume(base->consumer, self->decoder.consumer_buffer, (data_size + 4), tsk_null); - } - return 0; + tdav_session_av_t* base = (tdav_session_av_t*)self; + if(!self || !base->consumer) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + T140_RESIZE_BUFFER(self->decoder.consumer_buffer, self->decoder.consumer_buffer_size, (data_size + 4)); + if(self->decoder.consumer_buffer) { + *((int32_t*)self->decoder.consumer_buffer) = data_type; + if(data_ptr && data_size) { + memcpy(&((uint8_t*)self->decoder.consumer_buffer)[4], data_ptr, data_size); + } + tmedia_consumer_consume(base->consumer, self->decoder.consumer_buffer, (data_size + 4), tsk_null); + } + return 0; } static int _tdav_session_t140_pred_block_with_transmit_count_more_than_or_equal(const tsk_list_item_t *item, const void *transmit_count) { - if(item && item->data){ - t140_block_t *block = item->data; - return (block->transmit_count >= *((uint32_t*)transmit_count)) ? 0 : -1; - } - return -1; + if(item && item->data) { + t140_block_t *block = item->data; + return (block->transmit_count >= *((uint32_t*)transmit_count)) ? 0 : -1; + } + return -1; } static int _tdav_session_t140_timer_cb(const void* arg, tsk_timer_id_t timer_id) { - tdav_session_t140_t* t140 = (tdav_session_t140_t*)arg; - tdav_session_av_t* base = (tdav_session_av_t*)arg; - static const tsk_bool_t called_from_timer = tsk_true; - int ret = 0; - - tsk_safeobj_lock(base); - - if(timer_id == t140->decoder.timer_pkt_loss.id){ - ret = _tdav_session_t140_decode_and_deliver_blocks(t140, called_from_timer); - } - else if(timer_id == t140->encoder.timer_idle.id){ - ret = tdav_session_t140_send_data_2(TMEDIA_SESSION(t140), tmedia_t140_data_type_zero_width_no_break_space); - t140->encoder.timer_idle.id = tsk_timer_manager_schedule(t140->h_timer, t140->encoder.timer_idle.timeout, _tdav_session_t140_timer_cb, t140); - } - else if(timer_id == t140->encoder.timer_buffering.id){ - void* buffer_ptr; - tsk_size_t buffer_size; - tsk_bool_t was_idle = TSK_TIMER_ID_IS_VALID(t140->encoder.timer_idle.id); - tsk_bool_t last_data = tsk_false; - if(base->red.codec){ - // encapsulated red data and schedule timers if required - buffer_size = _tdav_session_t140_encap_red(t140, &t140->encoder.red_buffer, &t140->encoder.red_buffer_size, &last_data); - buffer_ptr = t140->encoder.red_buffer; - } - else{ - // send buffered data - buffer_ptr = t140->encoder.buffer; - buffer_size = t140->encoder.buffer_idx; - last_data = tsk_true; - t140->encoder.buffer_idx = 0; - } - if(buffer_ptr && buffer_size){ - trtp_manager_send_rtp(base->rtp_manager, buffer_ptr, buffer_size, 300, was_idle, last_data); - } - t140->encoder.timer_buffering.id = last_data - ? TSK_INVALID_TIMER_ID - : tsk_timer_manager_schedule(t140->h_timer, t140->encoder.timer_buffering.timeout, _tdav_session_t140_timer_cb, t140); - } - - tsk_safeobj_unlock(base); - - return ret; + tdav_session_t140_t* t140 = (tdav_session_t140_t*)arg; + tdav_session_av_t* base = (tdav_session_av_t*)arg; + static const tsk_bool_t called_from_timer = tsk_true; + int ret = 0; + + tsk_safeobj_lock(base); + + if(timer_id == t140->decoder.timer_pkt_loss.id) { + ret = _tdav_session_t140_decode_and_deliver_blocks(t140, called_from_timer); + } + else if(timer_id == t140->encoder.timer_idle.id) { + ret = tdav_session_t140_send_data_2(TMEDIA_SESSION(t140), tmedia_t140_data_type_zero_width_no_break_space); + t140->encoder.timer_idle.id = tsk_timer_manager_schedule(t140->h_timer, t140->encoder.timer_idle.timeout, _tdav_session_t140_timer_cb, t140); + } + else if(timer_id == t140->encoder.timer_buffering.id) { + void* buffer_ptr; + tsk_size_t buffer_size; + tsk_bool_t was_idle = TSK_TIMER_ID_IS_VALID(t140->encoder.timer_idle.id); + tsk_bool_t last_data = tsk_false; + if(base->red.codec) { + // encapsulated red data and schedule timers if required + buffer_size = _tdav_session_t140_encap_red(t140, &t140->encoder.red_buffer, &t140->encoder.red_buffer_size, &last_data); + buffer_ptr = t140->encoder.red_buffer; + } + else { + // send buffered data + buffer_ptr = t140->encoder.buffer; + buffer_size = t140->encoder.buffer_idx; + last_data = tsk_true; + t140->encoder.buffer_idx = 0; + } + if(buffer_ptr && buffer_size) { + trtp_manager_send_rtp(base->rtp_manager, buffer_ptr, buffer_size, 300, was_idle, last_data); + } + t140->encoder.timer_buffering.id = last_data + ? TSK_INVALID_TIMER_ID + : tsk_timer_manager_schedule(t140->h_timer, t140->encoder.timer_buffering.timeout, _tdav_session_t140_timer_cb, t140); + } + + tsk_safeobj_unlock(base); + + return ret; } @@ -947,96 +938,94 @@ static int _tdav_session_t140_timer_cb(const void* arg, tsk_timer_id_t timer_id) /* constructor */ static tsk_object_t* tdav_session_t140_ctor(tsk_object_t * self, va_list * app) { - tdav_session_t140_t *t140 = self; - if(t140){ - int ret; - tdav_session_av_t *base = TDAV_SESSION_AV(self); - - /* init() base */ - if((ret = tdav_session_av_init(base, tmedia_t140)) != 0){ - TSK_DEBUG_ERROR("tdav_session_av_init(t140) failed"); - return tsk_null; - } - - /* init() self */ - t140->encoder.timer_buffering.id = t140->decoder.timer_pkt_loss.id = TSK_INVALID_TIMER_ID; - if(base->producer){ - tmedia_producer_set_enc_callback(base->producer, _tdav_session_t140_producer_enc_cb, t140); - } - if(base->consumer){ - } - if(!(t140->encoder.blocks = tsk_list_create())){ - TSK_DEBUG_ERROR("Failed to create encoder blocks list"); - return tsk_null; - } - if(!(t140->decoder.blocks = tsk_list_create())){ - TSK_DEBUG_ERROR("Failed to create decoder blocks list"); - return tsk_null; - } - if(!(t140->h_timer = tsk_timer_manager_create())){ - TSK_DEBUG_ERROR("Failed to create timer manager"); - return tsk_null; - } - } - return self; + tdav_session_t140_t *t140 = self; + if(t140) { + int ret; + tdav_session_av_t *base = TDAV_SESSION_AV(self); + + /* init() base */ + if((ret = tdav_session_av_init(base, tmedia_t140)) != 0) { + TSK_DEBUG_ERROR("tdav_session_av_init(t140) failed"); + return tsk_null; + } + + /* init() self */ + t140->encoder.timer_buffering.id = t140->decoder.timer_pkt_loss.id = TSK_INVALID_TIMER_ID; + if(base->producer) { + tmedia_producer_set_enc_callback(base->producer, _tdav_session_t140_producer_enc_cb, t140); + } + if(base->consumer) { + } + if(!(t140->encoder.blocks = tsk_list_create())) { + TSK_DEBUG_ERROR("Failed to create encoder blocks list"); + return tsk_null; + } + if(!(t140->decoder.blocks = tsk_list_create())) { + TSK_DEBUG_ERROR("Failed to create decoder blocks list"); + return tsk_null; + } + if(!(t140->h_timer = tsk_timer_manager_create())) { + TSK_DEBUG_ERROR("Failed to create timer manager"); + return tsk_null; + } + } + return self; } /* destructor */ static tsk_object_t* tdav_session_t140_dtor(tsk_object_t * self) -{ - tdav_session_t140_t *t140 = self; - if(t140){ - tdav_session_t140_stop((tmedia_session_t*)t140); - TSK_OBJECT_SAFE_FREE(t140->h_timer); - // Do it in this order (deinit self first) - TSK_OBJECT_SAFE_FREE(t140->encoder.codec); - TSK_FREE(t140->encoder.buffer); - TSK_FREE(t140->encoder.red_buffer); - TSK_OBJECT_SAFE_FREE(t140->encoder.blocks); - TSK_OBJECT_SAFE_FREE(t140->decoder.codec); - TSK_FREE(t140->decoder.buffer); - TSK_FREE(t140->decoder.consumer_buffer); - TSK_OBJECT_SAFE_FREE(t140->decoder.blocks); - - /* deinit base */ - tdav_session_av_deinit(TDAV_SESSION_AV(self)); - } - - return self; +{ + tdav_session_t140_t *t140 = self; + if(t140) { + tdav_session_t140_stop((tmedia_session_t*)t140); + TSK_OBJECT_SAFE_FREE(t140->h_timer); + // Do it in this order (deinit self first) + TSK_OBJECT_SAFE_FREE(t140->encoder.codec); + TSK_FREE(t140->encoder.buffer); + TSK_FREE(t140->encoder.red_buffer); + TSK_OBJECT_SAFE_FREE(t140->encoder.blocks); + TSK_OBJECT_SAFE_FREE(t140->decoder.codec); + TSK_FREE(t140->decoder.buffer); + TSK_FREE(t140->decoder.consumer_buffer); + TSK_OBJECT_SAFE_FREE(t140->decoder.blocks); + + /* deinit base */ + tdav_session_av_deinit(TDAV_SESSION_AV(self)); + } + + return self; } /* object definition */ -static const tsk_object_def_t tdav_session_t140_def_s = -{ - sizeof(tdav_session_t140_t), - tdav_session_t140_ctor, - tdav_session_t140_dtor, - tmedia_session_cmp, +static const tsk_object_def_t tdav_session_t140_def_s = { + sizeof(tdav_session_t140_t), + tdav_session_t140_ctor, + tdav_session_t140_dtor, + tmedia_session_cmp, }; /* plugin definition*/ -static const tmedia_session_plugin_def_t tdav_session_t140_plugin_def_s = -{ - &tdav_session_t140_def_s, - - tmedia_t140, - "text", - - tdav_session_t140_set, - tdav_session_t140_get, - tdav_session_t140_prepare, - tdav_session_t140_start, - tdav_session_t140_pause, - tdav_session_t140_stop, - - /* Audio part */ - {0}, - - tdav_session_t140_get_lo, - tdav_session_t140_set_ro, - - /* T.140 part */ - { - tdav_session_t140_set_ondata_cbfn, - tdav_session_t140_send_data - } +static const tmedia_session_plugin_def_t tdav_session_t140_plugin_def_s = { + &tdav_session_t140_def_s, + + tmedia_t140, + "text", + + tdav_session_t140_set, + tdav_session_t140_get, + tdav_session_t140_prepare, + tdav_session_t140_start, + tdav_session_t140_pause, + tdav_session_t140_stop, + + /* Audio part */ + {0}, + + tdav_session_t140_get_lo, + tdav_session_t140_set_ro, + + /* T.140 part */ + { + tdav_session_t140_set_ondata_cbfn, + tdav_session_t140_send_data + } }; const tmedia_session_plugin_def_t *tdav_session_t140_plugin_def_t = &tdav_session_t140_plugin_def_s; @@ -1045,121 +1034,124 @@ const tmedia_session_plugin_def_t *tdav_session_t140_plugin_def_t = &tdav_sessio // static tsk_object_t* t140_block_ctor(tsk_object_t * self, va_list * app) { - t140_block_t *block = self; - if(block){ - } - return self; + t140_block_t *block = self; + if(block) { + } + return self; } static tsk_object_t* t140_block_dtor(tsk_object_t * self) -{ - t140_block_t *block = self; - if(block){ - TSK_FREE(block->data.ptr); - } +{ + t140_block_t *block = self; + if(block) { + TSK_FREE(block->data.ptr); + } - return self; + return self; } static int t140_block_cmp(const tsk_object_t *_b1, const tsk_object_t *_b2) { - const t140_block_t *b1 = _b1; - const t140_block_t *b2 = _b2; - - if(b1 && b2){ - return (int)(b1->seq_num - b2->seq_num); - } - else if(!b1 && !b2) return 0; - else return -1; + const t140_block_t *b1 = _b1; + const t140_block_t *b2 = _b2; + + if(b1 && b2) { + return (int)(b1->seq_num - b2->seq_num); + } + else if(!b1 && !b2) { + return 0; + } + else { + return -1; + } } -static const tsk_object_def_t t140_block_def_s = -{ - sizeof(t140_block_t), - t140_block_ctor, - t140_block_dtor, - t140_block_cmp, +static const tsk_object_def_t t140_block_def_s = { + sizeof(t140_block_t), + t140_block_ctor, + t140_block_dtor, + t140_block_cmp, }; const tsk_object_def_t *t140_block_def_t = &t140_block_def_s; static tsk_bool_t _tdav_session_t140_blocks_has_gap(tdav_session_t140_blocks_L_t* blocks) { - if(blocks && !TSK_LIST_IS_EMPTY(blocks)){ - const tsk_list_item_t* item; - int32_t last_seq_num = -1; - tsk_bool_t has_gap = tsk_false; - tsk_list_lock(blocks); - tsk_list_foreach(item, blocks){ - if(last_seq_num > 0 && ((last_seq_num + 1) != T140_BLOCK(item->data)->seq_num)){ - has_gap = tsk_true; - } - last_seq_num = T140_BLOCK(item->data)->seq_num; - if(has_gap){ - break; - } - } - tsk_list_unlock(blocks); - return has_gap; - } - return tsk_false; + if(blocks && !TSK_LIST_IS_EMPTY(blocks)) { + const tsk_list_item_t* item; + int32_t last_seq_num = -1; + tsk_bool_t has_gap = tsk_false; + tsk_list_lock(blocks); + tsk_list_foreach(item, blocks) { + if(last_seq_num > 0 && ((last_seq_num + 1) != T140_BLOCK(item->data)->seq_num)) { + has_gap = tsk_true; + } + last_seq_num = T140_BLOCK(item->data)->seq_num; + if(has_gap) { + break; + } + } + tsk_list_unlock(blocks); + return has_gap; + } + return tsk_false; } static tsk_bool_t _tdav_session_t140_blocks_has_seqnum(tdav_session_t140_blocks_L_t* blocks, uint16_t seq_num) { - if(blocks){ - const tsk_list_item_t* item; - tsk_bool_t has_seqnum = tsk_false; - tsk_list_lock(blocks); - tsk_list_foreach(item, blocks){ - if(seq_num == T140_BLOCK(item->data)->seq_num){ - has_seqnum = tsk_true; - break; - } - } - tsk_list_unlock(blocks); - return has_seqnum; - } - return tsk_false; + if(blocks) { + const tsk_list_item_t* item; + tsk_bool_t has_seqnum = tsk_false; + tsk_list_lock(blocks); + tsk_list_foreach(item, blocks) { + if(seq_num == T140_BLOCK(item->data)->seq_num) { + has_seqnum = tsk_true; + break; + } + } + tsk_list_unlock(blocks); + return has_seqnum; + } + return tsk_false; } static int _tdav_session_t140_blocks_add(tdav_session_t140_blocks_L_t* blocks, int64_t* blocks_count, t140_block_t** block, int64_t blocks_count_max) { - if(blocks && blocks_count && block){ - tsk_list_lock(blocks); - if(tsk_list_push_ascending_data(blocks, (void**)block) == 0){ - if((*blocks_count = (*blocks_count) + 1) > blocks_count_max){ - tsk_list_item_t* first_item = tsk_list_pop_first_item(blocks); - TSK_OBJECT_SAFE_FREE(first_item); - } - } - tsk_list_unlock(blocks); - } - return 0; + if(blocks && blocks_count && block) { + tsk_list_lock(blocks); + if(tsk_list_push_ascending_data(blocks, (void**)block) == 0) { + if((*blocks_count = (*blocks_count) + 1) > blocks_count_max) { + tsk_list_item_t* first_item = tsk_list_pop_first_item(blocks); + TSK_OBJECT_SAFE_FREE(first_item); + } + } + tsk_list_unlock(blocks); + } + return 0; } static t140_block_t* _tdav_session_t140_block_create(uint8_t pt, uint16_t seq_num, uint32_t timestamp, tsk_bool_t delivered, const void* data_ptr, tsk_size_t data_size) { - void* _data_ptr = tsk_null; - t140_block_t* block = tsk_null; - - if(data_ptr && data_size){ - if(!(_data_ptr = tsk_malloc(data_size))){ - TSK_DEBUG_ERROR("Failed to alloc data with size = %u", data_size); - goto bail; - } - memcpy(_data_ptr, data_ptr, data_size); - } - if(!(block = tsk_object_new(t140_block_def_t))){ - TSK_DEBUG_ERROR("Failed to create new block object"); - goto bail; - } - if(_data_ptr){ - block->data.ptr = _data_ptr, _data_ptr = tsk_null; - block->data.size = data_size; - } - block->pt = pt; - block->seq_num = seq_num; - block->timestamp = timestamp; + void* _data_ptr = tsk_null; + t140_block_t* block = tsk_null; + + if(data_ptr && data_size) { + if(!(_data_ptr = tsk_malloc(data_size))) { + TSK_DEBUG_ERROR("Failed to alloc data with size = %u", data_size); + goto bail; + } + memcpy(_data_ptr, data_ptr, data_size); + } + if(!(block = tsk_object_new(t140_block_def_t))) { + TSK_DEBUG_ERROR("Failed to create new block object"); + goto bail; + } + if(_data_ptr) { + block->data.ptr = _data_ptr, _data_ptr = tsk_null; + block->data.size = data_size; + } + block->pt = pt; + block->seq_num = seq_num; + block->timestamp = timestamp; bail: - TSK_FREE(_data_ptr); - return block; + TSK_FREE(_data_ptr); + return block; }
\ No newline at end of file |