diff options
Diffstat (limited to 'tinyRTP/src/rtcp')
-rwxr-xr-x | tinyRTP/src/rtcp/trtp_rtcp_header.c | 133 | ||||
-rwxr-xr-x | tinyRTP/src/rtcp/trtp_rtcp_packet.c | 379 | ||||
-rwxr-xr-x | tinyRTP/src/rtcp/trtp_rtcp_rblock.c | 167 | ||||
-rwxr-xr-x | tinyRTP/src/rtcp/trtp_rtcp_report.c | 6 | ||||
-rwxr-xr-x | tinyRTP/src/rtcp/trtp_rtcp_report_bye.c | 319 | ||||
-rwxr-xr-x | tinyRTP/src/rtcp/trtp_rtcp_report_fb.c | 1101 | ||||
-rwxr-xr-x | tinyRTP/src/rtcp/trtp_rtcp_report_rr.c | 337 | ||||
-rwxr-xr-x | tinyRTP/src/rtcp/trtp_rtcp_report_sdes.c | 271 | ||||
-rwxr-xr-x | tinyRTP/src/rtcp/trtp_rtcp_report_sr.c | 407 | ||||
-rwxr-xr-x | tinyRTP/src/rtcp/trtp_rtcp_report_xr.c | 6 | ||||
-rwxr-xr-x | tinyRTP/src/rtcp/trtp_rtcp_sdes_chunck.c | 224 | ||||
-rwxr-xr-x | tinyRTP/src/rtcp/trtp_rtcp_sdes_item.c | 171 | ||||
-rwxr-xr-x | tinyRTP/src/rtcp/trtp_rtcp_session.c | 2421 |
13 files changed, 3051 insertions, 2891 deletions
diff --git a/tinyRTP/src/rtcp/trtp_rtcp_header.c b/tinyRTP/src/rtcp/trtp_rtcp_header.c index e93772a..d11d32f 100755 --- a/tinyRTP/src/rtcp/trtp_rtcp_header.c +++ b/tinyRTP/src/rtcp/trtp_rtcp_header.c @@ -2,19 +2,19 @@ * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * * Contact: Mamadou Diop <diopmamadou(at)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. * @@ -35,73 +35,73 @@ header |V=2|P| RC | PT=SR=200 | length | trtp_rtcp_header_t* trtp_rtcp_header_create_null() { - return tsk_object_new(trtp_rtcp_header_def_t); + return tsk_object_new(trtp_rtcp_header_def_t); } trtp_rtcp_header_t* trtp_rtcp_header_create(uint8_t version, uint8_t padding, uint8_t rc, trtp_rtcp_packet_type_t type, uint16_t length_in_bytes) { - trtp_rtcp_header_t* header; - if((header = trtp_rtcp_header_create_null())){ - header->version = version; - header->padding = padding; - header->rc = rc; - header->type = type; - header->length_in_words_minus1 = ((length_in_bytes >> 2) - 1); - header->length_in_bytes = length_in_bytes; - } + trtp_rtcp_header_t* header; + if((header = trtp_rtcp_header_create_null())) { + header->version = version; + header->padding = padding; + header->rc = rc; + header->type = type; + header->length_in_words_minus1 = ((length_in_bytes >> 2) - 1); + header->length_in_bytes = length_in_bytes; + } - return header; + return header; } int trtp_rtcp_header_serialize_to(const trtp_rtcp_header_t *self, void* data, tsk_size_t size) { - uint8_t* pdata = (uint8_t*)data; - if(!self || !data || size < TRTP_RTCP_HEADER_SIZE){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - // Octet-0: version(2), Padding(1), RC(5) - pdata[0] = ((uint8_t)self->version)<<6 | - ((uint8_t)self->padding)<<5 | - ((uint8_t)self->rc); - // Octet-1: PT(8) - pdata[1] = self->type; - // Octet-2 and Octet3: length (16) - pdata[2] = self->length_in_words_minus1 >> 8; - pdata[3] = self->length_in_words_minus1 & 0xFF; - return 0; + uint8_t* pdata = (uint8_t*)data; + if(!self || !data || size < TRTP_RTCP_HEADER_SIZE) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + // Octet-0: version(2), Padding(1), RC(5) + pdata[0] = ((uint8_t)self->version)<<6 | + ((uint8_t)self->padding)<<5 | + ((uint8_t)self->rc); + // Octet-1: PT(8) + pdata[1] = self->type; + // Octet-2 and Octet3: length (16) + pdata[2] = self->length_in_words_minus1 >> 8; + pdata[3] = self->length_in_words_minus1 & 0xFF; + return 0; } trtp_rtcp_header_t* trtp_rtcp_header_deserialize(const void *data, tsk_size_t size) { - trtp_rtcp_header_t* header = tsk_null; - if(trtp_rtcp_header_deserialize_to(&header, data, size) != 0){ - TSK_DEBUG_ERROR("Failed to deserialize the rtcp header"); - TSK_OBJECT_SAFE_FREE(header); - } - return header; + trtp_rtcp_header_t* header = tsk_null; + if(trtp_rtcp_header_deserialize_to(&header, data, size) != 0) { + TSK_DEBUG_ERROR("Failed to deserialize the rtcp header"); + TSK_OBJECT_SAFE_FREE(header); + } + return header; } int trtp_rtcp_header_deserialize_to(trtp_rtcp_header_t** self, const void *data, tsk_size_t size) { - const uint8_t* pdata = (uint8_t*)data; - if(!self || !data || size < TRTP_RTCP_HEADER_SIZE){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(!*self && !(*self = trtp_rtcp_header_create_null())){ - TSK_DEBUG_ERROR("Failed to create new rtcp header"); - return -3; - } - (*self)->version = pdata[0] >> 6; - (*self)->padding = (pdata[0] >> 5) & 0x01; - (*self)->rc = (pdata[0] & 0x1f); - (*self)->type = (enum trtp_rtcp_packet_type_e)pdata[1]; - (*self)->length_in_words_minus1 = tnet_ntohs_2(&pdata[2]); - (*self)->length_in_bytes = ((*self)->length_in_words_minus1 + 1) << 2; + const uint8_t* pdata = (uint8_t*)data; + if(!self || !data || size < TRTP_RTCP_HEADER_SIZE) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - return 0; + if(!*self && !(*self = trtp_rtcp_header_create_null())) { + TSK_DEBUG_ERROR("Failed to create new rtcp header"); + return -3; + } + (*self)->version = pdata[0] >> 6; + (*self)->padding = (pdata[0] >> 5) & 0x01; + (*self)->rc = (pdata[0] & 0x1f); + (*self)->type = (enum trtp_rtcp_packet_type_e)pdata[1]; + (*self)->length_in_words_minus1 = tnet_ntohs_2(&pdata[2]); + (*self)->length_in_bytes = ((*self)->length_in_words_minus1 + 1) << 2; + + return 0; } //================================================================================================= @@ -109,26 +109,25 @@ int trtp_rtcp_header_deserialize_to(trtp_rtcp_header_t** self, const void *data, // static tsk_object_t* trtp_rtcp_header_ctor(tsk_object_t * self, va_list * app) { - trtp_rtcp_header_t *header = self; - if(header){ - } - return self; + trtp_rtcp_header_t *header = self; + if(header) { + } + return self; } static tsk_object_t* trtp_rtcp_header_dtor(tsk_object_t * self) -{ - trtp_rtcp_header_t *header = self; - if(header){ - } +{ + trtp_rtcp_header_t *header = self; + if(header) { + } - return self; + return self; } -static const tsk_object_def_t trtp_rtcp_header_def_s = -{ - sizeof(trtp_rtcp_header_t), - trtp_rtcp_header_ctor, - trtp_rtcp_header_dtor, - tsk_null, +static const tsk_object_def_t trtp_rtcp_header_def_s = { + sizeof(trtp_rtcp_header_t), + trtp_rtcp_header_ctor, + trtp_rtcp_header_dtor, + tsk_null, }; const tsk_object_def_t *trtp_rtcp_header_def_t = &trtp_rtcp_header_def_s; diff --git a/tinyRTP/src/rtcp/trtp_rtcp_packet.c b/tinyRTP/src/rtcp/trtp_rtcp_packet.c index d2ec856..d5614b8 100755 --- a/tinyRTP/src/rtcp/trtp_rtcp_packet.c +++ b/tinyRTP/src/rtcp/trtp_rtcp_packet.c @@ -2,19 +2,19 @@ * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * * Contact: Mamadou Diop <diopmamadou(at)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. * @@ -32,224 +32,255 @@ static tsk_object_t* trtp_rtcp_packet_ctor(tsk_object_t * self, va_list * app) { - trtp_rtcp_packet_t *packet = self; - if(packet){ - } - return self; + trtp_rtcp_packet_t *packet = self; + if(packet) { + } + return self; } static tsk_object_t* trtp_rtcp_packet_dtor(tsk_object_t * self) -{ - trtp_rtcp_packet_t *packet = self; - if(packet){ +{ + trtp_rtcp_packet_t *packet = self; + if(packet) { - } + } - return self; + return self; } -static const tsk_object_def_t trtp_rtcp_packet_def_s = -{ - sizeof(trtp_rtcp_packet_t), - trtp_rtcp_packet_ctor, - trtp_rtcp_packet_dtor, - tsk_null, +static const tsk_object_def_t trtp_rtcp_packet_def_s = { + sizeof(trtp_rtcp_packet_t), + trtp_rtcp_packet_ctor, + trtp_rtcp_packet_dtor, + tsk_null, }; const tsk_object_def_t *trtp_rtcp_packet_def_t = &trtp_rtcp_packet_def_s; trtp_rtcp_packet_t* trtp_rtcp_packet_create(struct trtp_rtcp_header_s* header) { - trtp_rtcp_packet_t* packet; - if((packet = tsk_object_new(trtp_rtcp_packet_def_t)) && header){ - packet->header = tsk_object_ref(header); - } - return packet; + trtp_rtcp_packet_t* packet; + if((packet = tsk_object_new(trtp_rtcp_packet_def_t)) && header) { + packet->header = tsk_object_ref(header); + } + return packet; } int trtp_rtcp_packet_init(trtp_rtcp_packet_t* self, uint8_t version, uint8_t padding, uint8_t rc, trtp_rtcp_packet_type_t type, uint16_t length_in_bytes) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(!self->header){ - self->header = trtp_rtcp_header_create(version, padding, rc, type, length_in_bytes); - } - else{ - self->header->version = version; - self->header->padding = padding; - self->header->rc = rc; - self->header->type = type; - self->header->length_in_bytes = length_in_bytes; - self->header->length_in_words_minus1 = ((length_in_bytes >> 2) - 1); - } - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(!self->header) { + self->header = trtp_rtcp_header_create(version, padding, rc, type, length_in_bytes); + } + else { + self->header->version = version; + self->header->padding = padding; + self->header->rc = rc; + self->header->type = type; + self->header->length_in_bytes = length_in_bytes; + self->header->length_in_words_minus1 = ((length_in_bytes >> 2) - 1); + } + return 0; } trtp_rtcp_packet_t* trtp_rtcp_packet_deserialize(const void* data, tsk_size_t size) { - trtp_rtcp_packet_type_t type; - - if(!data || size < TRTP_RTCP_HEADER_SIZE){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - type = (trtp_rtcp_packet_type_t)((const uint8_t*)data)[1]; - - switch(type){ - case trtp_rtcp_packet_type_rr: return (trtp_rtcp_packet_t*)trtp_rtcp_report_rr_deserialize(data, size); - case trtp_rtcp_packet_type_sr: return (trtp_rtcp_packet_t*)trtp_rtcp_report_sr_deserialize(data, size); - case trtp_rtcp_packet_type_sdes: return (trtp_rtcp_packet_t*)trtp_rtcp_report_sdes_deserialize(data, size); - case trtp_rtcp_packet_type_bye: return (trtp_rtcp_packet_t*)trtp_rtcp_report_bye_deserialize(data, size); - case trtp_rtcp_packet_type_rtpfb: return (trtp_rtcp_packet_t*)trtp_rtcp_report_rtpfb_deserialize(data, size); - case trtp_rtcp_packet_type_psfb: return (trtp_rtcp_packet_t*)trtp_rtcp_report_psfb_deserialize(data, size); - default: - { - // returns abstract RTCP packet - trtp_rtcp_header_t* header; - TSK_DEBUG_ERROR("%d not recognized as valid RTCP packet type", (int)type); - if((header = trtp_rtcp_header_deserialize(data, size))){ - trtp_rtcp_packet_t* packet = trtp_rtcp_packet_create(header); - TSK_OBJECT_SAFE_FREE(header); - return packet; - } - break; - } - } - - return tsk_null; + trtp_rtcp_packet_type_t type; + + if(!data || size < TRTP_RTCP_HEADER_SIZE) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + type = (trtp_rtcp_packet_type_t)((const uint8_t*)data)[1]; + + switch(type) { + case trtp_rtcp_packet_type_rr: + return (trtp_rtcp_packet_t*)trtp_rtcp_report_rr_deserialize(data, size); + case trtp_rtcp_packet_type_sr: + return (trtp_rtcp_packet_t*)trtp_rtcp_report_sr_deserialize(data, size); + case trtp_rtcp_packet_type_sdes: + return (trtp_rtcp_packet_t*)trtp_rtcp_report_sdes_deserialize(data, size); + case trtp_rtcp_packet_type_bye: + return (trtp_rtcp_packet_t*)trtp_rtcp_report_bye_deserialize(data, size); + case trtp_rtcp_packet_type_rtpfb: + return (trtp_rtcp_packet_t*)trtp_rtcp_report_rtpfb_deserialize(data, size); + case trtp_rtcp_packet_type_psfb: + return (trtp_rtcp_packet_t*)trtp_rtcp_report_psfb_deserialize(data, size); + default: { + // returns abstract RTCP packet + trtp_rtcp_header_t* header; + TSK_DEBUG_ERROR("%d not recognized as valid RTCP packet type", (int)type); + if((header = trtp_rtcp_header_deserialize(data, size))) { + trtp_rtcp_packet_t* packet = trtp_rtcp_packet_create(header); + TSK_OBJECT_SAFE_FREE(header); + return packet; + } + break; + } + } + + return tsk_null; } int trtp_rtcp_packet_serialize_to(const trtp_rtcp_packet_t* self, void* data, tsk_size_t size) { - if(!self || !self->header || !data || !size){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - switch(self->header->type){ - case trtp_rtcp_packet_type_rr: return trtp_rtcp_report_rr_serialize_to((const trtp_rtcp_report_rr_t*)self, data, size); - case trtp_rtcp_packet_type_sr: return trtp_rtcp_report_sr_serialize_to((const trtp_rtcp_report_sr_t*)self, data, size); - case trtp_rtcp_packet_type_sdes: return trtp_rtcp_report_sdes_serialize_to((const trtp_rtcp_report_sdes_t*)self, data, size); - case trtp_rtcp_packet_type_bye: return trtp_rtcp_report_bye_serialize_to((const trtp_rtcp_report_bye_t*)self, data, size); - case trtp_rtcp_packet_type_psfb: return trtp_rtcp_report_psfb_serialize_to((const trtp_rtcp_report_psfb_t*)self, data, size); - case trtp_rtcp_packet_type_rtpfb: return trtp_rtcp_report_rtpfb_serialize_to((const trtp_rtcp_report_rtpfb_t*)self, data, size); - default: - { - TSK_DEBUG_ERROR("%d not recognized as valid RTCP packet type", (int)self->header->type); - return -2; - } - } + if(!self || !self->header || !data || !size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + switch(self->header->type) { + case trtp_rtcp_packet_type_rr: + return trtp_rtcp_report_rr_serialize_to((const trtp_rtcp_report_rr_t*)self, data, size); + case trtp_rtcp_packet_type_sr: + return trtp_rtcp_report_sr_serialize_to((const trtp_rtcp_report_sr_t*)self, data, size); + case trtp_rtcp_packet_type_sdes: + return trtp_rtcp_report_sdes_serialize_to((const trtp_rtcp_report_sdes_t*)self, data, size); + case trtp_rtcp_packet_type_bye: + return trtp_rtcp_report_bye_serialize_to((const trtp_rtcp_report_bye_t*)self, data, size); + case trtp_rtcp_packet_type_psfb: + return trtp_rtcp_report_psfb_serialize_to((const trtp_rtcp_report_psfb_t*)self, data, size); + case trtp_rtcp_packet_type_rtpfb: + return trtp_rtcp_report_rtpfb_serialize_to((const trtp_rtcp_report_rtpfb_t*)self, data, size); + default: { + TSK_DEBUG_ERROR("%d not recognized as valid RTCP packet type", (int)self->header->type); + return -2; + } + } } tsk_buffer_t* trtp_rtcp_packet_serialize(const trtp_rtcp_packet_t* self, tsk_size_t num_bytes_pad) { - tsk_size_t size = trtp_rtcp_packet_get_size(self); - if(self && size){ - tsk_buffer_t* buffer; - const tsk_size_t _size = (size + num_bytes_pad); - if((buffer = tsk_buffer_create(tsk_null, _size))){ - if(trtp_rtcp_packet_serialize_to(self, buffer->data, size) != 0){ - TSK_OBJECT_SAFE_FREE(buffer); - } - else buffer->size = size; - return buffer; - } - } - return tsk_null; + tsk_size_t size = trtp_rtcp_packet_get_size(self); + if(self && size) { + tsk_buffer_t* buffer; + const tsk_size_t _size = (size + num_bytes_pad); + if((buffer = tsk_buffer_create(tsk_null, _size))) { + if(trtp_rtcp_packet_serialize_to(self, buffer->data, size) != 0) { + TSK_OBJECT_SAFE_FREE(buffer); + } + else { + buffer->size = size; + } + return buffer; + } + } + return tsk_null; } int trtp_rtcp_packet_add_packet(trtp_rtcp_packet_t* self, trtp_rtcp_packet_t* packet, tsk_bool_t front) { - trtp_rtcp_packets_L_t* packets = tsk_null; - if(!self || !self->header || !packet){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - switch(self->header->type){ - case trtp_rtcp_packet_type_rr: packets = ((trtp_rtcp_report_rr_t*)self)->packets; break; - case trtp_rtcp_packet_type_sr: packets = ((trtp_rtcp_report_sr_t*)self)->packets; break; - case trtp_rtcp_packet_type_bye: packets = ((trtp_rtcp_report_bye_t*)self)->packets; break; - default: TSK_DEBUG_ERROR("not valid operation for packet type %d", (int)self->header->type); return -2; - } - - if(packets){ - //tsk_size_t packet_size = trtp_rtcp_packet_get_size(packet); - packet = tsk_object_ref(packet); - // self->header->length_in_bytes += packet_size; - // self->header->length_in_words_minus1 = ((self->header->length_in_bytes >> 2) - 1) + - // ((self->header->length_in_bytes & 0x03) ? 1 : 0); - tsk_list_push_data(packets, (void**)&packet, !front); - } - - return 0; + trtp_rtcp_packets_L_t* packets = tsk_null; + if(!self || !self->header || !packet) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + switch(self->header->type) { + case trtp_rtcp_packet_type_rr: + packets = ((trtp_rtcp_report_rr_t*)self)->packets; + break; + case trtp_rtcp_packet_type_sr: + packets = ((trtp_rtcp_report_sr_t*)self)->packets; + break; + case trtp_rtcp_packet_type_bye: + packets = ((trtp_rtcp_report_bye_t*)self)->packets; + break; + default: + TSK_DEBUG_ERROR("not valid operation for packet type %d", (int)self->header->type); + return -2; + } + + if(packets) { + //tsk_size_t packet_size = trtp_rtcp_packet_get_size(packet); + packet = tsk_object_ref(packet); + // self->header->length_in_bytes += packet_size; + // self->header->length_in_words_minus1 = ((self->header->length_in_bytes >> 2) - 1) + + // ((self->header->length_in_bytes & 0x03) ? 1 : 0); + tsk_list_push_data(packets, (void**)&packet, !front); + } + + return 0; } const trtp_rtcp_packet_t* trtp_rtcp_packet_get_at(const trtp_rtcp_packet_t* self, trtp_rtcp_packet_type_t type, tsk_size_t index) { - const tsk_list_item_t *item; - const trtp_rtcp_packets_L_t* packets = tsk_null; - tsk_size_t i; - - if(!self || !self->header){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - if(self->header->type == type && index == 0){ - return self; - } - switch(self->header->type){ - case trtp_rtcp_packet_type_rr: packets = ((const trtp_rtcp_report_rr_t*)self)->packets; break; - case trtp_rtcp_packet_type_sr: packets = ((const trtp_rtcp_report_sr_t*)self)->packets; break; - case trtp_rtcp_packet_type_bye: packets = ((const trtp_rtcp_report_bye_t*)self)->packets; break; - default: break; - } - - i = 0; - tsk_list_foreach(item, packets){ - if(TRTP_RTCP_PACKET(item->data)->header->type == type && i++ >= index){ - return TRTP_RTCP_PACKET(item->data); - } - } - return tsk_null; + const tsk_list_item_t *item; + const trtp_rtcp_packets_L_t* packets = tsk_null; + tsk_size_t i; + + if(!self || !self->header) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + if(self->header->type == type && index == 0) { + return self; + } + switch(self->header->type) { + case trtp_rtcp_packet_type_rr: + packets = ((const trtp_rtcp_report_rr_t*)self)->packets; + break; + case trtp_rtcp_packet_type_sr: + packets = ((const trtp_rtcp_report_sr_t*)self)->packets; + break; + case trtp_rtcp_packet_type_bye: + packets = ((const trtp_rtcp_report_bye_t*)self)->packets; + break; + default: + break; + } + + i = 0; + tsk_list_foreach(item, packets) { + if(TRTP_RTCP_PACKET(item->data)->header->type == type && i++ >= index) { + return TRTP_RTCP_PACKET(item->data); + } + } + return tsk_null; } const trtp_rtcp_packet_t* trtp_rtcp_packet_get(const trtp_rtcp_packet_t* self, trtp_rtcp_packet_type_t type) { - return trtp_rtcp_packet_get_at(self, type, 0); + return trtp_rtcp_packet_get_at(self, type, 0); } tsk_size_t trtp_rtcp_packet_get_size(const trtp_rtcp_packet_t* self) { - if(!self || !self->header){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - - switch(self->header->type){ - case trtp_rtcp_packet_type_rr: return trtp_rtcp_report_rr_get_size((const trtp_rtcp_report_rr_t*)self); - case trtp_rtcp_packet_type_sr: return trtp_rtcp_report_sr_get_size((const trtp_rtcp_report_sr_t*)self); - case trtp_rtcp_packet_type_sdes: return trtp_rtcp_report_sdes_get_size((const trtp_rtcp_report_sdes_t*)self); - case trtp_rtcp_packet_type_bye: return trtp_rtcp_report_bye_get_size((const trtp_rtcp_report_bye_t*)self); - case trtp_rtcp_packet_type_rtpfb: return trtp_rtcp_report_rtpfb_get_size((const trtp_rtcp_report_rtpfb_t*)self); - case trtp_rtcp_packet_type_psfb: return trtp_rtcp_report_psfb_get_size((const trtp_rtcp_report_psfb_t*)self); - default: - { - TSK_DEBUG_ERROR("%d not recognized as valid RTCP packet type", (int)self->header->type); - return self->header->length_in_bytes; - } - } + if(!self || !self->header) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + switch(self->header->type) { + case trtp_rtcp_packet_type_rr: + return trtp_rtcp_report_rr_get_size((const trtp_rtcp_report_rr_t*)self); + case trtp_rtcp_packet_type_sr: + return trtp_rtcp_report_sr_get_size((const trtp_rtcp_report_sr_t*)self); + case trtp_rtcp_packet_type_sdes: + return trtp_rtcp_report_sdes_get_size((const trtp_rtcp_report_sdes_t*)self); + case trtp_rtcp_packet_type_bye: + return trtp_rtcp_report_bye_get_size((const trtp_rtcp_report_bye_t*)self); + case trtp_rtcp_packet_type_rtpfb: + return trtp_rtcp_report_rtpfb_get_size((const trtp_rtcp_report_rtpfb_t*)self); + case trtp_rtcp_packet_type_psfb: + return trtp_rtcp_report_psfb_get_size((const trtp_rtcp_report_psfb_t*)self); + default: { + TSK_DEBUG_ERROR("%d not recognized as valid RTCP packet type", (int)self->header->type); + return self->header->length_in_bytes; + } + } } int trtp_rtcp_packet_deinit(trtp_rtcp_packet_t* self) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - TSK_OBJECT_SAFE_FREE(self->header); - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + TSK_OBJECT_SAFE_FREE(self->header); + return 0; } diff --git a/tinyRTP/src/rtcp/trtp_rtcp_rblock.c b/tinyRTP/src/rtcp/trtp_rtcp_rblock.c index 9a85b4b..3c9bc51 100755 --- a/tinyRTP/src/rtcp/trtp_rtcp_rblock.c +++ b/tinyRTP/src/rtcp/trtp_rtcp_rblock.c @@ -2,19 +2,19 @@ * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * * Contact: Mamadou Diop <diopmamadou(at)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. * @@ -42,112 +42,111 @@ block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ static tsk_object_t* trtp_rtcp_rblock_ctor(tsk_object_t * self, va_list * app) { - trtp_rtcp_rblock_t *block = self; - if(block){ - } - return self; + trtp_rtcp_rblock_t *block = self; + if(block) { + } + return self; } static tsk_object_t* trtp_rtcp_rblock_dtor(tsk_object_t * self) -{ - trtp_rtcp_rblock_t *block = self; - if(block){ - } +{ + trtp_rtcp_rblock_t *block = self; + if(block) { + } - return self; + return self; } -static const tsk_object_def_t trtp_rtcp_rblock_def_s = -{ - sizeof(trtp_rtcp_rblock_t), - trtp_rtcp_rblock_ctor, - trtp_rtcp_rblock_dtor, - tsk_null, +static const tsk_object_def_t trtp_rtcp_rblock_def_s = { + sizeof(trtp_rtcp_rblock_t), + trtp_rtcp_rblock_ctor, + trtp_rtcp_rblock_dtor, + tsk_null, }; const tsk_object_def_t *trtp_rtcp_rblock_def_t = &trtp_rtcp_rblock_def_s; trtp_rtcp_rblock_t* trtp_rtcp_rblock_create_null() { - return tsk_object_new(trtp_rtcp_rblock_def_t); + return tsk_object_new(trtp_rtcp_rblock_def_t); } trtp_rtcp_rblock_t* trtp_rtcp_rblock_deserialize(const void* data, tsk_size_t size) { - trtp_rtcp_rblock_t* rblock = tsk_null; - const uint8_t* pdata = (const uint8_t*)data; - if(!data || size < TRTP_RTCP_RBLOCK_SIZE){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - if((rblock = trtp_rtcp_rblock_create_null())){ - rblock->ssrc = (uint32_t)tnet_ntohl_2(pdata); - rblock->fraction = pdata[4]; - rblock->cumulative_no_lost = (tnet_ntohl_2(&pdata[5]) >> 8) & 0xFFFFFF; - rblock->last_seq = (uint32_t)tnet_ntohl_2(&pdata[8]); - rblock->jitter = (uint32_t)tnet_ntohl_2(&pdata[12]); - rblock->lsr = (uint32_t)tnet_ntohl_2(&pdata[16]); - rblock->dlsr = (uint32_t)tnet_ntohl_2(&pdata[20]); - } - else{ - TSK_DEBUG_ERROR("Failed to create report block object"); - } + trtp_rtcp_rblock_t* rblock = tsk_null; + const uint8_t* pdata = (const uint8_t*)data; + if(!data || size < TRTP_RTCP_RBLOCK_SIZE) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + if((rblock = trtp_rtcp_rblock_create_null())) { + rblock->ssrc = (uint32_t)tnet_ntohl_2(pdata); + rblock->fraction = pdata[4]; + rblock->cumulative_no_lost = (tnet_ntohl_2(&pdata[5]) >> 8) & 0xFFFFFF; + rblock->last_seq = (uint32_t)tnet_ntohl_2(&pdata[8]); + rblock->jitter = (uint32_t)tnet_ntohl_2(&pdata[12]); + rblock->lsr = (uint32_t)tnet_ntohl_2(&pdata[16]); + rblock->dlsr = (uint32_t)tnet_ntohl_2(&pdata[20]); + } + else { + TSK_DEBUG_ERROR("Failed to create report block object"); + } - return rblock; + return rblock; } // Up to the int trtp_rtcp_rblock_deserialize_list(const void* data, tsk_size_t _size, trtp_rtcp_rblocks_L_t* dest_list) { - int32_t size = (int32_t)_size; - const uint8_t* pdata = (const uint8_t*)data; - trtp_rtcp_rblock_t* rblock; + int32_t size = (int32_t)_size; + const uint8_t* pdata = (const uint8_t*)data; + trtp_rtcp_rblock_t* rblock; - if(!data || !size || !dest_list){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if(!data || !size || !dest_list) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - while(size >= TRTP_RTCP_RBLOCK_SIZE){ - if((rblock = trtp_rtcp_rblock_deserialize(pdata, size))){ - tsk_list_push_back_data(dest_list, (void**)&rblock); - } - if((size -= TRTP_RTCP_RBLOCK_SIZE) > 0){ - pdata += TRTP_RTCP_RBLOCK_SIZE; - } - } - return 0; + while(size >= TRTP_RTCP_RBLOCK_SIZE) { + if((rblock = trtp_rtcp_rblock_deserialize(pdata, size))) { + tsk_list_push_back_data(dest_list, (void**)&rblock); + } + if((size -= TRTP_RTCP_RBLOCK_SIZE) > 0) { + pdata += TRTP_RTCP_RBLOCK_SIZE; + } + } + return 0; } int trtp_rtcp_rblock_serialize_to(const trtp_rtcp_rblock_t* self, void* data, tsk_size_t size) { - uint8_t* pdata = (uint8_t*)data; - if(!self || !data || size < TRTP_RTCP_RBLOCK_SIZE){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + uint8_t* pdata = (uint8_t*)data; + if(!self || !data || size < TRTP_RTCP_RBLOCK_SIZE) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - pdata[0] = self->ssrc >> 24; - pdata[1] = (self->ssrc >> 16) & 0xFF; - pdata[2] = (self->ssrc >> 8) & 0xFF; - pdata[3] = (self->ssrc & 0xFF); - pdata[4] = self->fraction; - pdata[5] = (self->cumulative_no_lost >> 16) & 0xFF; - pdata[6] = (self->cumulative_no_lost >> 8) & 0xFF; - pdata[7] = (self->cumulative_no_lost & 0xFF); - pdata[8] = self->last_seq >> 24; - pdata[9] = (self->last_seq >> 16) & 0xFF; - pdata[10] = (self->last_seq >> 8) & 0xFF; - pdata[11] = (self->last_seq & 0xFF); - pdata[12] = self->jitter >> 24; - pdata[13] = (self->jitter >> 16) & 0xFF; - pdata[14] = (self->jitter >> 8) & 0xFF; - pdata[15] = (self->jitter & 0xFF); - pdata[16] = self->lsr >> 24; - pdata[17] = (self->lsr >> 16) & 0xFF; - pdata[18] = (self->lsr >> 8) & 0xFF; - pdata[19] = (self->lsr & 0xFF); - pdata[20] = self->dlsr >> 24; - pdata[21] = (self->dlsr >> 16) & 0xFF; - pdata[22] = (self->dlsr >> 8) & 0xFF; - pdata[23] = (self->dlsr & 0xFF); + pdata[0] = self->ssrc >> 24; + pdata[1] = (self->ssrc >> 16) & 0xFF; + pdata[2] = (self->ssrc >> 8) & 0xFF; + pdata[3] = (self->ssrc & 0xFF); + pdata[4] = self->fraction; + pdata[5] = (self->cumulative_no_lost >> 16) & 0xFF; + pdata[6] = (self->cumulative_no_lost >> 8) & 0xFF; + pdata[7] = (self->cumulative_no_lost & 0xFF); + pdata[8] = self->last_seq >> 24; + pdata[9] = (self->last_seq >> 16) & 0xFF; + pdata[10] = (self->last_seq >> 8) & 0xFF; + pdata[11] = (self->last_seq & 0xFF); + pdata[12] = self->jitter >> 24; + pdata[13] = (self->jitter >> 16) & 0xFF; + pdata[14] = (self->jitter >> 8) & 0xFF; + pdata[15] = (self->jitter & 0xFF); + pdata[16] = self->lsr >> 24; + pdata[17] = (self->lsr >> 16) & 0xFF; + pdata[18] = (self->lsr >> 8) & 0xFF; + pdata[19] = (self->lsr & 0xFF); + pdata[20] = self->dlsr >> 24; + pdata[21] = (self->dlsr >> 16) & 0xFF; + pdata[22] = (self->dlsr >> 8) & 0xFF; + pdata[23] = (self->dlsr & 0xFF); - return 0; + return 0; }
\ No newline at end of file diff --git a/tinyRTP/src/rtcp/trtp_rtcp_report.c b/tinyRTP/src/rtcp/trtp_rtcp_report.c index 5fb2697..41e177b 100755 --- a/tinyRTP/src/rtcp/trtp_rtcp_report.c +++ b/tinyRTP/src/rtcp/trtp_rtcp_report.c @@ -2,19 +2,19 @@ * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * * Contact: Mamadou Diop <diopmamadou(at)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. * diff --git a/tinyRTP/src/rtcp/trtp_rtcp_report_bye.c b/tinyRTP/src/rtcp/trtp_rtcp_report_bye.c index 0f44608..9085160 100755 --- a/tinyRTP/src/rtcp/trtp_rtcp_report_bye.c +++ b/tinyRTP/src/rtcp/trtp_rtcp_report_bye.c @@ -2,19 +2,19 @@ * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * * Contact: Mamadou Diop <diopmamadou(at)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. * @@ -31,195 +31,194 @@ static tsk_object_t* trtp_rtcp_report_bye_ctor(tsk_object_t * self, va_list * app) { - trtp_rtcp_report_bye_t *bye = self; - if(bye){ - bye->packets = tsk_list_create(); - } - return self; + trtp_rtcp_report_bye_t *bye = self; + if(bye) { + bye->packets = tsk_list_create(); + } + return self; } static tsk_object_t* trtp_rtcp_report_bye_dtor(tsk_object_t * self) -{ - trtp_rtcp_report_bye_t *bye = self; - if(bye){ - // deinit self - TSK_OBJECT_SAFE_FREE(bye->packets); - TSK_FREE(bye->ssrc_list); - // deinit base - trtp_rtcp_packet_deinit(TRTP_RTCP_PACKET(bye)); - } - - return self; +{ + trtp_rtcp_report_bye_t *bye = self; + if(bye) { + // deinit self + TSK_OBJECT_SAFE_FREE(bye->packets); + TSK_FREE(bye->ssrc_list); + // deinit base + trtp_rtcp_packet_deinit(TRTP_RTCP_PACKET(bye)); + } + + return self; } -static const tsk_object_def_t trtp_rtcp_report_bye_def_s = -{ - sizeof(trtp_rtcp_report_bye_t), - trtp_rtcp_report_bye_ctor, - trtp_rtcp_report_bye_dtor, - tsk_null, +static const tsk_object_def_t trtp_rtcp_report_bye_def_s = { + sizeof(trtp_rtcp_report_bye_t), + trtp_rtcp_report_bye_ctor, + trtp_rtcp_report_bye_dtor, + tsk_null, }; const tsk_object_def_t *trtp_rtcp_report_bye_def_t = &trtp_rtcp_report_bye_def_s; trtp_rtcp_report_bye_t* trtp_rtcp_report_bye_create_null() { - trtp_rtcp_report_bye_t* bye; - if((bye = (trtp_rtcp_report_bye_t*)tsk_object_new(trtp_rtcp_report_bye_def_t))){ - trtp_rtcp_packet_init(TRTP_RTCP_PACKET(bye), TRTP_RTCP_HEADER_VERSION_DEFAULT, 0, 0, trtp_rtcp_packet_type_bye, TRTP_RTCP_HEADER_SIZE); - } - return bye; + trtp_rtcp_report_bye_t* bye; + if((bye = (trtp_rtcp_report_bye_t*)tsk_object_new(trtp_rtcp_report_bye_def_t))) { + trtp_rtcp_packet_init(TRTP_RTCP_PACKET(bye), TRTP_RTCP_HEADER_VERSION_DEFAULT, 0, 0, trtp_rtcp_packet_type_bye, TRTP_RTCP_HEADER_SIZE); + } + return bye; } trtp_rtcp_report_bye_t* trtp_rtcp_report_bye_create(struct trtp_rtcp_header_s* header) { - trtp_rtcp_report_bye_t* bye; - if((bye = (trtp_rtcp_report_bye_t*)tsk_object_new(trtp_rtcp_report_bye_def_t))){ - TRTP_RTCP_PACKET(bye)->header = tsk_object_ref(header); - } - return bye; + trtp_rtcp_report_bye_t* bye; + if((bye = (trtp_rtcp_report_bye_t*)tsk_object_new(trtp_rtcp_report_bye_def_t))) { + TRTP_RTCP_PACKET(bye)->header = tsk_object_ref(header); + } + return bye; } trtp_rtcp_report_bye_t* trtp_rtcp_report_bye_create_2(uint32_t ssrc) { - uint32_t* ssrc_list = tsk_malloc(sizeof(uint32_t)); - if(ssrc_list){ - trtp_rtcp_report_bye_t* bye; - if((bye = (trtp_rtcp_report_bye_t*)tsk_object_new(trtp_rtcp_report_bye_def_t))){ - trtp_rtcp_packet_init(TRTP_RTCP_PACKET(bye), TRTP_RTCP_HEADER_VERSION_DEFAULT, 0, 0, trtp_rtcp_packet_type_bye, (TRTP_RTCP_HEADER_SIZE + 4)); - TRTP_RTCP_PACKET(bye)->header->rc = 1; - *ssrc_list = ssrc, bye->ssrc_list = ssrc_list, ssrc_list = tsk_null; - } - TSK_FREE(ssrc_list); - return bye; - } - return tsk_null; + uint32_t* ssrc_list = tsk_malloc(sizeof(uint32_t)); + if(ssrc_list) { + trtp_rtcp_report_bye_t* bye; + if((bye = (trtp_rtcp_report_bye_t*)tsk_object_new(trtp_rtcp_report_bye_def_t))) { + trtp_rtcp_packet_init(TRTP_RTCP_PACKET(bye), TRTP_RTCP_HEADER_VERSION_DEFAULT, 0, 0, trtp_rtcp_packet_type_bye, (TRTP_RTCP_HEADER_SIZE + 4)); + TRTP_RTCP_PACKET(bye)->header->rc = 1; + *ssrc_list = ssrc, bye->ssrc_list = ssrc_list, ssrc_list = tsk_null; + } + TSK_FREE(ssrc_list); + return bye; + } + return tsk_null; } trtp_rtcp_report_bye_t* trtp_rtcp_report_bye_deserialize(const void* data, tsk_size_t _size) { - trtp_rtcp_report_bye_t* bye = tsk_null; - trtp_rtcp_header_t* header = tsk_null; - const uint8_t* pdata = (const uint8_t*)data; - int32_t size = (int32_t)_size; - - if(!data || size < TRTP_RTCP_PACKET_BYE_MIN_SIZE){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - if(!(header = trtp_rtcp_header_deserialize(pdata, size))){ - TSK_DEBUG_ERROR("Failed to deserialize the header"); - goto bail; - } - if(header->length_in_bytes < TRTP_RTCP_PACKET_BYE_MIN_SIZE){ - TSK_DEBUG_ERROR("Too short"); - goto bail; - } - - if(!(bye = trtp_rtcp_report_bye_create(header))){ - TSK_DEBUG_ERROR("Failed to create object"); - goto bail; - } - - pdata += (TRTP_RTCP_HEADER_SIZE); - size -= (TRTP_RTCP_HEADER_SIZE); - - // SSRCs - if(header->rc > 0){ - tsk_size_t i; - if((int32_t)(header->rc * sizeof(uint32_t)) > size){ - TSK_DEBUG_ERROR("Too short"); - goto bail; - } - if(!(bye->ssrc_list = tsk_calloc(header->rc, sizeof(uint32_t)))){ - goto bail; - } - for(i = 0; i < header->rc; ++i){ - bye->ssrc_list[i] = (uint32_t)tnet_ntohl_2(&pdata[0]); - pdata += sizeof(uint32_t); - size -= sizeof(uint32_t); - } - } - - // Other Packets - while(size > TRTP_RTCP_HEADER_SIZE){ - trtp_rtcp_packet_t* packet; - - if((packet = trtp_rtcp_packet_deserialize(pdata, size))){ - if((size -= packet->header->length_in_bytes) > 0){ - pdata += packet->header->length_in_bytes; - } - tsk_list_push_back_data(bye->packets, (void**)&packet); - continue; - } - break; - } + trtp_rtcp_report_bye_t* bye = tsk_null; + trtp_rtcp_header_t* header = tsk_null; + const uint8_t* pdata = (const uint8_t*)data; + int32_t size = (int32_t)_size; + + if(!data || size < TRTP_RTCP_PACKET_BYE_MIN_SIZE) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + if(!(header = trtp_rtcp_header_deserialize(pdata, size))) { + TSK_DEBUG_ERROR("Failed to deserialize the header"); + goto bail; + } + if(header->length_in_bytes < TRTP_RTCP_PACKET_BYE_MIN_SIZE) { + TSK_DEBUG_ERROR("Too short"); + goto bail; + } + + if(!(bye = trtp_rtcp_report_bye_create(header))) { + TSK_DEBUG_ERROR("Failed to create object"); + goto bail; + } + + pdata += (TRTP_RTCP_HEADER_SIZE); + size -= (TRTP_RTCP_HEADER_SIZE); + + // SSRCs + if(header->rc > 0) { + tsk_size_t i; + if((int32_t)(header->rc * sizeof(uint32_t)) > size) { + TSK_DEBUG_ERROR("Too short"); + goto bail; + } + if(!(bye->ssrc_list = tsk_calloc(header->rc, sizeof(uint32_t)))) { + goto bail; + } + for(i = 0; i < header->rc; ++i) { + bye->ssrc_list[i] = (uint32_t)tnet_ntohl_2(&pdata[0]); + pdata += sizeof(uint32_t); + size -= sizeof(uint32_t); + } + } + + // Other Packets + while(size > TRTP_RTCP_HEADER_SIZE) { + trtp_rtcp_packet_t* packet; + + if((packet = trtp_rtcp_packet_deserialize(pdata, size))) { + if((size -= packet->header->length_in_bytes) > 0) { + pdata += packet->header->length_in_bytes; + } + tsk_list_push_back_data(bye->packets, (void**)&packet); + continue; + } + break; + } bail: - TSK_OBJECT_SAFE_FREE(header); - return bye; + TSK_OBJECT_SAFE_FREE(header); + return bye; } int trtp_rtcp_report_bye_serialize_to(const trtp_rtcp_report_bye_t* self, void* data, tsk_size_t size) { - int ret; - tsk_size_t i; - uint8_t* pdata = (uint8_t*)data; - const tsk_list_item_t* item; - - if(!self || !data || size < trtp_rtcp_report_bye_get_size(self)){ - return -1; - } - - if((ret = trtp_rtcp_header_serialize_to(TRTP_RTCP_PACKET(self)->header, pdata, size))){ - TSK_DEBUG_ERROR("Failed to serialize the header"); - return ret; - } - - pdata += (TRTP_RTCP_HEADER_SIZE); - size -= (TRTP_RTCP_HEADER_SIZE); - - for(i = 0; i < TRTP_RTCP_PACKET(self)->header->rc; ++i){ - pdata[0] = self->ssrc_list[i] >> 24; - pdata[1] = (self->ssrc_list[i] >> 16) & 0xFF; - pdata[2] = (self->ssrc_list[i] >> 8) & 0xFF; - pdata[3] = (self->ssrc_list[i] & 0xFF); - pdata += 4; - size -= 4; - } - - tsk_list_foreach(item, self->packets){ - if(!item->data){ - continue; - } - if((ret = trtp_rtcp_packet_serialize_to(TRTP_RTCP_PACKET(item->data), pdata, size))){ - TSK_DEBUG_ERROR("Failed to serialize packet"); - goto bail; - } - pdata += TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; - size -= TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; - } + int ret; + tsk_size_t i; + uint8_t* pdata = (uint8_t*)data; + const tsk_list_item_t* item; + + if(!self || !data || size < trtp_rtcp_report_bye_get_size(self)) { + return -1; + } + + if((ret = trtp_rtcp_header_serialize_to(TRTP_RTCP_PACKET(self)->header, pdata, size))) { + TSK_DEBUG_ERROR("Failed to serialize the header"); + return ret; + } + + pdata += (TRTP_RTCP_HEADER_SIZE); + size -= (TRTP_RTCP_HEADER_SIZE); + + for(i = 0; i < TRTP_RTCP_PACKET(self)->header->rc; ++i) { + pdata[0] = self->ssrc_list[i] >> 24; + pdata[1] = (self->ssrc_list[i] >> 16) & 0xFF; + pdata[2] = (self->ssrc_list[i] >> 8) & 0xFF; + pdata[3] = (self->ssrc_list[i] & 0xFF); + pdata += 4; + size -= 4; + } + + tsk_list_foreach(item, self->packets) { + if(!item->data) { + continue; + } + if((ret = trtp_rtcp_packet_serialize_to(TRTP_RTCP_PACKET(item->data), pdata, size))) { + TSK_DEBUG_ERROR("Failed to serialize packet"); + goto bail; + } + pdata += TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; + size -= TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; + } bail: - return ret; + return ret; } tsk_size_t trtp_rtcp_report_bye_get_size(const trtp_rtcp_report_bye_t* self) { - tsk_size_t size; - const tsk_list_item_t* item; - - if(!self || !TRTP_RTCP_PACKET(self)->header){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - - size = TRTP_RTCP_PACKET(self)->header->length_in_bytes; - tsk_list_foreach(item, self->packets){ - if(item->data && TRTP_RTCP_PACKET(item->data)->header){ - size += TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; - } - } - - return size; + tsk_size_t size; + const tsk_list_item_t* item; + + if(!self || !TRTP_RTCP_PACKET(self)->header) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + size = TRTP_RTCP_PACKET(self)->header->length_in_bytes; + tsk_list_foreach(item, self->packets) { + if(item->data && TRTP_RTCP_PACKET(item->data)->header) { + size += TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; + } + } + + return size; } diff --git a/tinyRTP/src/rtcp/trtp_rtcp_report_fb.c b/tinyRTP/src/rtcp/trtp_rtcp_report_fb.c index bbc80b1..bb6690e 100755 --- a/tinyRTP/src/rtcp/trtp_rtcp_report_fb.c +++ b/tinyRTP/src/rtcp/trtp_rtcp_report_fb.c @@ -2,19 +2,19 @@ * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * * Contact: Mamadou Diop <diopmamadou(at)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 WArtpfbANTY; without even the implied wartpfbanty 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. * @@ -35,270 +35,274 @@ static int _trtp_rtcp_report_fb_deserialize(const void* data, tsk_size_t _size, trtp_rtcp_header_t** header, uint32_t* ssrc_sender, uint32_t* ssrc_media_src) { - const uint8_t* pdata = data; - if(!data || !header || _size < TRTP_RTCP_PACKET_FB_MIN_SIZE || (_size & 0x03)){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(!(*header = trtp_rtcp_header_deserialize(pdata, _size))){ - TSK_DEBUG_ERROR("Failed to deserialize the header"); - return -3; - } - if((*header)->length_in_bytes < TRTP_RTCP_PACKET_FB_MIN_SIZE){ - TSK_DEBUG_ERROR("Too short"); - return -4; - } - else if((*header)->length_in_bytes > _size){ - TSK_DEBUG_ERROR("Too long"); - return -5; - } - - *ssrc_sender = (uint32_t)tnet_ntohl_2(&pdata[4]); - *ssrc_media_src = (uint32_t)tnet_ntohl_2(&pdata[8]); - return 0; + const uint8_t* pdata = data; + if(!data || !header || _size < TRTP_RTCP_PACKET_FB_MIN_SIZE || (_size & 0x03)) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(!(*header = trtp_rtcp_header_deserialize(pdata, _size))) { + TSK_DEBUG_ERROR("Failed to deserialize the header"); + return -3; + } + if((*header)->length_in_bytes < TRTP_RTCP_PACKET_FB_MIN_SIZE) { + TSK_DEBUG_ERROR("Too short"); + return -4; + } + else if((*header)->length_in_bytes > _size) { + TSK_DEBUG_ERROR("Too long"); + return -5; + } + + *ssrc_sender = (uint32_t)tnet_ntohl_2(&pdata[4]); + *ssrc_media_src = (uint32_t)tnet_ntohl_2(&pdata[8]); + return 0; } static int _trtp_rtcp_report_fb_serialize_to(const trtp_rtcp_report_fb_t* self, void* data, tsk_size_t size) { - int ret; - uint8_t* pdata = (uint8_t*)data; - - if(!self || !data || size < TRTP_RTCP_PACKET_FB_MIN_SIZE){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if((ret = trtp_rtcp_header_serialize_to(TRTP_RTCP_PACKET(self)->header, pdata, size))){ - TSK_DEBUG_ERROR("Failed to serialize the header"); - return ret; - } - - pdata[TRTP_RTCP_HEADER_SIZE] = self->ssrc_sender >> 24; - pdata[TRTP_RTCP_HEADER_SIZE + 1] = (self->ssrc_sender >> 16) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 2] = (self->ssrc_sender >> 8) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 3] = (self->ssrc_sender & 0xFF); - pdata[TRTP_RTCP_HEADER_SIZE + 4] = self->ssrc_media >> 24; - pdata[TRTP_RTCP_HEADER_SIZE + 5] = (self->ssrc_media >> 16) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 6] = (self->ssrc_media >> 8) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 7] = (self->ssrc_media & 0xFF); - - return 0; + int ret; + uint8_t* pdata = (uint8_t*)data; + + if(!self || !data || size < TRTP_RTCP_PACKET_FB_MIN_SIZE) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if((ret = trtp_rtcp_header_serialize_to(TRTP_RTCP_PACKET(self)->header, pdata, size))) { + TSK_DEBUG_ERROR("Failed to serialize the header"); + return ret; + } + + pdata[TRTP_RTCP_HEADER_SIZE] = self->ssrc_sender >> 24; + pdata[TRTP_RTCP_HEADER_SIZE + 1] = (self->ssrc_sender >> 16) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 2] = (self->ssrc_sender >> 8) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 3] = (self->ssrc_sender & 0xFF); + pdata[TRTP_RTCP_HEADER_SIZE + 4] = self->ssrc_media >> 24; + pdata[TRTP_RTCP_HEADER_SIZE + 5] = (self->ssrc_media >> 16) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 6] = (self->ssrc_media >> 8) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 7] = (self->ssrc_media & 0xFF); + + return 0; } static tsk_object_t* trtp_rtcp_report_rtpfb_ctor(tsk_object_t * self, va_list * app) { - trtp_rtcp_report_rtpfb_t *rtpfb = self; - if(rtpfb){ - - } - return self; + trtp_rtcp_report_rtpfb_t *rtpfb = self; + if(rtpfb) { + + } + return self; } static tsk_object_t* trtp_rtcp_report_rtpfb_dtor(tsk_object_t * self) -{ - trtp_rtcp_report_rtpfb_t *rtpfb = self; - if(rtpfb){ - // deinit self - switch(rtpfb->fci_type){ - case trtp_rtcp_rtpfb_fci_type_nack: - { - TSK_FREE(rtpfb->nack.pid); - TSK_FREE(rtpfb->nack.blp); - break; - } - case trtp_rtcp_rtpfb_fci_type_tmmbn: - { - TSK_FREE(rtpfb->tmmbn.ssrc); - TSK_FREE(rtpfb->tmmbn.MxTBR_Exp); - TSK_FREE(rtpfb->tmmbn.MxTBR_Mantissa); - TSK_FREE(rtpfb->tmmbn.MeasuredOverhead); - break; - } - } - // deinit base - trtp_rtcp_packet_deinit(TRTP_RTCP_PACKET(rtpfb)); - } - - return self; -} -static const tsk_object_def_t trtp_rtcp_report_rtpfb_def_s = { - sizeof(trtp_rtcp_report_rtpfb_t), - trtp_rtcp_report_rtpfb_ctor, - trtp_rtcp_report_rtpfb_dtor, - tsk_null, + trtp_rtcp_report_rtpfb_t *rtpfb = self; + if(rtpfb) { + // deinit self + switch(rtpfb->fci_type) { + case trtp_rtcp_rtpfb_fci_type_nack: { + TSK_FREE(rtpfb->nack.pid); + TSK_FREE(rtpfb->nack.blp); + break; + } + case trtp_rtcp_rtpfb_fci_type_tmmbn: { + TSK_FREE(rtpfb->tmmbn.ssrc); + TSK_FREE(rtpfb->tmmbn.MxTBR_Exp); + TSK_FREE(rtpfb->tmmbn.MxTBR_Mantissa); + TSK_FREE(rtpfb->tmmbn.MeasuredOverhead); + break; + } + } + // deinit base + trtp_rtcp_packet_deinit(TRTP_RTCP_PACKET(rtpfb)); + } + + return self; +} +static const tsk_object_def_t trtp_rtcp_report_rtpfb_def_s = { + sizeof(trtp_rtcp_report_rtpfb_t), + trtp_rtcp_report_rtpfb_ctor, + trtp_rtcp_report_rtpfb_dtor, + tsk_null, }; const tsk_object_def_t *trtp_rtcp_report_rtpfb_def_t = &trtp_rtcp_report_rtpfb_def_s; trtp_rtcp_report_rtpfb_t* trtp_rtcp_report_rtpfb_create_null() { - trtp_rtcp_report_rtpfb_t* rtpfb; - if((rtpfb = (trtp_rtcp_report_rtpfb_t*)tsk_object_new(trtp_rtcp_report_rtpfb_def_t))){ - trtp_rtcp_packet_init(TRTP_RTCP_PACKET(rtpfb), TRTP_RTCP_HEADER_VERSION_DEFAULT, 0, 0, trtp_rtcp_packet_type_rtpfb, TRTP_RTCP_PACKET_FB_MIN_SIZE); - } - return rtpfb; + trtp_rtcp_report_rtpfb_t* rtpfb; + if((rtpfb = (trtp_rtcp_report_rtpfb_t*)tsk_object_new(trtp_rtcp_report_rtpfb_def_t))) { + trtp_rtcp_packet_init(TRTP_RTCP_PACKET(rtpfb), TRTP_RTCP_HEADER_VERSION_DEFAULT, 0, 0, trtp_rtcp_packet_type_rtpfb, TRTP_RTCP_PACKET_FB_MIN_SIZE); + } + return rtpfb; } trtp_rtcp_report_rtpfb_t* trtp_rtcp_report_rtpfb_create(trtp_rtcp_header_t* header) { - trtp_rtcp_report_rtpfb_t* rtpfb; - if((rtpfb = (trtp_rtcp_report_rtpfb_t*)tsk_object_new(trtp_rtcp_report_rtpfb_def_t))){ - TRTP_RTCP_PACKET(rtpfb)->header = tsk_object_ref(header); - } - return rtpfb; + trtp_rtcp_report_rtpfb_t* rtpfb; + if((rtpfb = (trtp_rtcp_report_rtpfb_t*)tsk_object_new(trtp_rtcp_report_rtpfb_def_t))) { + TRTP_RTCP_PACKET(rtpfb)->header = tsk_object_ref(header); + } + return rtpfb; } trtp_rtcp_report_rtpfb_t* trtp_rtcp_report_rtpfb_create_2(trtp_rtcp_rtpfb_fci_type_t fci_type, uint32_t ssrc_sender, uint32_t ssrc_media_src) { - trtp_rtcp_report_rtpfb_t* rtpfb; - if((rtpfb = trtp_rtcp_report_rtpfb_create_null())){ - rtpfb->fci_type = TRTP_RTCP_PACKET(rtpfb)->header->rc = fci_type; - TRTP_RTCP_REPORT_FB(rtpfb)->ssrc_sender = ssrc_sender; - TRTP_RTCP_REPORT_FB(rtpfb)->ssrc_media = ssrc_media_src; - } - return rtpfb; + trtp_rtcp_report_rtpfb_t* rtpfb; + if((rtpfb = trtp_rtcp_report_rtpfb_create_null())) { + rtpfb->fci_type = TRTP_RTCP_PACKET(rtpfb)->header->rc = fci_type; + TRTP_RTCP_REPORT_FB(rtpfb)->ssrc_sender = ssrc_sender; + TRTP_RTCP_REPORT_FB(rtpfb)->ssrc_media = ssrc_media_src; + } + return rtpfb; } // seq_nums[n] must be in [seq_nums[0], seq_nums[0] + 16] and > seq_nums[n - 1] trtp_rtcp_report_rtpfb_t* trtp_rtcp_report_rtpfb_create_nack(uint32_t ssrc_sender, uint32_t ssrc_media_src, const uint16_t* seq_nums, tsk_size_t count) { - trtp_rtcp_report_rtpfb_t* rtpfb; - if(!seq_nums || !count){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - if((rtpfb = trtp_rtcp_report_rtpfb_create_2(trtp_rtcp_rtpfb_fci_type_nack, ssrc_sender, ssrc_media_src))){ - tsk_size_t i, j; - rtpfb->nack.count = 1; // max = 16 - rtpfb->nack.blp = tsk_malloc(sizeof(uint16_t)); - rtpfb->nack.pid = tsk_malloc(sizeof(uint16_t)); - if(!rtpfb->nack.blp || !rtpfb->nack.pid){ - TSK_OBJECT_SAFE_FREE(rtpfb); - return tsk_null; - } - rtpfb->nack.pid[0] = seq_nums[0]; - rtpfb->nack.blp[0] = 0; - for(i = 1; i <= 16 && i < count; ++i){ - j = seq_nums[i] - rtpfb->nack.pid[0]; - rtpfb->nack.blp[0] |= (1 << (j - 1)); - } - - TRTP_RTCP_PACKET(rtpfb)->header->length_in_bytes += (uint32_t)(rtpfb->nack.count << 2); - TRTP_RTCP_PACKET(rtpfb)->header->length_in_words_minus1 = ((TRTP_RTCP_PACKET(rtpfb)->header->length_in_bytes >> 2) - 1); - } - return rtpfb; + trtp_rtcp_report_rtpfb_t* rtpfb; + if(!seq_nums || !count) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + if((rtpfb = trtp_rtcp_report_rtpfb_create_2(trtp_rtcp_rtpfb_fci_type_nack, ssrc_sender, ssrc_media_src))) { + tsk_size_t i, j; + rtpfb->nack.count = 1; // max = 16 + rtpfb->nack.blp = tsk_malloc(sizeof(uint16_t)); + rtpfb->nack.pid = tsk_malloc(sizeof(uint16_t)); + if(!rtpfb->nack.blp || !rtpfb->nack.pid) { + TSK_OBJECT_SAFE_FREE(rtpfb); + return tsk_null; + } + rtpfb->nack.pid[0] = seq_nums[0]; + rtpfb->nack.blp[0] = 0; + for(i = 1; i <= 16 && i < count; ++i) { + j = seq_nums[i] - rtpfb->nack.pid[0]; + rtpfb->nack.blp[0] |= (1 << (j - 1)); + } + + TRTP_RTCP_PACKET(rtpfb)->header->length_in_bytes += (uint32_t)(rtpfb->nack.count << 2); + TRTP_RTCP_PACKET(rtpfb)->header->length_in_words_minus1 = ((TRTP_RTCP_PACKET(rtpfb)->header->length_in_bytes >> 2) - 1); + } + return rtpfb; } trtp_rtcp_report_rtpfb_t* trtp_rtcp_report_rtpfb_deserialize(const void* data, tsk_size_t _size) { - trtp_rtcp_report_rtpfb_t* rtpfb = tsk_null; - trtp_rtcp_header_t* header = tsk_null; - uint32_t ssrc_sender, ssrc_media_src; - - if(_trtp_rtcp_report_fb_deserialize(data, _size, &header, &ssrc_sender, &ssrc_media_src) == 0){ - if((rtpfb = trtp_rtcp_report_rtpfb_create(header))){ - const uint8_t* pdata = ((const uint8_t*)data) + TRTP_RTCP_PACKET_FB_MIN_SIZE; - tsk_size_t size = (header->length_in_bytes - TRTP_RTCP_PACKET_FB_MIN_SIZE), i; - - TRTP_RTCP_REPORT_FB(rtpfb)->ssrc_sender = ssrc_sender; - TRTP_RTCP_REPORT_FB(rtpfb)->ssrc_media = ssrc_media_src; - - switch(rtpfb->fci_type = (trtp_rtcp_rtpfb_fci_type_t)header->rc){ - case trtp_rtcp_rtpfb_fci_type_nack: - { - if((rtpfb->nack.count = (size >> 2)) > 0){ - rtpfb->nack.pid = tsk_realloc(rtpfb->nack.pid, (rtpfb->nack.count * sizeof(uint16_t))); - rtpfb->nack.blp = tsk_realloc(rtpfb->nack.blp, (rtpfb->nack.count * sizeof(uint16_t))); - for(i = 0; i < rtpfb->nack.count; ++i){ - if(rtpfb->nack.pid) rtpfb->nack.pid[i] = tnet_ntohs_2(&pdata[0]); - if(rtpfb->nack.blp) rtpfb->nack.blp[i] = tnet_ntohs_2(&pdata[2]); - pdata += 4; - } - } - break; - } - case trtp_rtcp_rtpfb_fci_type_tmmbn: - { - TSK_DEBUG_INFO("TMMBN"); - if((rtpfb->tmmbn.count = (size >> 3)) > 0){ - uint32_t u32; - rtpfb->tmmbn.ssrc = tsk_realloc(rtpfb->tmmbn.ssrc, (rtpfb->tmmbn.count * sizeof(uint32_t))); - rtpfb->tmmbn.MxTBR_Exp = tsk_realloc(rtpfb->tmmbn.MxTBR_Exp, (rtpfb->tmmbn.count * sizeof(uint16_t))); - rtpfb->tmmbn.MxTBR_Mantissa = tsk_realloc(rtpfb->tmmbn.MxTBR_Mantissa, (rtpfb->tmmbn.count * sizeof(uint32_t))); - rtpfb->tmmbn.MeasuredOverhead = tsk_realloc(rtpfb->tmmbn.MeasuredOverhead, (rtpfb->tmmbn.count * sizeof(uint16_t))); - for(i = 0; i < rtpfb->tmmbn.count; ++i){ - if(rtpfb->tmmbn.ssrc) rtpfb->tmmbn.ssrc[i] = (uint32_t)tnet_ntohl_2(&pdata[0]); - u32 = (uint32_t)tnet_ntohl_2(&pdata[4]); - if(rtpfb->tmmbn.MxTBR_Exp) rtpfb->tmmbn.MxTBR_Exp[i] = (u32 >> 26); - if(rtpfb->tmmbn.MxTBR_Mantissa) rtpfb->tmmbn.MxTBR_Mantissa[i] = ((u32 >> 9) & 0x1FFFF); - if(rtpfb->tmmbn.MeasuredOverhead) rtpfb->tmmbn.MeasuredOverhead[i] = (u32 & 0x1FF); - pdata += 8; - } - } - break; - } - - default: - { - TSK_DEBUG_ERROR("Unsupported Feedback message type %d", (int)rtpfb->fci_type); - break; - } - } - } - } - - TSK_OBJECT_SAFE_FREE(header); - return rtpfb; + trtp_rtcp_report_rtpfb_t* rtpfb = tsk_null; + trtp_rtcp_header_t* header = tsk_null; + uint32_t ssrc_sender, ssrc_media_src; + + if(_trtp_rtcp_report_fb_deserialize(data, _size, &header, &ssrc_sender, &ssrc_media_src) == 0) { + if((rtpfb = trtp_rtcp_report_rtpfb_create(header))) { + const uint8_t* pdata = ((const uint8_t*)data) + TRTP_RTCP_PACKET_FB_MIN_SIZE; + tsk_size_t size = (header->length_in_bytes - TRTP_RTCP_PACKET_FB_MIN_SIZE), i; + + TRTP_RTCP_REPORT_FB(rtpfb)->ssrc_sender = ssrc_sender; + TRTP_RTCP_REPORT_FB(rtpfb)->ssrc_media = ssrc_media_src; + + switch(rtpfb->fci_type = (trtp_rtcp_rtpfb_fci_type_t)header->rc) { + case trtp_rtcp_rtpfb_fci_type_nack: { + if((rtpfb->nack.count = (size >> 2)) > 0) { + rtpfb->nack.pid = tsk_realloc(rtpfb->nack.pid, (rtpfb->nack.count * sizeof(uint16_t))); + rtpfb->nack.blp = tsk_realloc(rtpfb->nack.blp, (rtpfb->nack.count * sizeof(uint16_t))); + for(i = 0; i < rtpfb->nack.count; ++i) { + if(rtpfb->nack.pid) { + rtpfb->nack.pid[i] = tnet_ntohs_2(&pdata[0]); + } + if(rtpfb->nack.blp) { + rtpfb->nack.blp[i] = tnet_ntohs_2(&pdata[2]); + } + pdata += 4; + } + } + break; + } + case trtp_rtcp_rtpfb_fci_type_tmmbn: { + TSK_DEBUG_INFO("TMMBN"); + if((rtpfb->tmmbn.count = (size >> 3)) > 0) { + uint32_t u32; + rtpfb->tmmbn.ssrc = tsk_realloc(rtpfb->tmmbn.ssrc, (rtpfb->tmmbn.count * sizeof(uint32_t))); + rtpfb->tmmbn.MxTBR_Exp = tsk_realloc(rtpfb->tmmbn.MxTBR_Exp, (rtpfb->tmmbn.count * sizeof(uint16_t))); + rtpfb->tmmbn.MxTBR_Mantissa = tsk_realloc(rtpfb->tmmbn.MxTBR_Mantissa, (rtpfb->tmmbn.count * sizeof(uint32_t))); + rtpfb->tmmbn.MeasuredOverhead = tsk_realloc(rtpfb->tmmbn.MeasuredOverhead, (rtpfb->tmmbn.count * sizeof(uint16_t))); + for(i = 0; i < rtpfb->tmmbn.count; ++i) { + if(rtpfb->tmmbn.ssrc) { + rtpfb->tmmbn.ssrc[i] = (uint32_t)tnet_ntohl_2(&pdata[0]); + } + u32 = (uint32_t)tnet_ntohl_2(&pdata[4]); + if(rtpfb->tmmbn.MxTBR_Exp) { + rtpfb->tmmbn.MxTBR_Exp[i] = (u32 >> 26); + } + if(rtpfb->tmmbn.MxTBR_Mantissa) { + rtpfb->tmmbn.MxTBR_Mantissa[i] = ((u32 >> 9) & 0x1FFFF); + } + if(rtpfb->tmmbn.MeasuredOverhead) { + rtpfb->tmmbn.MeasuredOverhead[i] = (u32 & 0x1FF); + } + pdata += 8; + } + } + break; + } + + default: { + TSK_DEBUG_ERROR("Unsupported Feedback message type %d", (int)rtpfb->fci_type); + break; + } + } + } + } + + TSK_OBJECT_SAFE_FREE(header); + return rtpfb; } int trtp_rtcp_report_rtpfb_serialize_to(const trtp_rtcp_report_rtpfb_t* self, void* data, tsk_size_t size) { - int ret; - uint8_t* pdata = (uint8_t*)data; - - if(!self || !data || size < trtp_rtcp_report_rtpfb_get_size(self)){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if((ret = _trtp_rtcp_report_fb_serialize_to(TRTP_RTCP_REPORT_FB(self), pdata, size))){ - TSK_DEBUG_ERROR("Failed to serialize FB message"); - return ret; - } - pdata += TRTP_RTCP_PACKET_FB_MIN_SIZE; - size -= TRTP_RTCP_PACKET_FB_MIN_SIZE; - - switch(self->fci_type){ - case trtp_rtcp_rtpfb_fci_type_nack: - { - tsk_size_t i; - for(i = 0; i < self->nack.count; ++i){ - pdata[0] = self->nack.pid[i] >> 8; - pdata[1] = (self->nack.pid[i] & 0xFF); - pdata[2] = self->nack.blp[i] >> 8; - pdata[3] = (self->nack.blp[i] & 0xFF); - pdata += 4; - } - break; - } - default: - { - TSK_DEBUG_ERROR("Not implemented"); - return -2; - } - } - return 0; + int ret; + uint8_t* pdata = (uint8_t*)data; + + if(!self || !data || size < trtp_rtcp_report_rtpfb_get_size(self)) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if((ret = _trtp_rtcp_report_fb_serialize_to(TRTP_RTCP_REPORT_FB(self), pdata, size))) { + TSK_DEBUG_ERROR("Failed to serialize FB message"); + return ret; + } + pdata += TRTP_RTCP_PACKET_FB_MIN_SIZE; + size -= TRTP_RTCP_PACKET_FB_MIN_SIZE; + + switch(self->fci_type) { + case trtp_rtcp_rtpfb_fci_type_nack: { + tsk_size_t i; + for(i = 0; i < self->nack.count; ++i) { + pdata[0] = self->nack.pid[i] >> 8; + pdata[1] = (self->nack.pid[i] & 0xFF); + pdata[2] = self->nack.blp[i] >> 8; + pdata[3] = (self->nack.blp[i] & 0xFF); + pdata += 4; + } + break; + } + default: { + TSK_DEBUG_ERROR("Not implemented"); + return -2; + } + } + return 0; } tsk_size_t trtp_rtcp_report_rtpfb_get_size(const trtp_rtcp_report_rtpfb_t* self) { - if(!self || !TRTP_RTCP_PACKET(self)->header){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - return TRTP_RTCP_PACKET(self)->header->length_in_bytes; + if(!self || !TRTP_RTCP_PACKET(self)->header) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + return TRTP_RTCP_PACKET(self)->header->length_in_bytes; } @@ -311,341 +315,406 @@ tsk_size_t trtp_rtcp_report_rtpfb_get_size(const trtp_rtcp_report_rtpfb_t* self) static tsk_object_t* trtp_rtcp_report_psfb_ctor(tsk_object_t * self, va_list * app) { - trtp_rtcp_report_psfb_t *psfb = self; - if(psfb){ - - } - return self; + trtp_rtcp_report_psfb_t *psfb = self; + if(psfb) { + + } + return self; } static tsk_object_t* trtp_rtcp_report_psfb_dtor(tsk_object_t * self) -{ - trtp_rtcp_report_psfb_t *psfb = self; - if(psfb){ - // deinit self - switch(psfb->fci_type){ - case trtp_rtcp_psfb_fci_type_pli: - break; - case trtp_rtcp_psfb_fci_type_sli: - TSK_FREE(psfb->sli.first); - TSK_FREE(psfb->sli.number); - TSK_FREE(psfb->sli.pic_id); - break; - case trtp_rtcp_psfb_fci_type_rpsi: - TSK_FREE(psfb->rpsi.bytes); - break; - case trtp_rtcp_psfb_fci_type_fir: - TSK_FREE(psfb->fir.ssrc); - TSK_FREE(psfb->fir.seq_num); - break; - case trtp_rtcp_psfb_fci_type_afb: - switch(psfb->afb.type){ - case trtp_rtcp_psfb_afb_type_none: - TSK_FREE(psfb->afb.none.bytes); - break; - case trtp_rtcp_psfb_afb_type_remb: - TSK_FREE(psfb->afb.remb.ssrc_feedbacks); - break; - } - break; - } - // deinit base - trtp_rtcp_packet_deinit(TRTP_RTCP_PACKET(psfb)); - } - - return self; -} -static const tsk_object_def_t trtp_rtcp_report_psfb_def_s = { - sizeof(trtp_rtcp_report_psfb_t), - trtp_rtcp_report_psfb_ctor, - trtp_rtcp_report_psfb_dtor, - tsk_null, + trtp_rtcp_report_psfb_t *psfb = self; + if(psfb) { + // deinit self + switch(psfb->fci_type) { + case trtp_rtcp_psfb_fci_type_pli: + break; + case trtp_rtcp_psfb_fci_type_sli: + TSK_FREE(psfb->sli.first); + TSK_FREE(psfb->sli.number); + TSK_FREE(psfb->sli.pic_id); + break; + case trtp_rtcp_psfb_fci_type_rpsi: + TSK_FREE(psfb->rpsi.bytes); + break; + case trtp_rtcp_psfb_fci_type_fir: + TSK_FREE(psfb->fir.ssrc); + TSK_FREE(psfb->fir.seq_num); + break; + case trtp_rtcp_psfb_fci_type_afb: + switch(psfb->afb.type) { + case trtp_rtcp_psfb_afb_type_none: + TSK_FREE(psfb->afb.none.bytes); + break; + case trtp_rtcp_psfb_afb_type_remb: + TSK_FREE(psfb->afb.remb.ssrc_feedbacks); + break; + case trtp_rtcp_psfb_afb_type_jcng: + TSK_FREE(psfb->afb.jcng.ssrc_feedbacks); + break; + } + break; + } + // deinit base + trtp_rtcp_packet_deinit(TRTP_RTCP_PACKET(psfb)); + } + + return self; +} +static const tsk_object_def_t trtp_rtcp_report_psfb_def_s = { + sizeof(trtp_rtcp_report_psfb_t), + trtp_rtcp_report_psfb_ctor, + trtp_rtcp_report_psfb_dtor, + tsk_null, }; const tsk_object_def_t *trtp_rtcp_report_psfb_def_t = &trtp_rtcp_report_psfb_def_s; trtp_rtcp_report_psfb_t* trtp_rtcp_report_psfb_create_null() { - trtp_rtcp_report_psfb_t* psfb; - if((psfb = (trtp_rtcp_report_psfb_t*)tsk_object_new(trtp_rtcp_report_psfb_def_t))){ - trtp_rtcp_packet_init(TRTP_RTCP_PACKET(psfb), TRTP_RTCP_HEADER_VERSION_DEFAULT, 0, 0, trtp_rtcp_packet_type_psfb, TRTP_RTCP_PACKET_FB_MIN_SIZE); - } - return psfb; + trtp_rtcp_report_psfb_t* psfb; + if ((psfb = (trtp_rtcp_report_psfb_t*)tsk_object_new(trtp_rtcp_report_psfb_def_t))) { + trtp_rtcp_packet_init(TRTP_RTCP_PACKET(psfb), TRTP_RTCP_HEADER_VERSION_DEFAULT, 0, 0, trtp_rtcp_packet_type_psfb, TRTP_RTCP_PACKET_FB_MIN_SIZE); + } + return psfb; } trtp_rtcp_report_psfb_t* trtp_rtcp_report_psfb_create(trtp_rtcp_header_t* header) { - trtp_rtcp_report_psfb_t* psfb; - if((psfb = (trtp_rtcp_report_psfb_t*)tsk_object_new(trtp_rtcp_report_psfb_def_t))){ - TRTP_RTCP_PACKET(psfb)->header = tsk_object_ref(header); - } - return psfb; + trtp_rtcp_report_psfb_t* psfb; + if ((psfb = (trtp_rtcp_report_psfb_t*)tsk_object_new(trtp_rtcp_report_psfb_def_t))) { + TRTP_RTCP_PACKET(psfb)->header = tsk_object_ref(header); + } + return psfb; } trtp_rtcp_report_psfb_t* trtp_rtcp_report_psfb_create_2(trtp_rtcp_psfb_fci_type_t fci_type, uint32_t ssrc_sender, uint32_t ssrc_media_src) { - trtp_rtcp_report_psfb_t* psfb; - if((psfb = trtp_rtcp_report_psfb_create_null())){ - TRTP_RTCP_PACKET(psfb)->header->rc = psfb->fci_type = fci_type; - TRTP_RTCP_REPORT_FB(psfb)->ssrc_sender = ssrc_sender; - TRTP_RTCP_REPORT_FB(psfb)->ssrc_media = ssrc_media_src; - } - return psfb; + trtp_rtcp_report_psfb_t* psfb; + if ((psfb = trtp_rtcp_report_psfb_create_null())) { + TRTP_RTCP_PACKET(psfb)->header->rc = psfb->fci_type = fci_type; + TRTP_RTCP_REPORT_FB(psfb)->ssrc_sender = ssrc_sender; + TRTP_RTCP_REPORT_FB(psfb)->ssrc_media = ssrc_media_src; + } + return psfb; } trtp_rtcp_report_psfb_t* trtp_rtcp_report_psfb_create_pli(uint32_t ssrc_sender, uint32_t ssrc_media_src) { - return trtp_rtcp_report_psfb_create_2(trtp_rtcp_psfb_fci_type_pli, ssrc_sender, ssrc_media_src); + return trtp_rtcp_report_psfb_create_2(trtp_rtcp_psfb_fci_type_pli, ssrc_sender, ssrc_media_src); } trtp_rtcp_report_psfb_t* trtp_rtcp_report_psfb_create_fir(uint8_t seq_num, uint32_t ssrc_sender, uint32_t ssrc_media_src) { - trtp_rtcp_report_psfb_t* psfb; - if((psfb = trtp_rtcp_report_psfb_create_2(trtp_rtcp_psfb_fci_type_fir, ssrc_sender, ssrc_media_src))){ - psfb->fir.ssrc = tsk_malloc(sizeof(uint32_t)); - psfb->fir.seq_num = tsk_malloc(sizeof(uint8_t)); - if(!psfb->fir.ssrc || !psfb->fir.seq_num){ - TSK_OBJECT_SAFE_FREE(psfb); - return tsk_null; - } - psfb->fir.count = 1; - psfb->fir.seq_num[0] = seq_num; - psfb->fir.ssrc[0] = ssrc_media_src; - TRTP_RTCP_PACKET(psfb)->header->length_in_bytes += (uint32_t)(psfb->fir.count << 3); - TRTP_RTCP_PACKET(psfb)->header->length_in_words_minus1 = ((TRTP_RTCP_PACKET(psfb)->header->length_in_bytes >> 2) - 1); - } - return psfb; + trtp_rtcp_report_psfb_t* psfb; + if ((psfb = trtp_rtcp_report_psfb_create_2(trtp_rtcp_psfb_fci_type_fir, ssrc_sender, ssrc_media_src))) { + psfb->fir.ssrc = tsk_malloc(sizeof(uint32_t)); + psfb->fir.seq_num = tsk_malloc(sizeof(uint8_t)); + if (!psfb->fir.ssrc || !psfb->fir.seq_num) { + TSK_OBJECT_SAFE_FREE(psfb); + return tsk_null; + } + psfb->fir.count = 1; + psfb->fir.seq_num[0] = seq_num; + psfb->fir.ssrc[0] = ssrc_media_src; + TRTP_RTCP_PACKET(psfb)->header->length_in_bytes += (uint32_t)(psfb->fir.count << 3); + TRTP_RTCP_PACKET(psfb)->header->length_in_words_minus1 = ((TRTP_RTCP_PACKET(psfb)->header->length_in_bytes >> 2) - 1); + } + return psfb; } trtp_rtcp_report_psfb_t* trtp_rtcp_report_psfb_create_afb_remb(uint32_t ssrc_sender, const uint32_t* ssrc_media_src_list, uint32_t ssrc_media_src_list_count, uint32_t bitrate/*in bps*/) { - trtp_rtcp_report_psfb_t* psfb; - // draft-alvestrand-rmcat-remb-02 2.2: SSRC media source always equal to zero - if((psfb = trtp_rtcp_report_psfb_create_2(trtp_rtcp_psfb_fci_type_afb, ssrc_sender, 0))){ - static const uint32_t __max_mantissa = 131072; - psfb->afb.type = trtp_rtcp_psfb_afb_type_remb; - psfb->afb.remb.exp = 0; - if(bitrate <= __max_mantissa){ - psfb->afb.remb.mantissa = bitrate; - } - else{ - while(bitrate >= (__max_mantissa << psfb->afb.remb.exp) && psfb->afb.remb.exp < 63) ++psfb->afb.remb.exp; - psfb->afb.remb.mantissa = (bitrate >> psfb->afb.remb.exp); - } - if(ssrc_media_src_list && ssrc_media_src_list_count > 0 && (psfb->afb.remb.ssrc_feedbacks = (uint32_t*)tsk_malloc(ssrc_media_src_list_count << 2))){ - uint32_t i; - psfb->afb.remb.num_ssrc = ssrc_media_src_list_count; - for(i = 0; i < ssrc_media_src_list_count; ++i){ - psfb->afb.remb.ssrc_feedbacks[i] = ssrc_media_src_list[i]; - } - } - TRTP_RTCP_PACKET(psfb)->header->length_in_bytes += 8; /*'R' 'E' 'M' 'B', Num SSRC, BR Exp, BR Mantissa */ - TRTP_RTCP_PACKET(psfb)->header->length_in_bytes += (psfb->afb.remb.num_ssrc << 2); - TRTP_RTCP_PACKET(psfb)->header->length_in_words_minus1 = ((TRTP_RTCP_PACKET(psfb)->header->length_in_bytes >> 2) - 1); - } - return psfb; + trtp_rtcp_report_psfb_t* psfb; + // draft-alvestrand-rmcat-remb-02 2.2: SSRC media source always equal to zero + if ((psfb = trtp_rtcp_report_psfb_create_2(trtp_rtcp_psfb_fci_type_afb, ssrc_sender, 0))) { + static const uint32_t __max_mantissa = 131072; + psfb->afb.type = trtp_rtcp_psfb_afb_type_remb; + psfb->afb.remb.exp = 0; + if (bitrate <= __max_mantissa) { + psfb->afb.remb.mantissa = bitrate; + } + else { + while (bitrate >= (__max_mantissa << psfb->afb.remb.exp) && psfb->afb.remb.exp < 63) { + ++psfb->afb.remb.exp; + } + psfb->afb.remb.mantissa = (bitrate >> psfb->afb.remb.exp); + } + if (ssrc_media_src_list && ssrc_media_src_list_count > 0 && (psfb->afb.remb.ssrc_feedbacks = (uint32_t*)tsk_malloc(ssrc_media_src_list_count << 2))) { + uint32_t i; + psfb->afb.remb.num_ssrc = ssrc_media_src_list_count; + for (i = 0; i < ssrc_media_src_list_count; ++i) { + psfb->afb.remb.ssrc_feedbacks[i] = ssrc_media_src_list[i]; + } + } + TRTP_RTCP_PACKET(psfb)->header->length_in_bytes += 8; /*'R' 'E' 'M' 'B', Num SSRC, BR Exp, BR Mantissa */ + TRTP_RTCP_PACKET(psfb)->header->length_in_bytes += (psfb->afb.remb.num_ssrc << 2); + TRTP_RTCP_PACKET(psfb)->header->length_in_words_minus1 = ((TRTP_RTCP_PACKET(psfb)->header->length_in_bytes >> 2) - 1); + } + return psfb; +} + +trtp_rtcp_report_psfb_t* trtp_rtcp_report_psfb_create_afb_jcng(uint32_t ssrc_sender, const uint32_t* ssrc_media_src_list, uint32_t ssrc_media_src_list_count, float jcng_q/*in quality metric*/) +{ + trtp_rtcp_report_psfb_t* psfb; + // SSRC media source always equal to zero + if ((psfb = trtp_rtcp_report_psfb_create_2(trtp_rtcp_psfb_fci_type_afb, ssrc_sender, 0))) { + psfb->afb.type = trtp_rtcp_psfb_afb_type_jcng; + psfb->afb.jcng.q = (uint8_t)(jcng_q * 255.f); + if (ssrc_media_src_list && ssrc_media_src_list_count > 0 && (psfb->afb.jcng.ssrc_feedbacks = (uint32_t*)tsk_malloc(ssrc_media_src_list_count << 2))) { + uint32_t i; + psfb->afb.jcng.num_ssrc = ssrc_media_src_list_count; + for (i = 0; i < ssrc_media_src_list_count; ++i) { + psfb->afb.jcng.ssrc_feedbacks[i] = ssrc_media_src_list[i]; + } + } + TRTP_RTCP_PACKET(psfb)->header->length_in_bytes += 8; /*'J' 'C' 'N' 'G', Num SSRC, Q, Reserverd */ + TRTP_RTCP_PACKET(psfb)->header->length_in_bytes += (psfb->afb.jcng.num_ssrc << 2); + TRTP_RTCP_PACKET(psfb)->header->length_in_words_minus1 = ((TRTP_RTCP_PACKET(psfb)->header->length_in_bytes >> 2) - 1); + } + return psfb; } trtp_rtcp_report_psfb_t* trtp_rtcp_report_psfb_deserialize(const void* data, tsk_size_t _size) { - trtp_rtcp_report_psfb_t* psfb = tsk_null; - trtp_rtcp_header_t* header = tsk_null; - uint32_t ssrc_sender, ssrc_media_src; - - if(_trtp_rtcp_report_fb_deserialize(data, _size, &header, &ssrc_sender, &ssrc_media_src) == 0){ - if((psfb = trtp_rtcp_report_psfb_create(header))){ - const uint8_t* pdata = ((const uint8_t*)data) + TRTP_RTCP_PACKET_FB_MIN_SIZE; - tsk_size_t size = (header->length_in_bytes - TRTP_RTCP_PACKET_FB_MIN_SIZE); - - TRTP_RTCP_REPORT_FB(psfb)->ssrc_sender = ssrc_sender; - TRTP_RTCP_REPORT_FB(psfb)->ssrc_media = ssrc_media_src; - - switch((psfb->fci_type = header->rc)/* FMT for RTCP-FB messages */){ - case trtp_rtcp_psfb_fci_type_pli: - { - // No FCI in PLI - // TSK_DEBUG_INFO("PLI"); - break; - } - case trtp_rtcp_psfb_fci_type_sli: - { - tsk_size_t sli_count = (size >> 2), i; - uint32_t u32; - if(sli_count == 0){ - TSK_DEBUG_ERROR("Too short"); - goto bail; - } - psfb->sli.first = tsk_realloc(psfb->sli.first, (sli_count * sizeof(uint16_t))); - psfb->sli.number = tsk_realloc(psfb->sli.number, (sli_count * sizeof(uint16_t))); - psfb->sli.pic_id = tsk_realloc(psfb->sli.pic_id, (sli_count * sizeof(uint16_t))); - for(i = 0; i < sli_count; ++i){ - u32 = (uint32_t)tnet_ntohl_2(&pdata[i >> 2]); - if(psfb->sli.first) psfb->sli.first[i] = (u32 >> 19); - if(psfb->sli.number) psfb->sli.number[i] = (u32 >> 6) & 0x1FFF; - if(psfb->sli.pic_id) psfb->sli.pic_id[i] = u32 & 0x3F; - } - - break; - } - case trtp_rtcp_psfb_fci_type_rpsi: - { - uint16_t u16; - if(size < 2){ - TSK_DEBUG_ERROR("Too short"); - goto bail; - } - u16 = tnet_ntohs_2(&pdata[0]); - psfb->rpsi.pb = (u16 >> 8); - psfb->rpsi.pt = (u16 & 0x7F); - if((psfb->rpsi.bytes = tsk_calloc((size - 2), sizeof(uint8_t)))){ - memcpy(psfb->rpsi.bytes, &pdata[2], (size - 2)); - } - break; - } - case trtp_rtcp_psfb_fci_type_fir: - { - tsk_size_t fir_count = (size >> 3), i; - if(fir_count == 0){ - TSK_DEBUG_ERROR("Too short"); - goto bail; - } - psfb->fir.count = fir_count; - psfb->fir.ssrc = tsk_realloc(psfb->fir.seq_num, (fir_count * sizeof(uint32_t))); - psfb->fir.seq_num = tsk_realloc(psfb->fir.seq_num, (fir_count * sizeof(uint8_t))); - for(i = 0; i < fir_count; ++i){ - if(psfb->fir.ssrc) psfb->fir.ssrc[i] = (uint32_t)tnet_ntohl_2(&pdata[0]); - if(psfb->fir.seq_num) psfb->fir.seq_num[i] = pdata[4]; - pdata+=8; - } - break; - } - case trtp_rtcp_psfb_fci_type_afb: - { - if(size > 0){ - psfb->afb.type = trtp_rtcp_psfb_afb_type_none; - // REMB (http://tools.ietf.org/html/draft-alvestrand-rmcat-remb-02) ? - if(size > 4 && tsk_strniequals(pdata, "REMB", 4)){ - uint32_t _u32; - if(size < 8){ // REMB, Num SSRC, BR Exp, BR Mantissa - TSK_DEBUG_ERROR("Too short"); - goto bail; - } - psfb->afb.type = trtp_rtcp_psfb_afb_type_remb; - _u32 = (uint32_t)tnet_ntohl_2(&pdata[4]); - psfb->afb.remb.num_ssrc = ((_u32 >> 24) & 0xFF); - if((psfb->afb.remb.num_ssrc << 2) != (size - 8)){ - TSK_DEBUG_ERROR("Invalid size"); - psfb->afb.remb.num_ssrc = 0; - goto bail; - } - psfb->afb.remb.exp = ((_u32 >> 18) & 0x3F); - psfb->afb.remb.mantissa = (_u32 & 0x3FFFF); - if((psfb->afb.remb.ssrc_feedbacks = tsk_malloc(psfb->afb.remb.num_ssrc << 2))){ - for(_u32 = 0; _u32 < psfb->afb.remb.num_ssrc; ++_u32){ - psfb->afb.remb.ssrc_feedbacks[_u32] = (uint32_t)tnet_ntohl_2(&pdata[8 + (_u32 << 2)]); - } - } - } - else{ - if((psfb->afb.none.bytes = tsk_calloc(size, sizeof(uint8_t)))){ - memcpy(psfb->afb.none.bytes, &pdata[0], size); - } - } - } - break; - } - default: - { - TSK_DEBUG_ERROR("%d not a valid FCI", psfb->fci_type); - goto bail; - } - } - } - } + trtp_rtcp_report_psfb_t* psfb = tsk_null; + trtp_rtcp_header_t* header = tsk_null; + uint32_t ssrc_sender, ssrc_media_src; + + if(_trtp_rtcp_report_fb_deserialize(data, _size, &header, &ssrc_sender, &ssrc_media_src) == 0) { + if((psfb = trtp_rtcp_report_psfb_create(header))) { + const uint8_t* pdata = ((const uint8_t*)data) + TRTP_RTCP_PACKET_FB_MIN_SIZE; + tsk_size_t size = (header->length_in_bytes - TRTP_RTCP_PACKET_FB_MIN_SIZE); + + TRTP_RTCP_REPORT_FB(psfb)->ssrc_sender = ssrc_sender; + TRTP_RTCP_REPORT_FB(psfb)->ssrc_media = ssrc_media_src; + + switch((psfb->fci_type = header->rc)/* FMT for RTCP-FB messages */) { + case trtp_rtcp_psfb_fci_type_pli: { + // No FCI in PLI + // TSK_DEBUG_INFO("PLI"); + break; + } + case trtp_rtcp_psfb_fci_type_sli: { + tsk_size_t sli_count = (size >> 2), i; + uint32_t u32; + if(sli_count == 0) { + TSK_DEBUG_ERROR("Too short"); + goto bail; + } + psfb->sli.first = tsk_realloc(psfb->sli.first, (sli_count * sizeof(uint16_t))); + psfb->sli.number = tsk_realloc(psfb->sli.number, (sli_count * sizeof(uint16_t))); + psfb->sli.pic_id = tsk_realloc(psfb->sli.pic_id, (sli_count * sizeof(uint16_t))); + for(i = 0; i < sli_count; ++i) { + u32 = (uint32_t)tnet_ntohl_2(&pdata[i >> 2]); + if(psfb->sli.first) { + psfb->sli.first[i] = (u32 >> 19); + } + if(psfb->sli.number) { + psfb->sli.number[i] = (u32 >> 6) & 0x1FFF; + } + if(psfb->sli.pic_id) { + psfb->sli.pic_id[i] = u32 & 0x3F; + } + } + + break; + } + case trtp_rtcp_psfb_fci_type_rpsi: { + uint16_t u16; + if(size < 2) { + TSK_DEBUG_ERROR("Too short"); + goto bail; + } + u16 = tnet_ntohs_2(&pdata[0]); + psfb->rpsi.pb = (u16 >> 8); + psfb->rpsi.pt = (u16 & 0x7F); + if((psfb->rpsi.bytes = tsk_calloc((size - 2), sizeof(uint8_t)))) { + memcpy(psfb->rpsi.bytes, &pdata[2], (size - 2)); + } + break; + } + case trtp_rtcp_psfb_fci_type_fir: { + tsk_size_t fir_count = (size >> 3), i; + if(fir_count == 0) { + TSK_DEBUG_ERROR("Too short"); + goto bail; + } + psfb->fir.count = fir_count; + psfb->fir.ssrc = tsk_realloc(psfb->fir.seq_num, (fir_count * sizeof(uint32_t))); + psfb->fir.seq_num = tsk_realloc(psfb->fir.seq_num, (fir_count * sizeof(uint8_t))); + for(i = 0; i < fir_count; ++i) { + if(psfb->fir.ssrc) { + psfb->fir.ssrc[i] = (uint32_t)tnet_ntohl_2(&pdata[0]); + } + if(psfb->fir.seq_num) { + psfb->fir.seq_num[i] = pdata[4]; + } + pdata+=8; + } + break; + } + case trtp_rtcp_psfb_fci_type_afb: { + if(size > 0) { + psfb->afb.type = trtp_rtcp_psfb_afb_type_none; + // REMB (http://tools.ietf.org/html/draft-alvestrand-rmcat-remb-02) or jitter buffer congestion estimation message? + if (size > 4 && tsk_strniequals(pdata, "REMB", 4)) { + uint32_t _u32; + if (size < 8) { // REMB, Num SSRC, BR Exp, BR Mantissa + TSK_DEBUG_ERROR("Too short"); + goto bail; + } + psfb->afb.type = trtp_rtcp_psfb_afb_type_remb; + _u32 = (uint32_t)tnet_ntohl_2(&pdata[4]); + psfb->afb.remb.num_ssrc = ((_u32 >> 24) & 0xFF); + if ((psfb->afb.remb.num_ssrc << 2) != (size - 8)) { + TSK_DEBUG_ERROR("Invalid size"); + psfb->afb.remb.num_ssrc = 0; + goto bail; + } + psfb->afb.remb.exp = ((_u32 >> 18) & 0x3F); + psfb->afb.remb.mantissa = (_u32 & 0x3FFFF); + if ((psfb->afb.remb.ssrc_feedbacks = tsk_malloc(psfb->afb.remb.num_ssrc << 2))) { + for (_u32 = 0; _u32 < psfb->afb.remb.num_ssrc; ++_u32) { + psfb->afb.remb.ssrc_feedbacks[_u32] = (uint32_t)tnet_ntohl_2(&pdata[8 + (_u32 << 2)]); + } + } + } + else if (size > 4 && tsk_strniequals(pdata, "JCNG", 4)) { + uint32_t _u32; + if (size < 8) { // JCNG, Num SSRC, Q, Reserved + TSK_DEBUG_ERROR("Too short"); + goto bail; + } + psfb->afb.type = trtp_rtcp_psfb_afb_type_jcng; + _u32 = (uint32_t)tnet_ntohl_2(&pdata[4]); + psfb->afb.jcng.num_ssrc = ((_u32 >> 24) & 0xFF); + if ((psfb->afb.jcng.num_ssrc << 2) != (size - 8)) { + TSK_DEBUG_ERROR("Invalid size"); + psfb->afb.jcng.num_ssrc = 0; + goto bail; + } + psfb->afb.jcng.q = ((_u32 >> 16) & 0xFF); + if ((psfb->afb.jcng.ssrc_feedbacks = tsk_malloc(psfb->afb.jcng.num_ssrc << 2))) { + for (_u32 = 0; _u32 < psfb->afb.jcng.num_ssrc; ++_u32) { + psfb->afb.jcng.ssrc_feedbacks[_u32] = (uint32_t)tnet_ntohl_2(&pdata[8 + (_u32 << 2)]); + } + } + } + else { + if ((psfb->afb.none.bytes = tsk_calloc(size, sizeof(uint8_t)))) { + memcpy(psfb->afb.none.bytes, &pdata[0], size); + } + } + } + break; + } + default: { + TSK_DEBUG_ERROR("%d not a valid FCI", psfb->fci_type); + goto bail; + } + } + } + } bail: - TSK_OBJECT_SAFE_FREE(header); - return psfb; + TSK_OBJECT_SAFE_FREE(header); + return psfb; } int trtp_rtcp_report_psfb_serialize_to(const trtp_rtcp_report_psfb_t* self, void* data, tsk_size_t size) { - int ret; - uint8_t* pdata = (uint8_t*)data; - - if(!self || !data || size < trtp_rtcp_report_psfb_get_size(self)){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if((ret = _trtp_rtcp_report_fb_serialize_to(TRTP_RTCP_REPORT_FB(self), pdata, size))){ - TSK_DEBUG_ERROR("Failed to serialize FB message"); - return ret; - } - pdata += TRTP_RTCP_PACKET_FB_MIN_SIZE; - size -= TRTP_RTCP_PACKET_FB_MIN_SIZE; - - switch(self->fci_type){ - case trtp_rtcp_psfb_fci_type_pli: - { - // No FCI in PLI - break; - } - case trtp_rtcp_psfb_fci_type_fir: - { - tsk_size_t i; - for(i = 0; i < self->fir.count; ++i){ - pdata[0] = self->fir.ssrc[i] >> 24; - pdata[1] = (self->fir.ssrc[i] >> 16) & 0xFF; - pdata[2] = (self->fir.ssrc[i] >> 8) & 0xFF; - pdata[3] = (self->fir.ssrc[i] & 0xFF); - pdata[4] = self->fir.seq_num[i]; - pdata += 8; // SSRC (4), Seq nr(1), Reserved(3) - } - break; - } - case trtp_rtcp_psfb_fci_type_afb: - { - if(self->afb.type == trtp_rtcp_psfb_afb_type_remb){ - tsk_size_t i; - // 'R' 'E' 'M' 'B' - pdata[0] = 'R', pdata[1] = 'E', pdata[2] = 'M', pdata[3] = 'B'; - // | Num SSRC | BR Exp | BR Mantissa - pdata[4] = self->afb.remb.num_ssrc; // 8bits - pdata[5] = (self->afb.remb.exp << 2) & 0xFC;// 6bits - // 18bits - pdata[5] |= (self->afb.remb.mantissa >> 16) & 0x3; - pdata[6] = (self->afb.remb.mantissa >> 8) & 0xFF; - pdata[7] = (self->afb.remb.mantissa & 0xFF); - if(self->afb.remb.ssrc_feedbacks){ - for(i = 0; i < self->afb.remb.num_ssrc; ++i){ - pdata[8 + (i<<2)] = self->afb.remb.ssrc_feedbacks[i] >> 24; - pdata[8 + (i<<2) + 1] = (self->afb.remb.ssrc_feedbacks[i] >> 16) & 0xFF; - pdata[8 + (i<<2) + 2] = (self->afb.remb.ssrc_feedbacks[i] >> 8) & 0xFF; - pdata[8 + (i<<2) + 3] = (self->afb.remb.ssrc_feedbacks[i] & 0xFF); - } - } - } - else{ - TSK_DEBUG_ERROR("Not implemented yet"); - return -1; - } - break; - } - default: - { - TSK_DEBUG_ERROR("Not implemented yet"); - return -1; - } - } - - return ret; + int ret; + uint8_t* pdata = (uint8_t*)data; + + if(!self || !data || size < trtp_rtcp_report_psfb_get_size(self)) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if((ret = _trtp_rtcp_report_fb_serialize_to(TRTP_RTCP_REPORT_FB(self), pdata, size))) { + TSK_DEBUG_ERROR("Failed to serialize FB message"); + return ret; + } + pdata += TRTP_RTCP_PACKET_FB_MIN_SIZE; + size -= TRTP_RTCP_PACKET_FB_MIN_SIZE; + + switch(self->fci_type) { + case trtp_rtcp_psfb_fci_type_pli: { + // No FCI in PLI + break; + } + case trtp_rtcp_psfb_fci_type_fir: { + tsk_size_t i; + for(i = 0; i < self->fir.count; ++i) { + pdata[0] = self->fir.ssrc[i] >> 24; + pdata[1] = (self->fir.ssrc[i] >> 16) & 0xFF; + pdata[2] = (self->fir.ssrc[i] >> 8) & 0xFF; + pdata[3] = (self->fir.ssrc[i] & 0xFF); + pdata[4] = self->fir.seq_num[i]; + pdata += 8; // SSRC (4), Seq nr(1), Reserved(3) + } + break; + } + case trtp_rtcp_psfb_fci_type_afb: { + if (self->afb.type == trtp_rtcp_psfb_afb_type_remb) { + tsk_size_t i; + // 'R' 'E' 'M' 'B' + pdata[0] = 'R', pdata[1] = 'E', pdata[2] = 'M', pdata[3] = 'B'; + // | Num SSRC | BR Exp | BR Mantissa + pdata[4] = self->afb.remb.num_ssrc; // 8bits + pdata[5] = (self->afb.remb.exp << 2) & 0xFC;// 6bits + // 18bits + pdata[5] |= (self->afb.remb.mantissa >> 16) & 0x3; + pdata[6] = (self->afb.remb.mantissa >> 8) & 0xFF; + pdata[7] = (self->afb.remb.mantissa & 0xFF); + if (self->afb.remb.ssrc_feedbacks) { + for (i = 0; i < self->afb.remb.num_ssrc; ++i) { + pdata[8 + (i<<2)] = self->afb.remb.ssrc_feedbacks[i] >> 24; + pdata[8 + (i<<2) + 1] = (self->afb.remb.ssrc_feedbacks[i] >> 16) & 0xFF; + pdata[8 + (i<<2) + 2] = (self->afb.remb.ssrc_feedbacks[i] >> 8) & 0xFF; + pdata[8 + (i<<2) + 3] = (self->afb.remb.ssrc_feedbacks[i] & 0xFF); + } + } + } + else if (self->afb.type == trtp_rtcp_psfb_afb_type_jcng) { + tsk_size_t i; + // 'J' 'C' 'N' 'G' + pdata[0] = 'J', pdata[1] = 'C', pdata[2] = 'N', pdata[3] = 'G'; + // | Num SSRC | Q | Reserved + pdata[4] = self->afb.jcng.num_ssrc; // 8bits + pdata[5] = self->afb.jcng.q;// 8bits + // 16bits, reserved, zeros + pdata[6] = 0x00; + pdata[7] = 0x00; + if (self->afb.jcng.ssrc_feedbacks) { + for (i = 0; i < self->afb.jcng.num_ssrc; ++i) { + pdata[8 + (i<<2)] = self->afb.jcng.ssrc_feedbacks[i] >> 24; + pdata[8 + (i<<2) + 1] = (self->afb.jcng.ssrc_feedbacks[i] >> 16) & 0xFF; + pdata[8 + (i<<2) + 2] = (self->afb.jcng.ssrc_feedbacks[i] >> 8) & 0xFF; + pdata[8 + (i<<2) + 3] = (self->afb.jcng.ssrc_feedbacks[i] & 0xFF); + } + } + } + else { + TSK_DEBUG_ERROR("Not implemented yet"); + return -1; + } + break; + } + default: { + TSK_DEBUG_ERROR("Not implemented yet"); + return -1; + } + } + + return ret; } tsk_size_t trtp_rtcp_report_psfb_get_size(const trtp_rtcp_report_psfb_t* self) { - if(!self || !TRTP_RTCP_PACKET(self)->header){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - return TRTP_RTCP_PACKET(self)->header->length_in_bytes; + if(!self || !TRTP_RTCP_PACKET(self)->header) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + return TRTP_RTCP_PACKET(self)->header->length_in_bytes; }
\ No newline at end of file diff --git a/tinyRTP/src/rtcp/trtp_rtcp_report_rr.c b/tinyRTP/src/rtcp/trtp_rtcp_report_rr.c index 2a38a4c..0842921 100755 --- a/tinyRTP/src/rtcp/trtp_rtcp_report_rr.c +++ b/tinyRTP/src/rtcp/trtp_rtcp_report_rr.c @@ -2,19 +2,19 @@ * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * * Contact: Mamadou Diop <diopmamadou(at)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. * @@ -30,203 +30,202 @@ static tsk_object_t* trtp_rtcp_report_rr_ctor(tsk_object_t * self, va_list * app) { - trtp_rtcp_report_rr_t *rr = self; - if(rr){ - rr->packets = tsk_list_create(); - rr->blocks = tsk_list_create(); - } - return self; + trtp_rtcp_report_rr_t *rr = self; + if(rr) { + rr->packets = tsk_list_create(); + rr->blocks = tsk_list_create(); + } + return self; } static tsk_object_t* trtp_rtcp_report_rr_dtor(tsk_object_t * self) -{ - trtp_rtcp_report_rr_t *rr = self; - if(rr){ - // deinit self - TSK_OBJECT_SAFE_FREE(rr->packets); - TSK_OBJECT_SAFE_FREE(rr->blocks); - // deinit base - trtp_rtcp_packet_deinit(TRTP_RTCP_PACKET(rr)); - } - - return self; -} -static const tsk_object_def_t trtp_rtcp_report_rr_def_s = { - sizeof(trtp_rtcp_report_rr_t), - trtp_rtcp_report_rr_ctor, - trtp_rtcp_report_rr_dtor, - tsk_null, + trtp_rtcp_report_rr_t *rr = self; + if(rr) { + // deinit self + TSK_OBJECT_SAFE_FREE(rr->packets); + TSK_OBJECT_SAFE_FREE(rr->blocks); + // deinit base + trtp_rtcp_packet_deinit(TRTP_RTCP_PACKET(rr)); + } + + return self; +} +static const tsk_object_def_t trtp_rtcp_report_rr_def_s = { + sizeof(trtp_rtcp_report_rr_t), + trtp_rtcp_report_rr_ctor, + trtp_rtcp_report_rr_dtor, + tsk_null, }; const tsk_object_def_t *trtp_rtcp_report_rr_def_t = &trtp_rtcp_report_rr_def_s; trtp_rtcp_report_rr_t* trtp_rtcp_report_rr_create_null() { - trtp_rtcp_report_rr_t* rr; - if((rr = (trtp_rtcp_report_rr_t*)tsk_object_new(trtp_rtcp_report_rr_def_t))){ - trtp_rtcp_packet_init(TRTP_RTCP_PACKET(rr), TRTP_RTCP_HEADER_VERSION_DEFAULT, 0, 0, trtp_rtcp_packet_type_rr, (TRTP_RTCP_HEADER_SIZE + 4)); - } - return rr; + trtp_rtcp_report_rr_t* rr; + if((rr = (trtp_rtcp_report_rr_t*)tsk_object_new(trtp_rtcp_report_rr_def_t))) { + trtp_rtcp_packet_init(TRTP_RTCP_PACKET(rr), TRTP_RTCP_HEADER_VERSION_DEFAULT, 0, 0, trtp_rtcp_packet_type_rr, (TRTP_RTCP_HEADER_SIZE + 4)); + } + return rr; } trtp_rtcp_report_rr_t* trtp_rtcp_report_rr_create(trtp_rtcp_header_t* header) { - trtp_rtcp_report_rr_t* rr; - if((rr = (trtp_rtcp_report_rr_t*)tsk_object_new(trtp_rtcp_report_rr_def_t))){ - TRTP_RTCP_PACKET(rr)->header = tsk_object_ref(header); - } - return rr; + trtp_rtcp_report_rr_t* rr; + if((rr = (trtp_rtcp_report_rr_t*)tsk_object_new(trtp_rtcp_report_rr_def_t))) { + TRTP_RTCP_PACKET(rr)->header = tsk_object_ref(header); + } + return rr; } trtp_rtcp_report_rr_t* trtp_rtcp_report_rr_create_2(uint32_t ssrc) { - trtp_rtcp_report_rr_t* rr; - if((rr = trtp_rtcp_report_rr_create_null())){ - rr->ssrc = ssrc; - } - return rr; + trtp_rtcp_report_rr_t* rr; + if((rr = trtp_rtcp_report_rr_create_null())) { + rr->ssrc = ssrc; + } + return rr; } trtp_rtcp_report_rr_t* trtp_rtcp_report_rr_deserialize(const void* data, tsk_size_t _size) { - trtp_rtcp_report_rr_t* rr = tsk_null; - trtp_rtcp_header_t* header = tsk_null; - const uint8_t* pdata = (const uint8_t*)data; - int32_t size = (int32_t)_size; - - if(!data || size < TRTP_RTCP_PACKET_RR_MIN_SIZE){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - if(!(header = trtp_rtcp_header_deserialize(pdata, size))){ - TSK_DEBUG_ERROR("Failed to deserialize the header"); - goto bail; - } - if(header->length_in_bytes < TRTP_RTCP_PACKET_RR_MIN_SIZE){ - TSK_DEBUG_ERROR("Too short"); - goto bail; - } - - if(!(rr = trtp_rtcp_report_rr_create(header))){ - TSK_DEBUG_ERROR("Failed to create object"); - goto bail; - } - - rr->ssrc = (uint32_t)tnet_ntohl_2(&pdata[4]); - - pdata += (TRTP_RTCP_HEADER_SIZE + 4); - size -= (TRTP_RTCP_HEADER_SIZE + 4); - - // Blocks - if(header->rc > 0){ - tsk_size_t i = 0; - trtp_rtcp_rblock_t* rblock; - - while(i++ < header->rc && size >= TRTP_RTCP_RBLOCK_SIZE){ - if((rblock = trtp_rtcp_rblock_deserialize(pdata, size))){ - tsk_list_push_back_data(rr->blocks, (void**)&rblock); - } - pdata += TRTP_RTCP_RBLOCK_SIZE; - size -= TRTP_RTCP_RBLOCK_SIZE; - } - } - - // Other Packets - while(size > TRTP_RTCP_HEADER_SIZE){ - trtp_rtcp_packet_t* packet; - - if((packet = trtp_rtcp_packet_deserialize(pdata, size))){ - if((size -= packet->header->length_in_bytes) > 0){ - pdata += packet->header->length_in_bytes; - } - tsk_list_push_back_data(rr->packets, (void**)&packet); - continue; - } - break; - } + trtp_rtcp_report_rr_t* rr = tsk_null; + trtp_rtcp_header_t* header = tsk_null; + const uint8_t* pdata = (const uint8_t*)data; + int32_t size = (int32_t)_size; + + if(!data || size < TRTP_RTCP_PACKET_RR_MIN_SIZE) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + if(!(header = trtp_rtcp_header_deserialize(pdata, size))) { + TSK_DEBUG_ERROR("Failed to deserialize the header"); + goto bail; + } + if(header->length_in_bytes < TRTP_RTCP_PACKET_RR_MIN_SIZE) { + TSK_DEBUG_ERROR("Too short"); + goto bail; + } + + if(!(rr = trtp_rtcp_report_rr_create(header))) { + TSK_DEBUG_ERROR("Failed to create object"); + goto bail; + } + + rr->ssrc = (uint32_t)tnet_ntohl_2(&pdata[4]); + + pdata += (TRTP_RTCP_HEADER_SIZE + 4); + size -= (TRTP_RTCP_HEADER_SIZE + 4); + + // Blocks + if(header->rc > 0) { + tsk_size_t i = 0; + trtp_rtcp_rblock_t* rblock; + + while(i++ < header->rc && size >= TRTP_RTCP_RBLOCK_SIZE) { + if((rblock = trtp_rtcp_rblock_deserialize(pdata, size))) { + tsk_list_push_back_data(rr->blocks, (void**)&rblock); + } + pdata += TRTP_RTCP_RBLOCK_SIZE; + size -= TRTP_RTCP_RBLOCK_SIZE; + } + } + + // Other Packets + while(size > TRTP_RTCP_HEADER_SIZE) { + trtp_rtcp_packet_t* packet; + + if((packet = trtp_rtcp_packet_deserialize(pdata, size))) { + if((size -= packet->header->length_in_bytes) > 0) { + pdata += packet->header->length_in_bytes; + } + tsk_list_push_back_data(rr->packets, (void**)&packet); + continue; + } + break; + } bail: - TSK_OBJECT_SAFE_FREE(header); - return rr; + TSK_OBJECT_SAFE_FREE(header); + return rr; } int trtp_rtcp_report_rr_serialize_to(const trtp_rtcp_report_rr_t* self, void* data, tsk_size_t size) { - int ret; - const tsk_list_item_t* item; - uint8_t* pdata = (uint8_t*)data; - - if(!self || !data || size < trtp_rtcp_report_rr_get_size(self)){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if((ret = trtp_rtcp_header_serialize_to(TRTP_RTCP_PACKET(self)->header, pdata, size))){ - TSK_DEBUG_ERROR("Failed to serialize the header"); - return ret; - } - - pdata[TRTP_RTCP_HEADER_SIZE] = self->ssrc >> 24; - pdata[TRTP_RTCP_HEADER_SIZE + 1] = (self->ssrc >> 16) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 2] = (self->ssrc >> 8) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 3] = (self->ssrc & 0xFF); - - pdata += (TRTP_RTCP_HEADER_SIZE + 4); - size -= (TRTP_RTCP_HEADER_SIZE + 4); - - if(TRTP_RTCP_PACKET(self)->header->rc > 0){ - tsk_list_foreach(item, self->blocks){ - if(!item->data){ - continue; - } - if((ret = trtp_rtcp_rblock_serialize_to(TRTP_RTCP_RBLOCK(item->data), pdata, size))){ - TSK_DEBUG_ERROR("Failed to serialize the rblock"); - goto bail; - } - pdata += TRTP_RTCP_RBLOCK_SIZE; - size -= TRTP_RTCP_RBLOCK_SIZE; - } - } - - tsk_list_foreach(item, self->packets){ - if(!item->data){ - continue; - } - if((ret = trtp_rtcp_packet_serialize_to(TRTP_RTCP_PACKET(item->data), pdata, size))){ - TSK_DEBUG_ERROR("Failed to serialize packet"); - goto bail; - } - pdata += TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; - size -= TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; - } + int ret; + const tsk_list_item_t* item; + uint8_t* pdata = (uint8_t*)data; + + if(!self || !data || size < trtp_rtcp_report_rr_get_size(self)) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if((ret = trtp_rtcp_header_serialize_to(TRTP_RTCP_PACKET(self)->header, pdata, size))) { + TSK_DEBUG_ERROR("Failed to serialize the header"); + return ret; + } + + pdata[TRTP_RTCP_HEADER_SIZE] = self->ssrc >> 24; + pdata[TRTP_RTCP_HEADER_SIZE + 1] = (self->ssrc >> 16) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 2] = (self->ssrc >> 8) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 3] = (self->ssrc & 0xFF); + + pdata += (TRTP_RTCP_HEADER_SIZE + 4); + size -= (TRTP_RTCP_HEADER_SIZE + 4); + + if(TRTP_RTCP_PACKET(self)->header->rc > 0) { + tsk_list_foreach(item, self->blocks) { + if(!item->data) { + continue; + } + if((ret = trtp_rtcp_rblock_serialize_to(TRTP_RTCP_RBLOCK(item->data), pdata, size))) { + TSK_DEBUG_ERROR("Failed to serialize the rblock"); + goto bail; + } + pdata += TRTP_RTCP_RBLOCK_SIZE; + size -= TRTP_RTCP_RBLOCK_SIZE; + } + } + + tsk_list_foreach(item, self->packets) { + if(!item->data) { + continue; + } + if((ret = trtp_rtcp_packet_serialize_to(TRTP_RTCP_PACKET(item->data), pdata, size))) { + TSK_DEBUG_ERROR("Failed to serialize packet"); + goto bail; + } + pdata += TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; + size -= TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; + } bail: - return ret; + return ret; } tsk_size_t trtp_rtcp_report_rr_get_size(const trtp_rtcp_report_rr_t* self) { - tsk_size_t size; - const tsk_list_item_t* item; - - if(!self || !TRTP_RTCP_PACKET(self)->header){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - - size = TRTP_RTCP_PACKET(self)->header->length_in_bytes; - if(TRTP_RTCP_PACKET(self)->header->rc > 0){ - tsk_list_foreach(item, self->blocks){ - if(item->data){ - size += TRTP_RTCP_RBLOCK_SIZE; - } - } - } - tsk_list_foreach(item, self->packets){ - if(item->data && TRTP_RTCP_PACKET(item->data)->header){ - size += TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; - } - } - - return size; + tsk_size_t size; + const tsk_list_item_t* item; + + if(!self || !TRTP_RTCP_PACKET(self)->header) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + size = TRTP_RTCP_PACKET(self)->header->length_in_bytes; + if(TRTP_RTCP_PACKET(self)->header->rc > 0) { + tsk_list_foreach(item, self->blocks) { + if(item->data) { + size += TRTP_RTCP_RBLOCK_SIZE; + } + } + } + tsk_list_foreach(item, self->packets) { + if(item->data && TRTP_RTCP_PACKET(item->data)->header) { + size += TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; + } + } + + return size; }
\ No newline at end of file diff --git a/tinyRTP/src/rtcp/trtp_rtcp_report_sdes.c b/tinyRTP/src/rtcp/trtp_rtcp_report_sdes.c index 4f5e944..8013509 100755 --- a/tinyRTP/src/rtcp/trtp_rtcp_report_sdes.c +++ b/tinyRTP/src/rtcp/trtp_rtcp_report_sdes.c @@ -2,19 +2,19 @@ * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * * Contact: Mamadou Diop <diopmamadou(at)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. * @@ -26,7 +26,7 @@ /* 6.5 SDES: Source Description RTCP Packet - 0 1 2 + 0 1 2 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ header |V=2|P| SC | PT=SDES=202 | length | @@ -45,170 +45,169 @@ chunk | SSRC/CSRC_2 | static tsk_object_t* trtp_rtcp_report_sdes_ctor(tsk_object_t * self, va_list * app) { - trtp_rtcp_report_sdes_t *sdes = self; - if(sdes){ - sdes->chuncks = tsk_list_create(); - } - return self; + trtp_rtcp_report_sdes_t *sdes = self; + if(sdes) { + sdes->chuncks = tsk_list_create(); + } + return self; } static tsk_object_t* trtp_rtcp_report_sdes_dtor(tsk_object_t * self) -{ - trtp_rtcp_report_sdes_t *sdes = self; - if(sdes){ - // deinit base - trtp_rtcp_packet_deinit(TRTP_RTCP_PACKET(sdes)); - // deinit self - TSK_OBJECT_SAFE_FREE(sdes->chuncks); - } - - return self; -} -static const tsk_object_def_t trtp_rtcp_report_sdes_def_s = { - sizeof(trtp_rtcp_report_sdes_t), - trtp_rtcp_report_sdes_ctor, - trtp_rtcp_report_sdes_dtor, - tsk_null, + trtp_rtcp_report_sdes_t *sdes = self; + if(sdes) { + // deinit base + trtp_rtcp_packet_deinit(TRTP_RTCP_PACKET(sdes)); + // deinit self + TSK_OBJECT_SAFE_FREE(sdes->chuncks); + } + + return self; +} +static const tsk_object_def_t trtp_rtcp_report_sdes_def_s = { + sizeof(trtp_rtcp_report_sdes_t), + trtp_rtcp_report_sdes_ctor, + trtp_rtcp_report_sdes_dtor, + tsk_null, }; const tsk_object_def_t *trtp_rtcp_report_sdes_def_t = &trtp_rtcp_report_sdes_def_s; trtp_rtcp_report_sdes_t* trtp_rtcp_report_sdes_create_null() { - trtp_rtcp_report_sdes_t* sdes; - if((sdes = (trtp_rtcp_report_sdes_t*)tsk_object_new(trtp_rtcp_report_sdes_def_t))){ - trtp_rtcp_packet_init(TRTP_RTCP_PACKET(sdes), TRTP_RTCP_HEADER_VERSION_DEFAULT, 0, 0, trtp_rtcp_packet_type_sdes, TRTP_RTCP_HEADER_SIZE); - } - return sdes; + trtp_rtcp_report_sdes_t* sdes; + if((sdes = (trtp_rtcp_report_sdes_t*)tsk_object_new(trtp_rtcp_report_sdes_def_t))) { + trtp_rtcp_packet_init(TRTP_RTCP_PACKET(sdes), TRTP_RTCP_HEADER_VERSION_DEFAULT, 0, 0, trtp_rtcp_packet_type_sdes, TRTP_RTCP_HEADER_SIZE); + } + return sdes; } trtp_rtcp_report_sdes_t* trtp_rtcp_report_sdes_create(trtp_rtcp_header_t* header) { - trtp_rtcp_report_sdes_t* sdes; - if((sdes = (trtp_rtcp_report_sdes_t*)tsk_object_new(trtp_rtcp_report_sdes_def_t))){ - TRTP_RTCP_PACKET(sdes)->header = tsk_object_ref(header); - } - return sdes; + trtp_rtcp_report_sdes_t* sdes; + if((sdes = (trtp_rtcp_report_sdes_t*)tsk_object_new(trtp_rtcp_report_sdes_def_t))) { + TRTP_RTCP_PACKET(sdes)->header = tsk_object_ref(header); + } + return sdes; } trtp_rtcp_report_sdes_t* trtp_rtcp_report_sdes_deserialize(const void* data, tsk_size_t _size) { - trtp_rtcp_report_sdes_t* sdes = tsk_null; - trtp_rtcp_header_t* header = tsk_null; - const uint8_t* pdata = (const uint8_t*)data; - int32_t size = (int32_t)_size; - - if(!data || size < TRTP_RTCP_HEADER_SIZE){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - if(!(header = trtp_rtcp_header_deserialize(pdata, size))){ - TSK_DEBUG_ERROR("Failed to deserialize the header"); - goto bail; - } - if(header->length_in_bytes < (TRTP_RTCP_HEADER_SIZE + 4)){ - TSK_DEBUG_ERROR("Too short"); - goto bail; - } - - if(!(sdes = trtp_rtcp_report_sdes_create(header))){ - TSK_DEBUG_ERROR("Failed to create object"); - goto bail; - } - - pdata += TRTP_RTCP_HEADER_SIZE; - size -= TRTP_RTCP_HEADER_SIZE; - - // Chuncks - if(header->rc > 0){ - tsk_size_t i = 0, chunck_size; - trtp_rtcp_sdes_chunck_t* chunck; - while(i++ < header->rc && size > TRTP_RTCP_SDES_CHUNCK_MIN_SIZE){ - if((chunck = trtp_rtcp_sdes_chunck_deserialize(pdata, size))){ - chunck_size = trtp_rtcp_sdes_chunck_get_size(chunck); - if((size -= (int32_t)chunck_size)){ - pdata += chunck_size; - } - tsk_list_push_ascending_data(sdes->chuncks, (void**)&chunck); - continue; - } - break; - } - } + trtp_rtcp_report_sdes_t* sdes = tsk_null; + trtp_rtcp_header_t* header = tsk_null; + const uint8_t* pdata = (const uint8_t*)data; + int32_t size = (int32_t)_size; + + if(!data || size < TRTP_RTCP_HEADER_SIZE) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + if(!(header = trtp_rtcp_header_deserialize(pdata, size))) { + TSK_DEBUG_ERROR("Failed to deserialize the header"); + goto bail; + } + if(header->length_in_bytes < (TRTP_RTCP_HEADER_SIZE + 4)) { + TSK_DEBUG_ERROR("Too short"); + goto bail; + } + + if(!(sdes = trtp_rtcp_report_sdes_create(header))) { + TSK_DEBUG_ERROR("Failed to create object"); + goto bail; + } + + pdata += TRTP_RTCP_HEADER_SIZE; + size -= TRTP_RTCP_HEADER_SIZE; + + // Chuncks + if(header->rc > 0) { + tsk_size_t i = 0, chunck_size; + trtp_rtcp_sdes_chunck_t* chunck; + while(i++ < header->rc && size > TRTP_RTCP_SDES_CHUNCK_MIN_SIZE) { + if((chunck = trtp_rtcp_sdes_chunck_deserialize(pdata, size))) { + chunck_size = trtp_rtcp_sdes_chunck_get_size(chunck); + if((size -= (int32_t)chunck_size)) { + pdata += chunck_size; + } + tsk_list_push_ascending_data(sdes->chuncks, (void**)&chunck); + continue; + } + break; + } + } bail: - TSK_OBJECT_SAFE_FREE(header); - return sdes; + TSK_OBJECT_SAFE_FREE(header); + return sdes; } int trtp_rtcp_report_sdes_serialize_to(const trtp_rtcp_report_sdes_t* self, void* data, tsk_size_t size) { - int ret; - uint8_t* pdata = (uint8_t*)data; - if(!self || !data || size < trtp_rtcp_report_sdes_get_size(self)){ - return -1; - } - - if((ret = trtp_rtcp_header_serialize_to(TRTP_RTCP_PACKET(self)->header, pdata, size))){ - TSK_DEBUG_ERROR("Failed to serialize the header"); - return ret; - } - - pdata += (TRTP_RTCP_HEADER_SIZE); - size -= (TRTP_RTCP_HEADER_SIZE); - - if(TRTP_RTCP_PACKET(self)->header->rc > 0){ - const tsk_list_item_t* item; - tsk_size_t chunck_size; - const trtp_rtcp_sdes_chunck_t* chunck; - tsk_list_foreach(item, self->chuncks){ - if(!(chunck = item->data)){ - continue; - } - if((ret = trtp_rtcp_sdes_chunck_serialize_to(chunck, pdata, size))){ - TSK_DEBUG_ERROR("Failed to serialize SDES chunck"); - goto bail; - } - chunck_size = trtp_rtcp_sdes_chunck_get_size(chunck); - pdata += chunck_size; - size -= chunck_size; - } - } + int ret; + uint8_t* pdata = (uint8_t*)data; + if(!self || !data || size < trtp_rtcp_report_sdes_get_size(self)) { + return -1; + } + + if((ret = trtp_rtcp_header_serialize_to(TRTP_RTCP_PACKET(self)->header, pdata, size))) { + TSK_DEBUG_ERROR("Failed to serialize the header"); + return ret; + } + + pdata += (TRTP_RTCP_HEADER_SIZE); + size -= (TRTP_RTCP_HEADER_SIZE); + + if(TRTP_RTCP_PACKET(self)->header->rc > 0) { + const tsk_list_item_t* item; + tsk_size_t chunck_size; + const trtp_rtcp_sdes_chunck_t* chunck; + tsk_list_foreach(item, self->chuncks) { + if(!(chunck = item->data)) { + continue; + } + if((ret = trtp_rtcp_sdes_chunck_serialize_to(chunck, pdata, size))) { + TSK_DEBUG_ERROR("Failed to serialize SDES chunck"); + goto bail; + } + chunck_size = trtp_rtcp_sdes_chunck_get_size(chunck); + pdata += chunck_size; + size -= chunck_size; + } + } bail: - return ret; + return ret; } int trtp_rtcp_report_sdes_add_chunck(trtp_rtcp_report_sdes_t* self, trtp_rtcp_sdes_chunck_t* chunck) { - if(!self || !self->chuncks || !chunck){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - chunck = tsk_object_ref(chunck); - TRTP_RTCP_PACKET(self)->header->length_in_bytes += (uint32_t)trtp_rtcp_sdes_chunck_get_size(chunck); - TRTP_RTCP_PACKET(self)->header->length_in_words_minus1 = ((TRTP_RTCP_PACKET(self)->header->length_in_bytes >> 2) - 1) - + ((TRTP_RTCP_PACKET(self)->header->length_in_bytes & 0x03) ? 1 : 0); - ++TRTP_RTCP_PACKET(self)->header->rc; - tsk_list_push_back_data(self->chuncks, (void**)&chunck); - return 0; + if(!self || !self->chuncks || !chunck) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + chunck = tsk_object_ref(chunck); + TRTP_RTCP_PACKET(self)->header->length_in_bytes += (uint32_t)trtp_rtcp_sdes_chunck_get_size(chunck); + TRTP_RTCP_PACKET(self)->header->length_in_words_minus1 = ((TRTP_RTCP_PACKET(self)->header->length_in_bytes >> 2) - 1) + + ((TRTP_RTCP_PACKET(self)->header->length_in_bytes & 0x03) ? 1 : 0); + ++TRTP_RTCP_PACKET(self)->header->rc; + tsk_list_push_back_data(self->chuncks, (void**)&chunck); + return 0; } tsk_size_t trtp_rtcp_report_sdes_get_size(const trtp_rtcp_report_sdes_t* self) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - else{ - tsk_size_t size = TRTP_RTCP_HEADER_SIZE; - const tsk_list_item_t* item; - tsk_list_foreach(item, self->chuncks){ - size += trtp_rtcp_sdes_chunck_get_size(TRTP_RTCP_SDES_CHUNCK(item->data)); - } - return size; - } + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + else { + tsk_size_t size = TRTP_RTCP_HEADER_SIZE; + const tsk_list_item_t* item; + tsk_list_foreach(item, self->chuncks) { + size += trtp_rtcp_sdes_chunck_get_size(TRTP_RTCP_SDES_CHUNCK(item->data)); + } + return size; + } } diff --git a/tinyRTP/src/rtcp/trtp_rtcp_report_sr.c b/tinyRTP/src/rtcp/trtp_rtcp_report_sr.c index 5d8ceda..e807f17 100755 --- a/tinyRTP/src/rtcp/trtp_rtcp_report_sr.c +++ b/tinyRTP/src/rtcp/trtp_rtcp_report_sr.c @@ -2,19 +2,19 @@ * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * * Contact: Mamadou Diop <diopmamadou(at)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. * @@ -30,241 +30,240 @@ static tsk_object_t* trtp_rtcp_report_sr_ctor(tsk_object_t * self, va_list * app) { - trtp_rtcp_report_sr_t *sr = self; - if(sr){ - sr->blocks = tsk_list_create(); - sr->packets = tsk_list_create(); - } - return self; + trtp_rtcp_report_sr_t *sr = self; + if(sr) { + sr->blocks = tsk_list_create(); + sr->packets = tsk_list_create(); + } + return self; } static tsk_object_t* trtp_rtcp_report_sr_dtor(tsk_object_t * self) -{ - trtp_rtcp_report_sr_t *sr = self; - if(sr){ - // deinit self - TSK_OBJECT_SAFE_FREE(sr->blocks); - TSK_OBJECT_SAFE_FREE(sr->packets); - // deinit base - trtp_rtcp_packet_deinit(TRTP_RTCP_PACKET(sr)); - } - - return self; +{ + trtp_rtcp_report_sr_t *sr = self; + if(sr) { + // deinit self + TSK_OBJECT_SAFE_FREE(sr->blocks); + TSK_OBJECT_SAFE_FREE(sr->packets); + // deinit base + trtp_rtcp_packet_deinit(TRTP_RTCP_PACKET(sr)); + } + + return self; } -static const tsk_object_def_t trtp_rtcp_report_sr_def_s = -{ - sizeof(trtp_rtcp_report_sr_t), - trtp_rtcp_report_sr_ctor, - trtp_rtcp_report_sr_dtor, - tsk_null, +static const tsk_object_def_t trtp_rtcp_report_sr_def_s = { + sizeof(trtp_rtcp_report_sr_t), + trtp_rtcp_report_sr_ctor, + trtp_rtcp_report_sr_dtor, + tsk_null, }; const tsk_object_def_t *trtp_rtcp_report_sr_def_t = &trtp_rtcp_report_sr_def_s; trtp_rtcp_report_sr_t* trtp_rtcp_report_sr_create_null() { - trtp_rtcp_report_sr_t* sr; - if((sr = (trtp_rtcp_report_sr_t*)tsk_object_new(trtp_rtcp_report_sr_def_t))){ - trtp_rtcp_packet_init(TRTP_RTCP_PACKET(sr), TRTP_RTCP_HEADER_VERSION_DEFAULT, 0, 0, trtp_rtcp_packet_type_sr, (TRTP_RTCP_HEADER_SIZE + 4 + 20)); - } - return sr; + trtp_rtcp_report_sr_t* sr; + if((sr = (trtp_rtcp_report_sr_t*)tsk_object_new(trtp_rtcp_report_sr_def_t))) { + trtp_rtcp_packet_init(TRTP_RTCP_PACKET(sr), TRTP_RTCP_HEADER_VERSION_DEFAULT, 0, 0, trtp_rtcp_packet_type_sr, (TRTP_RTCP_HEADER_SIZE + 4 + 20)); + } + return sr; } trtp_rtcp_report_sr_t* trtp_rtcp_report_sr_create(struct trtp_rtcp_header_s* header) { - trtp_rtcp_report_sr_t* sr; - if((sr = (trtp_rtcp_report_sr_t*)tsk_object_new(trtp_rtcp_report_sr_def_t))){ - TRTP_RTCP_PACKET(sr)->header = tsk_object_ref(header); - } - return sr; + trtp_rtcp_report_sr_t* sr; + if((sr = (trtp_rtcp_report_sr_t*)tsk_object_new(trtp_rtcp_report_sr_def_t))) { + TRTP_RTCP_PACKET(sr)->header = tsk_object_ref(header); + } + return sr; } trtp_rtcp_report_sr_t* trtp_rtcp_report_sr_deserialize(const void* data, tsk_size_t _size) { - trtp_rtcp_report_sr_t* sr = tsk_null; - trtp_rtcp_header_t* header = tsk_null; - const uint8_t* pdata = (const uint8_t*)data; - int32_t size = (int32_t)_size; - - if(!data || size < TRTP_RTCP_PACKET_SR_MIN_SIZE){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - if(!(header = trtp_rtcp_header_deserialize(pdata, size))){ - TSK_DEBUG_ERROR("Failed to deserialize the header"); - goto bail; - } - if(header->length_in_bytes < TRTP_RTCP_PACKET_SR_MIN_SIZE){ - TSK_DEBUG_ERROR("Too short"); - goto bail; - } - - if(!(sr = trtp_rtcp_report_sr_create(header))){ - TSK_DEBUG_ERROR("Failed to create object"); - goto bail; - } - - sr->ssrc = (uint32_t)tnet_ntohl_2(&pdata[4]); - pdata += (TRTP_RTCP_HEADER_SIZE + 4); - size -= (TRTP_RTCP_HEADER_SIZE + 4); - - // sender info - sr->sender_info.ntp_msw = (uint32_t)tnet_ntohl_2(&pdata[0]); - sr->sender_info.ntp_lsw = (uint32_t)tnet_ntohl_2(&pdata[4]); - sr->sender_info.rtp_timestamp = (uint32_t)tnet_ntohl_2(&pdata[8]); - sr->sender_info.sender_pcount = (uint32_t)tnet_ntohl_2(&pdata[12]); - sr->sender_info.sender_ocount = (uint32_t)tnet_ntohl_2(&pdata[16]); - pdata += 20; - size -= 20; - - // Blocks - if(header->rc > 0){ - tsk_size_t i = 0; - trtp_rtcp_rblock_t* rblock; - - while(i++ < header->rc && size >= TRTP_RTCP_RBLOCK_SIZE){ - if((rblock = trtp_rtcp_rblock_deserialize(pdata, size))){ - tsk_list_push_back_data(sr->blocks, (void**)&rblock); - } - pdata += TRTP_RTCP_RBLOCK_SIZE; - size -= TRTP_RTCP_RBLOCK_SIZE; - } - } - - // Other Packets - while(size > TRTP_RTCP_HEADER_SIZE){ - trtp_rtcp_packet_t* packet; - - if((packet = trtp_rtcp_packet_deserialize(pdata, size))){ - if((size -= packet->header->length_in_bytes) > 0){ - pdata += packet->header->length_in_bytes; - } - tsk_list_push_back_data(sr->packets, (void**)&packet); - continue; - } - break; - } + trtp_rtcp_report_sr_t* sr = tsk_null; + trtp_rtcp_header_t* header = tsk_null; + const uint8_t* pdata = (const uint8_t*)data; + int32_t size = (int32_t)_size; + + if(!data || size < TRTP_RTCP_PACKET_SR_MIN_SIZE) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + if(!(header = trtp_rtcp_header_deserialize(pdata, size))) { + TSK_DEBUG_ERROR("Failed to deserialize the header"); + goto bail; + } + if(header->length_in_bytes < TRTP_RTCP_PACKET_SR_MIN_SIZE) { + TSK_DEBUG_ERROR("Too short"); + goto bail; + } + + if(!(sr = trtp_rtcp_report_sr_create(header))) { + TSK_DEBUG_ERROR("Failed to create object"); + goto bail; + } + + sr->ssrc = (uint32_t)tnet_ntohl_2(&pdata[4]); + pdata += (TRTP_RTCP_HEADER_SIZE + 4); + size -= (TRTP_RTCP_HEADER_SIZE + 4); + + // sender info + sr->sender_info.ntp_msw = (uint32_t)tnet_ntohl_2(&pdata[0]); + sr->sender_info.ntp_lsw = (uint32_t)tnet_ntohl_2(&pdata[4]); + sr->sender_info.rtp_timestamp = (uint32_t)tnet_ntohl_2(&pdata[8]); + sr->sender_info.sender_pcount = (uint32_t)tnet_ntohl_2(&pdata[12]); + sr->sender_info.sender_ocount = (uint32_t)tnet_ntohl_2(&pdata[16]); + pdata += 20; + size -= 20; + + // Blocks + if(header->rc > 0) { + tsk_size_t i = 0; + trtp_rtcp_rblock_t* rblock; + + while(i++ < header->rc && size >= TRTP_RTCP_RBLOCK_SIZE) { + if((rblock = trtp_rtcp_rblock_deserialize(pdata, size))) { + tsk_list_push_back_data(sr->blocks, (void**)&rblock); + } + pdata += TRTP_RTCP_RBLOCK_SIZE; + size -= TRTP_RTCP_RBLOCK_SIZE; + } + } + + // Other Packets + while(size > TRTP_RTCP_HEADER_SIZE) { + trtp_rtcp_packet_t* packet; + + if((packet = trtp_rtcp_packet_deserialize(pdata, size))) { + if((size -= packet->header->length_in_bytes) > 0) { + pdata += packet->header->length_in_bytes; + } + tsk_list_push_back_data(sr->packets, (void**)&packet); + continue; + } + break; + } bail: - TSK_OBJECT_SAFE_FREE(header); - return sr; + TSK_OBJECT_SAFE_FREE(header); + return sr; } int trtp_rtcp_report_sr_serialize_to(const trtp_rtcp_report_sr_t* self, void* data, tsk_size_t size) { - int ret; - const tsk_list_item_t* item; - uint8_t* pdata = (uint8_t*)data; - - if(!self || !data || size < trtp_rtcp_report_sr_get_size(self)){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if((ret = trtp_rtcp_header_serialize_to(TRTP_RTCP_PACKET(self)->header, pdata, size))){ - TSK_DEBUG_ERROR("Failed to serialize the header"); - return ret; - } - - pdata[TRTP_RTCP_HEADER_SIZE] = self->ssrc >> 24; - pdata[TRTP_RTCP_HEADER_SIZE + 1] = (self->ssrc >> 16) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 2] = (self->ssrc >> 8) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 3] = (self->ssrc & 0xFF); - pdata[TRTP_RTCP_HEADER_SIZE + 4] = self->sender_info.ntp_msw >> 24; - pdata[TRTP_RTCP_HEADER_SIZE + 5] = (self->sender_info.ntp_msw >> 16) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 6] = (self->sender_info.ntp_msw >> 8) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 7] = self->sender_info.ntp_msw & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 8] = self->sender_info.ntp_lsw >> 24; - pdata[TRTP_RTCP_HEADER_SIZE + 9] = (self->sender_info.ntp_lsw >> 16) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 10] = (self->sender_info.ntp_lsw >> 8) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 11] = self->sender_info.ntp_lsw & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 12] = self->sender_info.rtp_timestamp >> 24; - pdata[TRTP_RTCP_HEADER_SIZE + 13] = (self->sender_info.rtp_timestamp >> 16) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 14] = (self->sender_info.rtp_timestamp >> 8) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 15] = self->sender_info.rtp_timestamp & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 16] = self->sender_info.sender_pcount >> 24; - pdata[TRTP_RTCP_HEADER_SIZE + 17] = (self->sender_info.sender_pcount >> 16) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 18] = (self->sender_info.sender_pcount >> 8) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 19] = self->sender_info.sender_pcount & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 20] = self->sender_info.sender_ocount >> 24; - pdata[TRTP_RTCP_HEADER_SIZE + 21] = (self->sender_info.sender_ocount >> 16) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 22] = (self->sender_info.sender_ocount >> 8) & 0xFF; - pdata[TRTP_RTCP_HEADER_SIZE + 23] = self->sender_info.sender_ocount & 0xFF; - - pdata += (TRTP_RTCP_HEADER_SIZE + 4 + 20); - size -= (TRTP_RTCP_HEADER_SIZE + 4 + 20); - - if(TRTP_RTCP_PACKET(self)->header->rc > 0){ - tsk_list_foreach(item, self->blocks){ - if(!item->data){ - continue; - } - if((ret = trtp_rtcp_rblock_serialize_to(TRTP_RTCP_RBLOCK(item->data), pdata, size))){ - TSK_DEBUG_ERROR("Failed to serialize the rblock"); - goto bail; - } - pdata += TRTP_RTCP_RBLOCK_SIZE; - size -= TRTP_RTCP_RBLOCK_SIZE; - } - } - - tsk_list_foreach(item, self->packets){ - if(!item->data){ - continue; - } - if((ret = trtp_rtcp_packet_serialize_to(TRTP_RTCP_PACKET(item->data), pdata, size))){ - TSK_DEBUG_ERROR("Failed to serialize packet"); - goto bail; - } - pdata += TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; - size -= TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; - } + int ret; + const tsk_list_item_t* item; + uint8_t* pdata = (uint8_t*)data; + + if(!self || !data || size < trtp_rtcp_report_sr_get_size(self)) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if((ret = trtp_rtcp_header_serialize_to(TRTP_RTCP_PACKET(self)->header, pdata, size))) { + TSK_DEBUG_ERROR("Failed to serialize the header"); + return ret; + } + + pdata[TRTP_RTCP_HEADER_SIZE] = self->ssrc >> 24; + pdata[TRTP_RTCP_HEADER_SIZE + 1] = (self->ssrc >> 16) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 2] = (self->ssrc >> 8) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 3] = (self->ssrc & 0xFF); + pdata[TRTP_RTCP_HEADER_SIZE + 4] = self->sender_info.ntp_msw >> 24; + pdata[TRTP_RTCP_HEADER_SIZE + 5] = (self->sender_info.ntp_msw >> 16) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 6] = (self->sender_info.ntp_msw >> 8) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 7] = self->sender_info.ntp_msw & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 8] = self->sender_info.ntp_lsw >> 24; + pdata[TRTP_RTCP_HEADER_SIZE + 9] = (self->sender_info.ntp_lsw >> 16) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 10] = (self->sender_info.ntp_lsw >> 8) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 11] = self->sender_info.ntp_lsw & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 12] = self->sender_info.rtp_timestamp >> 24; + pdata[TRTP_RTCP_HEADER_SIZE + 13] = (self->sender_info.rtp_timestamp >> 16) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 14] = (self->sender_info.rtp_timestamp >> 8) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 15] = self->sender_info.rtp_timestamp & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 16] = self->sender_info.sender_pcount >> 24; + pdata[TRTP_RTCP_HEADER_SIZE + 17] = (self->sender_info.sender_pcount >> 16) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 18] = (self->sender_info.sender_pcount >> 8) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 19] = self->sender_info.sender_pcount & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 20] = self->sender_info.sender_ocount >> 24; + pdata[TRTP_RTCP_HEADER_SIZE + 21] = (self->sender_info.sender_ocount >> 16) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 22] = (self->sender_info.sender_ocount >> 8) & 0xFF; + pdata[TRTP_RTCP_HEADER_SIZE + 23] = self->sender_info.sender_ocount & 0xFF; + + pdata += (TRTP_RTCP_HEADER_SIZE + 4 + 20); + size -= (TRTP_RTCP_HEADER_SIZE + 4 + 20); + + if(TRTP_RTCP_PACKET(self)->header->rc > 0) { + tsk_list_foreach(item, self->blocks) { + if(!item->data) { + continue; + } + if((ret = trtp_rtcp_rblock_serialize_to(TRTP_RTCP_RBLOCK(item->data), pdata, size))) { + TSK_DEBUG_ERROR("Failed to serialize the rblock"); + goto bail; + } + pdata += TRTP_RTCP_RBLOCK_SIZE; + size -= TRTP_RTCP_RBLOCK_SIZE; + } + } + + tsk_list_foreach(item, self->packets) { + if(!item->data) { + continue; + } + if((ret = trtp_rtcp_packet_serialize_to(TRTP_RTCP_PACKET(item->data), pdata, size))) { + TSK_DEBUG_ERROR("Failed to serialize packet"); + goto bail; + } + pdata += TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; + size -= TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; + } bail: - return ret; + return ret; } int trtp_rtcp_report_sr_add_block(trtp_rtcp_report_sr_t* self, trtp_rtcp_rblock_t* rblock) { - if(!self || !TRTP_RTCP_PACKET(self)->header || !rblock){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - rblock = tsk_object_ref(rblock); - tsk_list_push_back_data(self->blocks, (void**)&rblock); - ++TRTP_RTCP_PACKET(self)->header->rc; - TRTP_RTCP_PACKET(self)->header->length_in_bytes += TRTP_RTCP_RBLOCK_SIZE; - TRTP_RTCP_PACKET(self)->header->length_in_words_minus1 = ((TRTP_RTCP_PACKET(self)->header->length_in_bytes >> 2) - 1) + - ((TRTP_RTCP_PACKET(self)->header->length_in_bytes & 0x03) ? 1 : 0); - return 0; + if(!self || !TRTP_RTCP_PACKET(self)->header || !rblock) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + rblock = tsk_object_ref(rblock); + tsk_list_push_back_data(self->blocks, (void**)&rblock); + ++TRTP_RTCP_PACKET(self)->header->rc; + TRTP_RTCP_PACKET(self)->header->length_in_bytes += TRTP_RTCP_RBLOCK_SIZE; + TRTP_RTCP_PACKET(self)->header->length_in_words_minus1 = ((TRTP_RTCP_PACKET(self)->header->length_in_bytes >> 2) - 1) + + ((TRTP_RTCP_PACKET(self)->header->length_in_bytes & 0x03) ? 1 : 0); + return 0; } tsk_size_t trtp_rtcp_report_sr_get_size(const trtp_rtcp_report_sr_t* self) { - tsk_size_t size; - const tsk_list_item_t* item; - - if(!self || !TRTP_RTCP_PACKET(self)->header){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - - size = TRTP_RTCP_PACKET(self)->header->length_in_bytes; - //if(TRTP_RTCP_PACKET(self)->header->rc > 0){ - // tsk_list_foreach(item, self->blocks){ - // if(item->data){ - // size += TRTP_RTCP_RBLOCK_SIZE; - // } - // } - //} - tsk_list_foreach(item, self->packets){ - if(item->data && TRTP_RTCP_PACKET(item->data)->header){ - size += TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; - } - } - - return size; + tsk_size_t size; + const tsk_list_item_t* item; + + if(!self || !TRTP_RTCP_PACKET(self)->header) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + size = TRTP_RTCP_PACKET(self)->header->length_in_bytes; + //if(TRTP_RTCP_PACKET(self)->header->rc > 0){ + // tsk_list_foreach(item, self->blocks){ + // if(item->data){ + // size += TRTP_RTCP_RBLOCK_SIZE; + // } + // } + //} + tsk_list_foreach(item, self->packets) { + if(item->data && TRTP_RTCP_PACKET(item->data)->header) { + size += TRTP_RTCP_PACKET(item->data)->header->length_in_bytes; + } + } + + return size; } diff --git a/tinyRTP/src/rtcp/trtp_rtcp_report_xr.c b/tinyRTP/src/rtcp/trtp_rtcp_report_xr.c index 5fb2697..41e177b 100755 --- a/tinyRTP/src/rtcp/trtp_rtcp_report_xr.c +++ b/tinyRTP/src/rtcp/trtp_rtcp_report_xr.c @@ -2,19 +2,19 @@ * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * * Contact: Mamadou Diop <diopmamadou(at)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. * diff --git a/tinyRTP/src/rtcp/trtp_rtcp_sdes_chunck.c b/tinyRTP/src/rtcp/trtp_rtcp_sdes_chunck.c index 9104580..f8bed63 100755 --- a/tinyRTP/src/rtcp/trtp_rtcp_sdes_chunck.c +++ b/tinyRTP/src/rtcp/trtp_rtcp_sdes_chunck.c @@ -2,19 +2,19 @@ * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * * Contact: Mamadou Diop <diopmamadou(at)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. * @@ -44,27 +44,26 @@ Each chunk consists of an SSRC/CSRC identifier followed by a list of static tsk_object_t* trtp_rtcp_sdes_chunck_ctor(tsk_object_t * self, va_list * app) { - trtp_rtcp_sdes_chunck_t *chunck = self; - if(chunck){ - chunck->items = tsk_list_create(); - } - return self; + trtp_rtcp_sdes_chunck_t *chunck = self; + if(chunck) { + chunck->items = tsk_list_create(); + } + return self; } static tsk_object_t* trtp_rtcp_sdes_chunck_dtor(tsk_object_t * self) -{ - trtp_rtcp_sdes_chunck_t *chunck = self; - if(chunck){ - TSK_OBJECT_SAFE_FREE(chunck->items); - } +{ + trtp_rtcp_sdes_chunck_t *chunck = self; + if(chunck) { + TSK_OBJECT_SAFE_FREE(chunck->items); + } - return self; + return self; } -static const tsk_object_def_t trtp_rtcp_sdes_chunck_def_s = -{ - sizeof(trtp_rtcp_sdes_chunck_t), - trtp_rtcp_sdes_chunck_ctor, - trtp_rtcp_sdes_chunck_dtor, - tsk_null, +static const tsk_object_def_t trtp_rtcp_sdes_chunck_def_s = { + sizeof(trtp_rtcp_sdes_chunck_t), + trtp_rtcp_sdes_chunck_ctor, + trtp_rtcp_sdes_chunck_dtor, + tsk_null, }; const tsk_object_def_t *trtp_rtcp_sdes_chunck_def_t = &trtp_rtcp_sdes_chunck_def_s; @@ -72,119 +71,120 @@ const tsk_object_def_t *trtp_rtcp_sdes_chunck_def_t = &trtp_rtcp_sdes_chunck_def trtp_rtcp_sdes_chunck_t* trtp_rtcp_sdes_chunck_create_null() { - return tsk_object_new(trtp_rtcp_sdes_chunck_def_t); + return tsk_object_new(trtp_rtcp_sdes_chunck_def_t); } trtp_rtcp_sdes_chunck_t* trtp_rtcp_sdes_chunck_create(uint32_t ssrc) { - trtp_rtcp_sdes_chunck_t* chunck; - if((chunck = trtp_rtcp_sdes_chunck_create_null())){ - chunck->ssrc = ssrc; - } - return chunck; + trtp_rtcp_sdes_chunck_t* chunck; + if((chunck = trtp_rtcp_sdes_chunck_create_null())) { + chunck->ssrc = ssrc; + } + return chunck; } trtp_rtcp_sdes_chunck_t* trtp_rtcp_sdes_chunck_deserialize(const void* data, tsk_size_t size) { - trtp_rtcp_sdes_chunck_t* chunck = tsk_null; - const uint8_t* pdata = (uint8_t*)data; - const uint8_t* pend; - if(!data || size < TRTP_RTCP_SDES_CHUNCK_MIN_SIZE){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - pend = (pdata + size); - if((chunck = trtp_rtcp_sdes_chunck_create_null())){ - trtp_rtcp_sdes_item_t* item; - tsk_bool_t is_last_item = tsk_false; - // SSRC/CSRC - chunck->ssrc = (uint32_t)tnet_ntohl_2(pdata); - pdata += TRTP_RTCP_SDES_CHUNCK_SSRC_OR_CSRC_SIZE; - while((pdata < pend) && !is_last_item){ - if((item = trtp_rtcp_sdes_item_deserialize(pdata, (pend-pdata)))){ - is_last_item = (item->type == trtp_rtcp_sdes_item_type_end); - pdata += trtp_rtcp_sdes_item_get_size(item); - tsk_list_push_back_data(chunck->items, (void**)&item); - } - else{ - TSK_DEBUG_ERROR("Failed to deserialize sdes item"); - break; - } - } - } - else{ - TSK_DEBUG_ERROR("Failed to create new sdes_chunck object"); - return tsk_null; - } - - return chunck; + trtp_rtcp_sdes_chunck_t* chunck = tsk_null; + const uint8_t* pdata = (uint8_t*)data; + const uint8_t* pend; + if(!data || size < TRTP_RTCP_SDES_CHUNCK_MIN_SIZE) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + pend = (pdata + size); + if((chunck = trtp_rtcp_sdes_chunck_create_null())) { + trtp_rtcp_sdes_item_t* item; + tsk_bool_t is_last_item = tsk_false; + // SSRC/CSRC + chunck->ssrc = (uint32_t)tnet_ntohl_2(pdata); + pdata += TRTP_RTCP_SDES_CHUNCK_SSRC_OR_CSRC_SIZE; + while((pdata < pend) && !is_last_item) { + if((item = trtp_rtcp_sdes_item_deserialize(pdata, (pend-pdata)))) { + is_last_item = (item->type == trtp_rtcp_sdes_item_type_end); + pdata += trtp_rtcp_sdes_item_get_size(item); + tsk_list_push_back_data(chunck->items, (void**)&item); + } + else { + TSK_DEBUG_ERROR("Failed to deserialize sdes item"); + break; + } + } + } + else { + TSK_DEBUG_ERROR("Failed to create new sdes_chunck object"); + return tsk_null; + } + + return chunck; } int trtp_rtcp_sdes_chunck_serialize_to(const trtp_rtcp_sdes_chunck_t* self, void* data, tsk_size_t size) { - uint8_t* pdata = (uint8_t*)data; - const tsk_list_item_t* item; - const trtp_rtcp_sdes_item_t* sdes_item; - tsk_size_t sdes_item_size; - int ret = 0; - - if(!self || !data || size < trtp_rtcp_sdes_chunck_get_size(self)){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - pdata[0] = self->ssrc >> 24; - pdata[1] = (self->ssrc >> 16) & 0xFF; - pdata[2] = (self->ssrc >> 8) & 0xFF; - pdata[3] = (self->ssrc & 0xFF); - pdata += 4; - - tsk_list_foreach(item, self->items){ - if(!(sdes_item = TRTP_RTCP_SDES_ITEM(item->data))){ - continue; - } - if((ret = trtp_rtcp_sdes_item_serialize_to(sdes_item, pdata, size))){ - TSK_DEBUG_ERROR("SDES item serialization failed"); - goto bail; - } - sdes_item_size = trtp_rtcp_sdes_item_get_size(sdes_item); - pdata += sdes_item_size; size -= sdes_item_size; - } + uint8_t* pdata = (uint8_t*)data; + const tsk_list_item_t* item; + const trtp_rtcp_sdes_item_t* sdes_item; + tsk_size_t sdes_item_size; + int ret = 0; + + if(!self || !data || size < trtp_rtcp_sdes_chunck_get_size(self)) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + pdata[0] = self->ssrc >> 24; + pdata[1] = (self->ssrc >> 16) & 0xFF; + pdata[2] = (self->ssrc >> 8) & 0xFF; + pdata[3] = (self->ssrc & 0xFF); + pdata += 4; + + tsk_list_foreach(item, self->items) { + if(!(sdes_item = TRTP_RTCP_SDES_ITEM(item->data))) { + continue; + } + if((ret = trtp_rtcp_sdes_item_serialize_to(sdes_item, pdata, size))) { + TSK_DEBUG_ERROR("SDES item serialization failed"); + goto bail; + } + sdes_item_size = trtp_rtcp_sdes_item_get_size(sdes_item); + pdata += sdes_item_size; + size -= sdes_item_size; + } bail: - return ret; + return ret; } int trtp_rtcp_sdes_chunck_add_item(trtp_rtcp_sdes_chunck_t* self, trtp_rtcp_sdes_item_type_t type, const void* data, uint8_t length) { - trtp_rtcp_sdes_item_t *item; - if(!self || !self->items){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if((item = trtp_rtcp_sdes_item_create(type, data, length))){ - tsk_list_push_back_data(self->items, (void**)&item); - } - return 0; + trtp_rtcp_sdes_item_t *item; + if(!self || !self->items) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if((item = trtp_rtcp_sdes_item_create(type, data, length))) { + tsk_list_push_back_data(self->items, (void**)&item); + } + return 0; } tsk_size_t trtp_rtcp_sdes_chunck_get_size(const trtp_rtcp_sdes_chunck_t* self) { - const tsk_list_item_t* item; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - else{ - tsk_size_t size = TRTP_RTCP_SDES_CHUNCK_SSRC_OR_CSRC_SIZE; - tsk_list_foreach(item, self->items){ - size += trtp_rtcp_sdes_item_get_size(TRTP_RTCP_SDES_ITEM(item->data)); - } - if(size & 0x03){//Each chunk starts on a 32-bit boundary - size += (4 - (size & 0x03)); - } - return size; - } + const tsk_list_item_t* item; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + else { + tsk_size_t size = TRTP_RTCP_SDES_CHUNCK_SSRC_OR_CSRC_SIZE; + tsk_list_foreach(item, self->items) { + size += trtp_rtcp_sdes_item_get_size(TRTP_RTCP_SDES_ITEM(item->data)); + } + if(size & 0x03) { //Each chunk starts on a 32-bit boundary + size += (4 - (size & 0x03)); + } + return size; + } } diff --git a/tinyRTP/src/rtcp/trtp_rtcp_sdes_item.c b/tinyRTP/src/rtcp/trtp_rtcp_sdes_item.c index 7f22537..6d70a46 100755 --- a/tinyRTP/src/rtcp/trtp_rtcp_sdes_item.c +++ b/tinyRTP/src/rtcp/trtp_rtcp_sdes_item.c @@ -2,19 +2,19 @@ * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * * Contact: Mamadou Diop <diopmamadou(at)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. * @@ -32,117 +32,118 @@ static tsk_object_t* trtp_rtcp_sdes_item_ctor(tsk_object_t * self, va_list * app) { - trtp_rtcp_sdes_item_t *item = self; - if(item){ - } - return self; + trtp_rtcp_sdes_item_t *item = self; + if(item) { + } + return self; } static tsk_object_t* trtp_rtcp_sdes_item_dtor(tsk_object_t * self) -{ - trtp_rtcp_sdes_item_t *item = self; - if(item){ - TSK_OBJECT_SAFE_FREE(item->data); - } +{ + trtp_rtcp_sdes_item_t *item = self; + if(item) { + TSK_OBJECT_SAFE_FREE(item->data); + } - return self; + return self; } -static const tsk_object_def_t trtp_rtcp_sdes_item_def_s = -{ - sizeof(trtp_rtcp_sdes_item_t), - trtp_rtcp_sdes_item_ctor, - trtp_rtcp_sdes_item_dtor, - tsk_null, +static const tsk_object_def_t trtp_rtcp_sdes_item_def_s = { + sizeof(trtp_rtcp_sdes_item_t), + trtp_rtcp_sdes_item_ctor, + trtp_rtcp_sdes_item_dtor, + tsk_null, }; const tsk_object_def_t *trtp_rtcp_sdes_item_def_t = &trtp_rtcp_sdes_item_def_s; trtp_rtcp_sdes_item_t* _trtp_rtcp_sdes_item_create_null(trtp_rtcp_sdes_item_type_t type) { - return tsk_object_new(trtp_rtcp_sdes_item_def_t); + return tsk_object_new(trtp_rtcp_sdes_item_def_t); } trtp_rtcp_sdes_item_t* trtp_rtcp_sdes_item_create(trtp_rtcp_sdes_item_type_t type, const void* data, uint8_t length) { - trtp_rtcp_sdes_item_t* item; - if(!(item = _trtp_rtcp_sdes_item_create_null(type))){ - TSK_DEBUG_ERROR("Failed to create new SDES item"); - return tsk_null; - } - item->type = type; - if(data && length){ - item->data = tsk_buffer_create(data, length); - } - - return item; + trtp_rtcp_sdes_item_t* item; + if(!(item = _trtp_rtcp_sdes_item_create_null(type))) { + TSK_DEBUG_ERROR("Failed to create new SDES item"); + return tsk_null; + } + item->type = type; + if(data && length) { + item->data = tsk_buffer_create(data, length); + } + + return item; } trtp_rtcp_sdes_item_t* trtp_rtcp_sdes_item_deserialize(const void* data, tsk_size_t size) { - const uint8_t* pdata = (const uint8_t*)data; - - if(!data || !size){ - TSK_DEBUG_ERROR("Invlaid parameter"); - return tsk_null; - } - - if(pdata[0] == trtp_rtcp_sdes_item_type_end){ - return trtp_rtcp_sdes_item_create(trtp_rtcp_sdes_item_type_end, tsk_null, 0); - } - - if(size < TRTP_RTCP_SDES_ITEM_MIN_SIZE || size < (tsk_size_t)(pdata[1] + 2)){ - TSK_DEBUG_ERROR("Too short"); - return tsk_null; - } - - return trtp_rtcp_sdes_item_create((trtp_rtcp_sdes_item_type_t)pdata[0], &pdata[2], pdata[1]); + const uint8_t* pdata = (const uint8_t*)data; + + if(!data || !size) { + TSK_DEBUG_ERROR("Invlaid parameter"); + return tsk_null; + } + + if(pdata[0] == trtp_rtcp_sdes_item_type_end) { + return trtp_rtcp_sdes_item_create(trtp_rtcp_sdes_item_type_end, tsk_null, 0); + } + + if(size < TRTP_RTCP_SDES_ITEM_MIN_SIZE || size < (tsk_size_t)(pdata[1] + 2)) { + TSK_DEBUG_ERROR("Too short"); + return tsk_null; + } + + return trtp_rtcp_sdes_item_create((trtp_rtcp_sdes_item_type_t)pdata[0], &pdata[2], pdata[1]); } tsk_buffer_t* trtp_rtcp_sdes_item_serialize(const trtp_rtcp_sdes_item_t* self) { - tsk_buffer_t*buffer = tsk_null; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - if((buffer = tsk_buffer_create(tsk_null, trtp_rtcp_sdes_item_get_size(self)))){ - if(trtp_rtcp_sdes_item_serialize_to(self, buffer->data, buffer->size) != 0){ - TSK_OBJECT_SAFE_FREE(buffer); - } - } - return buffer; + tsk_buffer_t*buffer = tsk_null; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + if((buffer = tsk_buffer_create(tsk_null, trtp_rtcp_sdes_item_get_size(self)))) { + if(trtp_rtcp_sdes_item_serialize_to(self, buffer->data, buffer->size) != 0) { + TSK_OBJECT_SAFE_FREE(buffer); + } + } + return buffer; } int trtp_rtcp_sdes_item_serialize_to(const trtp_rtcp_sdes_item_t* self, void* data, tsk_size_t size) { - if(!self || !data || (size < trtp_rtcp_sdes_item_get_size(self))){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(self->type == trtp_rtcp_sdes_item_type_end){ - ((uint8_t*)data)[0] = trtp_rtcp_sdes_item_type_end; - } - else{ - ((uint8_t*)data)[0] = self->type; - if(self->data){ - ((uint8_t*)data)[1] = (uint8_t)self->data->size; - memcpy(&((uint8_t*)data)[2], self->data->data, self->data->size); - } - else{ - ((uint8_t*)data)[1] = 0; - } - } - return 0; + if(!self || !data || (size < trtp_rtcp_sdes_item_get_size(self))) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(self->type == trtp_rtcp_sdes_item_type_end) { + ((uint8_t*)data)[0] = trtp_rtcp_sdes_item_type_end; + } + else { + ((uint8_t*)data)[0] = self->type; + if(self->data) { + ((uint8_t*)data)[1] = (uint8_t)self->data->size; + memcpy(&((uint8_t*)data)[2], self->data->data, self->data->size); + } + else { + ((uint8_t*)data)[1] = 0; + } + } + return 0; } tsk_size_t trtp_rtcp_sdes_item_get_size(const trtp_rtcp_sdes_item_t* self) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - switch(self->type){ - case trtp_rtcp_sdes_item_type_end: return 1; - default: return 2 + (self->data ? self->data->size : 0); - } + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + switch(self->type) { + case trtp_rtcp_sdes_item_type_end: + return 1; + default: + return 2 + (self->data ? self->data->size : 0); + } } diff --git a/tinyRTP/src/rtcp/trtp_rtcp_session.c b/tinyRTP/src/rtcp/trtp_rtcp_session.c index b2f4733..226b0cd 100755 --- a/tinyRTP/src/rtcp/trtp_rtcp_session.c +++ b/tinyRTP/src/rtcp/trtp_rtcp_session.c @@ -2,19 +2,19 @@ * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * * Contact: Mamadou Diop <diopmamadou(at)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. * @@ -56,8 +56,14 @@ #include <limits.h> /* INT_MAX */ #ifdef _MSC_VER -static double drand48() { return (((double)rand()) / RAND_MAX); } -static void srand48(long sv) { srand((unsigned int) sv); } +static double drand48() +{ + return (((double)rand()) / RAND_MAX); +} +static void srand48(long sv) +{ + srand((unsigned int) sv); +} #endif #define RTCP_BW (160 * 50) // FIXME: default bandwidth (octet/second) @@ -70,19 +76,17 @@ static void srand48(long sv) { srand((unsigned int) sv); } typedef double time_tp; typedef void* packet_; -typedef enum event_ -{ - EVENT_BYE, - EVENT_REPORT, - EVENT_RTP +typedef enum event_ { + EVENT_BYE, + EVENT_REPORT, + EVENT_RTP } event_; -typedef enum PacketType_ -{ - PACKET_RTCP_REPORT, - PACKET_BYE, - PACKET_RTP, +typedef enum PacketType_ { + PACKET_RTCP_REPORT, + PACKET_BYE, + PACKET_RTP, } PacketType_; @@ -90,53 +94,51 @@ PacketType_; #define TRTP_RTCP_SOURCE(self) ((trtp_rtcp_source_t*)self) -typedef struct trtp_rtcp_source_s -{ - TSK_DECLARE_OBJECT; - - uint32_t ssrc; /* source's ssrc */ - uint16_t max_seq; /* highest seq. number seen */ - uint32_t cycles; /* shifted count of seq. number cycles */ - uint32_t base_seq; /* base seq number */ - uint32_t bad_seq; /* last 'bad' seq number + 1 */ - uint32_t probation; /* sequ. packets till source is valid */ - uint32_t received; /* packets received */ - uint32_t expected_prior; /* packet expected at last interval */ - uint32_t received_prior; /* packet received at last interval */ - uint32_t transit; /* relative trans time for prev pkt */ - double jitter; /* estimated jitter */ - - uint32_t base_ts; /* base timestamp */ - uint32_t max_ts; /* highest timestamp number seen */ - uint32_t rate; /* codec sampling rate */ - - uint32_t ntp_msw; /* last received NTP timestamp from RTCP sender */ - uint32_t ntp_lsw; /* last received NTP timestamp from RTCP sender */ - uint64_t dlsr; /* delay since last SR */ +typedef struct trtp_rtcp_source_s { + TSK_DECLARE_OBJECT; + + uint32_t ssrc; /* source's ssrc */ + uint16_t max_seq; /* highest seq. number seen */ + uint32_t cycles; /* shifted count of seq. number cycles */ + uint32_t base_seq; /* base seq number */ + uint32_t bad_seq; /* last 'bad' seq number + 1 */ + uint32_t probation; /* sequ. packets till source is valid */ + uint32_t received; /* packets received */ + uint32_t expected_prior; /* packet expected at last interval */ + uint32_t received_prior; /* packet received at last interval */ + uint32_t transit; /* relative trans time for prev pkt */ + double jitter; /* estimated jitter */ + + uint32_t base_ts; /* base timestamp */ + uint32_t max_ts; /* highest timestamp number seen */ + uint32_t rate; /* codec sampling rate */ + + uint32_t ntp_msw; /* last received NTP timestamp from RTCP sender */ + uint32_t ntp_lsw; /* last received NTP timestamp from RTCP sender */ + uint64_t dlsr; /* delay since last SR */ } trtp_rtcp_source_t; typedef tsk_list_t trtp_rtcp_sources_L_t; /**< List of @ref trtp_rtcp_header_t elements */ static tsk_object_t* trtp_rtcp_source_ctor(tsk_object_t * self, va_list * app) { - trtp_rtcp_source_t *source = self; - if(source){ - } - return self; + trtp_rtcp_source_t *source = self; + if(source) { + } + return self; } static tsk_object_t* trtp_rtcp_source_dtor(tsk_object_t * self) -{ - trtp_rtcp_source_t *source = self; - if(source){ - } - return self; -} -static const tsk_object_def_t trtp_rtcp_source_def_s = { - sizeof(trtp_rtcp_source_t), - trtp_rtcp_source_ctor, - trtp_rtcp_source_dtor, - tsk_null, + trtp_rtcp_source_t *source = self; + if(source) { + } + return self; +} +static const tsk_object_def_t trtp_rtcp_source_def_s = { + sizeof(trtp_rtcp_source_t), + trtp_rtcp_source_ctor, + trtp_rtcp_source_dtor, + tsk_null, }; const tsk_object_def_t *trtp_rtcp_source_def_t = &trtp_rtcp_source_def_s; @@ -145,113 +147,117 @@ static tsk_bool_t _trtp_rtcp_source_update_seq(trtp_rtcp_source_t* self, uint16_ static int __pred_find_source_by_ssrc(const tsk_list_item_t *item, const void *pssrc) { - if(item && item->data){ - trtp_rtcp_source_t *source = item->data; - return source->ssrc - *((uint32_t*)pssrc); - } - return -1; + if(item && item->data) { + trtp_rtcp_source_t *source = item->data; + return source->ssrc - *((uint32_t*)pssrc); + } + return -1; } static trtp_rtcp_source_t* _trtp_rtcp_source_create(uint32_t ssrc, uint16_t seq, uint32_t ts) { - trtp_rtcp_source_t* source; - if(!(source = tsk_object_new(trtp_rtcp_source_def_t))){ - TSK_DEBUG_ERROR("Failed to create source object"); - return tsk_null; - } - - _trtp_rtcp_source_init_seq(source, seq, ts); - source->ssrc = ssrc; - source->max_seq = seq - 1; - source->probation = MIN_SEQUENTIAL; - source->rate = CODEC_RATE;//FIXME - - return source; + trtp_rtcp_source_t* source; + if(!(source = tsk_object_new(trtp_rtcp_source_def_t))) { + TSK_DEBUG_ERROR("Failed to create source object"); + return tsk_null; + } + + _trtp_rtcp_source_init_seq(source, seq, ts); + source->ssrc = ssrc; + source->max_seq = seq - 1; + source->probation = MIN_SEQUENTIAL; + source->rate = CODEC_RATE;//FIXME + + return source; } static int _trtp_rtcp_source_init_seq(trtp_rtcp_source_t* self, uint16_t seq, uint32_t ts) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - self->base_seq = seq; - self->max_seq = seq; - self->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */ - self->cycles = 0; - self->received = 0; - self->received_prior = 0; - self->expected_prior = 0; - self->base_ts = ts; - self->max_ts = ts; - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + self->base_seq = seq; + self->max_seq = seq; + self->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */ + self->cycles = 0; + self->received = 0; + self->received_prior = 0; + self->expected_prior = 0; + self->base_ts = ts; + self->max_ts = ts; + return 0; } static tsk_bool_t _trtp_rtcp_source_update_seq(trtp_rtcp_source_t* self, uint16_t seq, uint32_t ts) { - uint16_t udelta; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_false; - } - - udelta = seq - self->max_seq; - - /* - * Source is not valid until MIN_SEQUENTIAL packets with - * sequential sequence numbers have been received. - */ - if (self->probation) { - /* packet is in sequence */ - if (seq == self->max_seq + 1) { - self->probation--; - self->max_seq = seq; - self->max_ts = ts; - if (self->probation == 0) { - _trtp_rtcp_source_init_seq(self, seq, ts); - self->received++; - return tsk_true; - } - } else { - self->probation = MIN_SEQUENTIAL - 1; - self->max_seq = seq; - self->max_ts = ts; - } - return tsk_false; - } else if (udelta < MAX_DROPOUT) { - /* in order, with permissible gap */ - if (seq < self->max_seq) { - /* - * Sequence number wrapped - count another 64K cycle. - */ - self->cycles += RTP_SEQ_MOD; - } - self->max_seq = seq; - self->max_ts = ts; - } else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) { - /* the sequence number made a very large jump */ - if (seq == self->bad_seq) { - /* - * Two sequential packets -- assume that the other side - * restarted without telling us so just re-sync - * (i.e., pretend this was the first packet). - */ - _trtp_rtcp_source_init_seq(self, seq, ts); - } - else { - self->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1); - return tsk_false; - } - } else { - /* duplicate or reordered packet */ - } - self->received++; - return tsk_true; + uint16_t udelta; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_false; + } + + udelta = seq - self->max_seq; + + /* + * Source is not valid until MIN_SEQUENTIAL packets with + * sequential sequence numbers have been received. + */ + if (self->probation) { + /* packet is in sequence */ + if (seq == self->max_seq + 1) { + self->probation--; + self->max_seq = seq; + self->max_ts = ts; + if (self->probation == 0) { + _trtp_rtcp_source_init_seq(self, seq, ts); + self->received++; + return tsk_true; + } + } + else { + self->probation = MIN_SEQUENTIAL - 1; + self->max_seq = seq; + self->max_ts = ts; + } + return tsk_false; + } + else if (udelta < MAX_DROPOUT) { + /* in order, with permissible gap */ + if (seq < self->max_seq) { + /* + * Sequence number wrapped - count another 64K cycle. + */ + self->cycles += RTP_SEQ_MOD; + } + self->max_seq = seq; + self->max_ts = ts; + } + else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) { + /* the sequence number made a very large jump */ + if (seq == self->bad_seq) { + /* + * Two sequential packets -- assume that the other side + * restarted without telling us so just re-sync + * (i.e., pretend this was the first packet). + */ + _trtp_rtcp_source_init_seq(self, seq, ts); + } + else { + self->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1); + return tsk_false; + } + } + else { + /* duplicate or reordered packet */ + } + self->received++; + return tsk_true; } static tsk_bool_t _trtp_rtcp_source_is_probed(const trtp_rtcp_source_t* self) { - return (self && self->probation == 0); + return (self && self->probation == 0); } @@ -261,118 +267,120 @@ static tsk_bool_t _trtp_rtcp_source_is_probed(const trtp_rtcp_source_t* self) typedef time_tp (*tc_f)(); -static time_tp _trtp_rtcp_session_tc() { return (time_tp)tsk_time_now(); } - -typedef struct trtp_rtcp_session_s +static time_tp _trtp_rtcp_session_tc() { - TSK_DECLARE_OBJECT; - - tsk_bool_t is_started; - tnet_fd_t local_fd; + return (time_tp)tsk_time_now(); +} + +typedef struct trtp_rtcp_session_s { + TSK_DECLARE_OBJECT; + + tsk_bool_t is_started; + tnet_fd_t local_fd; struct tnet_transport_s* transport; // not starter -> do not stop - const struct sockaddr * remote_addr; - struct tnet_ice_ctx_s* ice_ctx; // not starter -> do not stop - tsk_bool_t is_ice_turn_active; - - const void* callback_data; - trtp_rtcp_cb_f callback; - - int32_t app_bw_max_upload; // application specific (kbps) - int32_t app_bw_max_download; // application specific (kbps) - - struct{ - tsk_timer_manager_handle_t* handle_global; - tsk_timer_id_t id_report; - tsk_timer_id_t id_bye; - } timer; - - trtp_rtcp_source_t* source_local; /**< local source */ - trtp_rtcp_report_sdes_t* sdes; - uint64_t time_start; /**< Start time in millis (NOT in NTP unit yet) */ - - // <RTCP-FB> - uint8_t fir_seqnr; - // </RTCP-FB> - - // <sender> - char* cname; - uint32_t packets_count; - uint32_t octets_count; - // </sender> - - // <others> - time_tp tp; /**< the last time an RTCP packet was transmitted; */ - tc_f tc; /**< the current time */ - time_tp tn; /**< the next scheduled transmission time of an RTCP packet */ - int32_t pmembers; /**< the estimated number of session members at the time tn was last recomputed */ - int32_t members; /**< the most current estimate for the number of session members */ - int32_t senders; /**< the most current estimate for the number of senders in the session */ - double rtcp_bw; /**< The target RTCP bandwidth, i.e., the total bandwidth + const struct sockaddr * remote_addr; + struct tnet_ice_ctx_s* ice_ctx; // not starter -> do not stop + tsk_bool_t is_ice_turn_active; + + const void* callback_data; + trtp_rtcp_cb_f callback; + + int32_t app_bw_max_upload; // application specific (kbps) + int32_t app_bw_max_download; // application specific (kbps) + float app_jcng_q; // application specific for jitter buffer congestion estimation (quality in [0, 1]) + + struct { + tsk_timer_manager_handle_t* handle_global; + tsk_timer_id_t id_report; + tsk_timer_id_t id_bye; + } timer; + + trtp_rtcp_source_t* source_local; /**< local source */ + trtp_rtcp_report_sdes_t* sdes; + uint64_t time_start; /**< Start time in millis (NOT in NTP unit yet) */ + + // <RTCP-FB> + uint8_t fir_seqnr; + // </RTCP-FB> + + // <sender> + char* cname; + uint32_t packets_count; + uint32_t octets_count; + // </sender> + + // <others> + time_tp tp; /**< the last time an RTCP packet was transmitted; */ + tc_f tc; /**< the current time */ + time_tp tn; /**< the next scheduled transmission time of an RTCP packet */ + int32_t pmembers; /**< the estimated number of session members at the time tn was last recomputed */ + int32_t members; /**< the most current estimate for the number of session members */ + int32_t senders; /**< the most current estimate for the number of senders in the session */ + double rtcp_bw; /**< The target RTCP bandwidth, i.e., the total bandwidth that will be used for RTCP packets by all members of this session, in octets per second. This will be a specified fraction of the "session bandwidth" parameter supplied to the application at startup*/ - tsk_bool_t we_sent; /**< Flag that is true if the application has sent data since the 2nd previous RTCP report was transmitted */ - double avg_rtcp_size; /**< The average compound RTCP packet size, in octets, + tsk_bool_t we_sent; /**< Flag that is true if the application has sent data since the 2nd previous RTCP report was transmitted */ + double avg_rtcp_size; /**< The average compound RTCP packet size, in octets, over all RTCP packets sent and received by this participant. The size includes lower-layer transport and network protocol headers (e.g., UDP and IP) as explained in Section 6.2*/ - tsk_bool_t initial; /**< Flag that is true if the application has not yet sent an RTCP packet */ - // </others> + tsk_bool_t initial; /**< Flag that is true if the application has not yet sent an RTCP packet */ + // </others> - trtp_rtcp_sources_L_t *sources; + trtp_rtcp_sources_L_t *sources; - TSK_DECLARE_SAFEOBJ; + TSK_DECLARE_SAFEOBJ; #if HAVE_SRTP - struct{ - const srtp_t* session; - } srtp; + struct { + const srtp_t* session; + } srtp; #endif } trtp_rtcp_session_t; static tsk_object_t* trtp_rtcp_session_ctor(tsk_object_t * self, va_list * app) { - trtp_rtcp_session_t *session = self; - if(session){ - session->app_bw_max_upload = INT_MAX; // INT_MAX or <=0 means undefined - session->app_bw_max_download = INT_MAX; // INT_MAX or <=0 means undefined - session->sources = tsk_list_create(); - session->timer.id_report = TSK_INVALID_TIMER_ID; - session->timer.id_bye = TSK_INVALID_TIMER_ID; - session->tc = _trtp_rtcp_session_tc; - // get a handle for the global timer manager - session->timer.handle_global = tsk_timer_mgr_global_ref(); - tsk_safeobj_init(session); - } - return self; + trtp_rtcp_session_t *session = self; + if(session) { + session->app_bw_max_upload = INT_MAX; // INT_MAX or <=0 means undefined + session->app_bw_max_download = INT_MAX; // INT_MAX or <=0 means undefined + session->sources = tsk_list_create(); + session->timer.id_report = TSK_INVALID_TIMER_ID; + session->timer.id_bye = TSK_INVALID_TIMER_ID; + session->tc = _trtp_rtcp_session_tc; + // get a handle for the global timer manager + session->timer.handle_global = tsk_timer_mgr_global_ref(); + tsk_safeobj_init(session); + } + return self; } static tsk_object_t* trtp_rtcp_session_dtor(tsk_object_t * self) -{ - trtp_rtcp_session_t *session = self; - if(session){ - trtp_rtcp_session_stop(session); - - TSK_OBJECT_SAFE_FREE(session->sources); - TSK_OBJECT_SAFE_FREE(session->source_local); - TSK_OBJECT_SAFE_FREE(session->sdes); - TSK_OBJECT_SAFE_FREE(session->ice_ctx); // not starter -> do not stop - TSK_FREE(session->cname); +{ + trtp_rtcp_session_t *session = self; + if(session) { + trtp_rtcp_session_stop(session); + + TSK_OBJECT_SAFE_FREE(session->sources); + TSK_OBJECT_SAFE_FREE(session->source_local); + TSK_OBJECT_SAFE_FREE(session->sdes); + TSK_OBJECT_SAFE_FREE(session->ice_ctx); // not starter -> do not stop + TSK_FREE(session->cname); TSK_OBJECT_SAFE_FREE(session->transport); // not starter -> do not stop - // release the handle for the global timer manager - tsk_timer_mgr_global_unref(&session->timer.handle_global); + // release the handle for the global timer manager + tsk_timer_mgr_global_unref(&session->timer.handle_global); - tsk_safeobj_deinit(session); - } - return self; + tsk_safeobj_deinit(session); + } + return self; } -static const tsk_object_def_t trtp_rtcp_session_def_s = -{ - sizeof(trtp_rtcp_session_t), - trtp_rtcp_session_ctor, - trtp_rtcp_session_dtor, - tsk_null, +static const tsk_object_def_t trtp_rtcp_session_def_s = { + sizeof(trtp_rtcp_session_t), + trtp_rtcp_session_ctor, + trtp_rtcp_session_dtor, + tsk_null, }; const tsk_object_def_t *trtp_rtcp_session_def_t = &trtp_rtcp_session_def_s; @@ -394,378 +402,394 @@ static void SendBYEPacket(trtp_rtcp_session_t* session, event_ e); trtp_rtcp_session_t* trtp_rtcp_session_create(uint32_t ssrc, const char* cname) { - trtp_rtcp_session_t* session; - - if(!(session = tsk_object_new(trtp_rtcp_session_def_t))){ - TSK_DEBUG_ERROR("Failed to create new session object"); - return tsk_null; - } - - // RFC 3550 - 6.3.2 Initialization - if(!(session->source_local = _trtp_rtcp_source_create(ssrc, 0, 0))){ - TSK_DEBUG_ERROR("Failed to create new local source"); - TSK_OBJECT_SAFE_FREE(session); - goto bail; - } - _trtp_rtcp_session_add_source(session, session->source_local); - session->initial = tsk_true; - session->we_sent = tsk_false; - session->senders = 1; - session->members = 1; - session->rtcp_bw = RTCP_BW;//FIXME: as parameter from the code, Also added possiblities to update this value - session->cname = tsk_strdup(cname); - + trtp_rtcp_session_t* session; + + if(!(session = tsk_object_new(trtp_rtcp_session_def_t))) { + TSK_DEBUG_ERROR("Failed to create new session object"); + return tsk_null; + } + + // RFC 3550 - 6.3.2 Initialization + if(!(session->source_local = _trtp_rtcp_source_create(ssrc, 0, 0))) { + TSK_DEBUG_ERROR("Failed to create new local source"); + TSK_OBJECT_SAFE_FREE(session); + goto bail; + } + _trtp_rtcp_session_add_source(session, session->source_local); + session->initial = tsk_true; + session->we_sent = tsk_false; + session->senders = 1; + session->members = 1; + session->rtcp_bw = RTCP_BW;//FIXME: as parameter from the code, Also added possiblities to update this value + session->cname = tsk_strdup(cname); + bail: - return session; + return session; } struct trtp_rtcp_session_s* trtp_rtcp_session_create_2(struct tnet_ice_ctx_s* ice_ctx, uint32_t ssrc, const char* cname) { - struct trtp_rtcp_session_s* session = trtp_rtcp_session_create(ssrc, cname); - if (session) { - if ((session->ice_ctx = tsk_object_ref(ice_ctx))) { - session->is_ice_turn_active = tnet_ice_ctx_is_turn_rtcp_active(session->ice_ctx); - } - } - return session; + struct trtp_rtcp_session_s* session = trtp_rtcp_session_create(ssrc, cname); + if (session) { + if ((session->ice_ctx = tsk_object_ref(ice_ctx))) { + session->is_ice_turn_active = tnet_ice_ctx_is_turn_rtcp_active(session->ice_ctx); + } + } + return session; } int trtp_rtcp_session_set_callback(trtp_rtcp_session_t* self, trtp_rtcp_cb_f callback, const void* callback_data) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - tsk_safeobj_lock(self); - self->callback = callback; - self->callback_data = callback_data; - tsk_safeobj_unlock(self); - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + tsk_safeobj_lock(self); + self->callback = callback; + self->callback_data = callback_data; + tsk_safeobj_unlock(self); + return 0; } #if HAVE_SRTP int trtp_rtcp_session_set_srtp_sess(trtp_rtcp_session_t* self, const srtp_t* session) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - tsk_safeobj_lock(self); - self->srtp.session = session; - tsk_safeobj_unlock(self); + tsk_safeobj_lock(self); + self->srtp.session = session; + tsk_safeobj_unlock(self); - return 0; + return 0; } #endif -int trtp_rtcp_session_set_app_bandwidth_max(trtp_rtcp_session_t* self, int32_t bw_upload_kbps, int32_t bw_download_kbps) +int trtp_rtcp_session_set_app_bw_and_jcng(trtp_rtcp_session_t* self, int32_t bw_upload_kbps, int32_t bw_download_kbps, float jcng_q) { - trtp_rtcp_report_rr_t* rr; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - tsk_safeobj_lock(self); - - self->app_bw_max_upload = bw_upload_kbps; - self->app_bw_max_download = bw_download_kbps; - - if(self->is_started && self->source_local && self->app_bw_max_download > 0 && self->app_bw_max_download != INT_MAX){ // INT_MAX or <=0 means undefined - tsk_list_item_t* item; - uint32_t media_ssrc_list[256] = {0}; - uint32_t media_ssrc_list_count = 0; - // retrieve sources as array - tsk_list_foreach(item, self->sources){ - if(!item->data){ - continue; - } - if((media_ssrc_list_count + 1) < sizeof(media_ssrc_list)/sizeof(media_ssrc_list[0])){ - media_ssrc_list[media_ssrc_list_count++] = TRTP_RTCP_SOURCE(item->data)->ssrc; - } - } - // create RTCP-RR packet and send it over the network - if(media_ssrc_list_count > 0 && (rr = trtp_rtcp_report_rr_create_2(self->source_local->ssrc))){ - // app_bw_max_download unit is kbps while create_afb_remb() expect bps - trtp_rtcp_report_psfb_t* psfb_afb_remb = trtp_rtcp_report_psfb_create_afb_remb(self->source_local->ssrc/*sender SSRC*/, media_ssrc_list, media_ssrc_list_count, (self->app_bw_max_download * 1024)); - if(psfb_afb_remb){ - TSK_DEBUG_INFO("Packing RTCP-AFB-REMB (bw_dwn=%d kbps) for outgoing RTCP-RR", self->app_bw_max_download); - if(trtp_rtcp_packet_add_packet((trtp_rtcp_packet_t*)rr, (trtp_rtcp_packet_t*)psfb_afb_remb, tsk_false) == 0){ - _trtp_rtcp_session_send_pkt(self, (trtp_rtcp_packet_t*)rr); - } - TSK_OBJECT_SAFE_FREE(psfb_afb_remb); - } - TSK_OBJECT_SAFE_FREE(rr); - } - } - - tsk_safeobj_unlock(self); - - return 0; + trtp_rtcp_report_rr_t* rr; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + tsk_safeobj_lock(self); + + self->app_bw_max_upload = bw_upload_kbps; + self->app_bw_max_download = bw_download_kbps; + self->app_jcng_q = jcng_q; + + if(self->is_started && self->source_local) { // INT_MAX or <=0 means undefined + tsk_list_item_t* item; + uint32_t media_ssrc_list[256] = {0}; + uint32_t media_ssrc_list_count = 0; + // retrieve sources as array + tsk_list_foreach(item, self->sources) { + if(!item->data) { + continue; + } + if((media_ssrc_list_count + 1) < sizeof(media_ssrc_list)/sizeof(media_ssrc_list[0])) { + media_ssrc_list[media_ssrc_list_count++] = TRTP_RTCP_SOURCE(item->data)->ssrc; + } + } + // create RTCP-RR packet and send it over the network + if (media_ssrc_list_count > 0 && (rr = trtp_rtcp_report_rr_create_2(self->source_local->ssrc))) { + // RTCP-REMB + if (self->app_bw_max_download > 0 && self->app_bw_max_download != INT_MAX) { + // app_bw_max_download unit is kbps while create_afb_remb() expect bps + trtp_rtcp_report_psfb_t* psfb_afb_remb = trtp_rtcp_report_psfb_create_afb_remb(self->source_local->ssrc/*sender SSRC*/, media_ssrc_list, media_ssrc_list_count, (self->app_bw_max_download << 10)); + if (psfb_afb_remb) { + TSK_DEBUG_INFO("Packing RTCP-AFB-REMB (bw_dwn=%d kbps) for outgoing RTCP-RR", self->app_bw_max_download); + trtp_rtcp_packet_add_packet((trtp_rtcp_packet_t*)rr, (trtp_rtcp_packet_t*)psfb_afb_remb, tsk_false); + TSK_OBJECT_SAFE_FREE(psfb_afb_remb); + } + } + // RTCP-JCNG + if (self->app_jcng_q > 0.f && self->app_jcng_q <= 1.f) { + // app_bw_max_download unit is kbps while create_afb_remb() expect bps + trtp_rtcp_report_psfb_t* psfb_afb_jcng = trtp_rtcp_report_psfb_create_afb_jcng(self->source_local->ssrc/*sender SSRC*/, media_ssrc_list, media_ssrc_list_count, self->app_jcng_q); + if (psfb_afb_jcng) { + TSK_DEBUG_INFO("Packing RTCP-AFB-JCNG (q=%f) for outgoing RTCP-RR", self->app_jcng_q); + trtp_rtcp_packet_add_packet((trtp_rtcp_packet_t*)rr, (trtp_rtcp_packet_t*)psfb_afb_jcng, tsk_false); + TSK_OBJECT_SAFE_FREE(psfb_afb_jcng); + } + } + // send the RR message + _trtp_rtcp_session_send_pkt(self, (trtp_rtcp_packet_t*)rr); + TSK_OBJECT_SAFE_FREE(rr); + } + } + + tsk_safeobj_unlock(self); + + return 0; } int trtp_rtcp_session_start(trtp_rtcp_session_t* self, tnet_fd_t local_fd, const struct sockaddr * remote_addr) { - int ret; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(self->is_started){ - TSK_DEBUG_WARN("Already started"); - return 0; - } - - // start global timer manager - if((ret = tsk_timer_manager_start(self->timer.handle_global))){ - TSK_DEBUG_ERROR("Failed to start timer"); - return ret; - } - - self->local_fd = local_fd; - self->remote_addr = remote_addr; - - // Send Initial RR (mandatory) - Schedule(self, 0., EVENT_REPORT); - - // set start time - self->time_start = tsk_time_now(); - - self->is_started = tsk_true; - - return ret; + int ret; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(self->is_started) { + TSK_DEBUG_WARN("Already started"); + return 0; + } + + // start global timer manager + if((ret = tsk_timer_manager_start(self->timer.handle_global))) { + TSK_DEBUG_ERROR("Failed to start timer"); + return ret; + } + + self->local_fd = local_fd; + self->remote_addr = remote_addr; + + // Send Initial RR (mandatory) + Schedule(self, 0., EVENT_REPORT); + + // set start time + self->time_start = tsk_time_now(); + + self->is_started = tsk_true; + + return ret; } int trtp_rtcp_session_stop(trtp_rtcp_session_t* self) { - int ret = 0; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(self->is_started){ - // send BYE synchronous way - SendBYEPacket(self, EVENT_REPORT); - - // this is a global timer shared by many components -> stopping it won't remove - // all scheduled items as it could continue running if still used - tsk_safeobj_lock(self); // must - if(TSK_TIMER_ID_IS_VALID(self->timer.id_bye)){ - tsk_timer_manager_cancel(self->timer.handle_global, self->timer.id_bye); - self->timer.id_bye = TSK_INVALID_TIMER_ID; - } - if(TSK_TIMER_ID_IS_VALID(self->timer.id_report)){ - tsk_timer_manager_cancel(self->timer.handle_global, self->timer.id_report); - self->timer.id_report = TSK_INVALID_TIMER_ID; - } - tsk_safeobj_unlock(self); - self->is_started = tsk_false; - } - - return ret; + int ret = 0; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(self->is_started) { + // send BYE synchronous way + SendBYEPacket(self, EVENT_REPORT); + + // this is a global timer shared by many components -> stopping it won't remove + // all scheduled items as it could continue running if still used + tsk_safeobj_lock(self); // must + if(TSK_TIMER_ID_IS_VALID(self->timer.id_bye)) { + tsk_timer_manager_cancel(self->timer.handle_global, self->timer.id_bye); + self->timer.id_bye = TSK_INVALID_TIMER_ID; + } + if(TSK_TIMER_ID_IS_VALID(self->timer.id_report)) { + tsk_timer_manager_cancel(self->timer.handle_global, self->timer.id_report); + self->timer.id_report = TSK_INVALID_TIMER_ID; + } + tsk_safeobj_unlock(self); + self->is_started = tsk_false; + } + + return ret; } int trtp_rtcp_session_process_rtp_out(trtp_rtcp_session_t* self, const trtp_rtp_packet_t* packet_rtp, tsk_size_t size) { - int ret = 0; - - if(!self || !packet_rtp || !packet_rtp->header){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(!self->is_started){ - TSK_DEBUG_ERROR("Not started"); - return -2; - } - - tsk_safeobj_lock(self); - - // create local source if not already done - // first destroy it if the ssrc don't match - if(self->source_local && self->source_local->ssrc != packet_rtp->header->ssrc){ - tsk_bool_t removed = tsk_false; - // local ssrc has changed: sould never happen ...but who know? - // remove the source - TSK_DEBUG_WARN("Not expected to be called"); - _trtp_rtcp_session_remove_source(self, self->source_local->ssrc, &removed); - TSK_OBJECT_SAFE_FREE(self->source_local); - TSK_OBJECT_SAFE_FREE(self->sdes); - self->packets_count = 0; - self->octets_count = 0; - if(removed){ - --self->senders; - --self->members; - } - } - if(!self->source_local){ - if(!(self->source_local = _trtp_rtcp_source_create(packet_rtp->header->ssrc, packet_rtp->header->seq_num, packet_rtp->header->timestamp))){ - TSK_DEBUG_ERROR("Failed to create new local source"); - } - // add the source (refresh the number of senders, ...) - _trtp_rtcp_session_add_source(self, self->source_local); - // 'members' and 'senders' were already initialized in the constructor - } - - if(!self->we_sent){ - self->we_sent = tsk_true; - } - - ++self->packets_count; - self->octets_count += (uint32_t)size; - - tsk_safeobj_unlock(self); - - return ret; + int ret = 0; + + if(!self || !packet_rtp || !packet_rtp->header) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(!self->is_started) { + TSK_DEBUG_ERROR("Not started"); + return -2; + } + + tsk_safeobj_lock(self); + + // create local source if not already done + // first destroy it if the ssrc don't match + if(self->source_local && self->source_local->ssrc != packet_rtp->header->ssrc) { + tsk_bool_t removed = tsk_false; + // local ssrc has changed: sould never happen ...but who know? + // remove the source + TSK_DEBUG_WARN("Not expected to be called"); + _trtp_rtcp_session_remove_source(self, self->source_local->ssrc, &removed); + TSK_OBJECT_SAFE_FREE(self->source_local); + TSK_OBJECT_SAFE_FREE(self->sdes); + self->packets_count = 0; + self->octets_count = 0; + if(removed) { + --self->senders; + --self->members; + } + } + if(!self->source_local) { + if(!(self->source_local = _trtp_rtcp_source_create(packet_rtp->header->ssrc, packet_rtp->header->seq_num, packet_rtp->header->timestamp))) { + TSK_DEBUG_ERROR("Failed to create new local source"); + } + // add the source (refresh the number of senders, ...) + _trtp_rtcp_session_add_source(self, self->source_local); + // 'members' and 'senders' were already initialized in the constructor + } + + if(!self->we_sent) { + self->we_sent = tsk_true; + } + + ++self->packets_count; + self->octets_count += (uint32_t)size; + + tsk_safeobj_unlock(self); + + return ret; } int trtp_rtcp_session_process_rtp_in(trtp_rtcp_session_t* self, const trtp_rtp_packet_t* packet_rtp, tsk_size_t size) { - int ret = 0; - trtp_rtcp_source_t* source; - - if(!self || !packet_rtp || !packet_rtp->header){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(!self->is_started){ - TSK_DEBUG_INFO("RTCP session not started"); - return -2; - } - - tsk_safeobj_lock(self); - OnReceive(self, (const packet_)packet_rtp, EVENT_RTP, size); - if((source = _trtp_rtcp_session_find_source(self, packet_rtp->header->ssrc))){ - if(_trtp_rtcp_source_update_seq(source, packet_rtp->header->seq_num, packet_rtp->header->timestamp)){ - // RFC 3550 A.8 Estimating the Interarrival Jitter - /* uint32_t expected = (source->cycles + source->max_seq) - source->base_seq + 1; */ - double arrival = (((double)(source->max_ts - source->base_ts) / (double)source->rate) * 1000); - int32_t transit = (int32_t)arrival - packet_rtp->header->timestamp; - int32_t d = (transit - source->transit); - if(d < 0) d = -d; - source->transit = transit; - source->jitter += (1./16.) * ((double)d - source->jitter); - } - TSK_OBJECT_SAFE_FREE(source); - } - - tsk_safeobj_unlock(self); - - return ret; + int ret = 0; + trtp_rtcp_source_t* source; + + if(!self || !packet_rtp || !packet_rtp->header) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(!self->is_started) { + TSK_DEBUG_INFO("RTCP session not started"); + return -2; + } + + tsk_safeobj_lock(self); + OnReceive(self, (const packet_)packet_rtp, EVENT_RTP, size); + if((source = _trtp_rtcp_session_find_source(self, packet_rtp->header->ssrc))) { + if(_trtp_rtcp_source_update_seq(source, packet_rtp->header->seq_num, packet_rtp->header->timestamp)) { + // RFC 3550 A.8 Estimating the Interarrival Jitter + /* uint32_t expected = (source->cycles + source->max_seq) - source->base_seq + 1; */ + double arrival = (((double)(source->max_ts - source->base_ts) / (double)source->rate) * 1000); + int32_t transit = (int32_t)arrival - packet_rtp->header->timestamp; + int32_t d = (transit - source->transit); + if(d < 0) { + d = -d; + } + source->transit = transit; + source->jitter += (1./16.) * ((double)d - source->jitter); + } + TSK_OBJECT_SAFE_FREE(source); + } + + tsk_safeobj_unlock(self); + + return ret; } int trtp_rtcp_session_process_rtcp_in(trtp_rtcp_session_t* self, const void* buffer, tsk_size_t size) { - int ret = 0; - trtp_rtcp_packet_t* packet_rtcp = tsk_null; - - if(!self || !buffer || size < TRTP_RTCP_HEADER_SIZE){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(!self->is_started){ - TSK_DEBUG_ERROR("Not started"); - return -2; - } - - // derialize the RTCP packet for processing - packet_rtcp = trtp_rtcp_packet_deserialize(buffer, size); - if(packet_rtcp){ - tsk_safeobj_lock(self); - OnReceive(self, - (const packet_)packet_rtcp, - (packet_rtcp->header->type == trtp_rtcp_packet_type_bye) ? EVENT_BYE : EVENT_REPORT, - size); - if(packet_rtcp->header->type == trtp_rtcp_packet_type_sr){ - trtp_rtcp_source_t* source; - const trtp_rtcp_report_sr_t* sr = (const trtp_rtcp_report_sr_t*)packet_rtcp; - if((source = _trtp_rtcp_session_find_source(self, sr->ssrc))){ - source->ntp_lsw = sr->sender_info.ntp_lsw; - source->ntp_msw = sr->sender_info.ntp_msw; - source->dlsr = tsk_time_now(); - TSK_OBJECT_SAFE_FREE(source); - } - } - tsk_safeobj_unlock(self); // must be before callback() - - if(self->callback){ - ret = self->callback(self->callback_data, packet_rtcp); - } - TSK_OBJECT_SAFE_FREE(packet_rtcp); - } - - - return ret; + int ret = 0; + trtp_rtcp_packet_t* packet_rtcp = tsk_null; + + if(!self || !buffer || size < TRTP_RTCP_HEADER_SIZE) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(!self->is_started) { + TSK_DEBUG_ERROR("Not started"); + return -2; + } + + // derialize the RTCP packet for processing + packet_rtcp = trtp_rtcp_packet_deserialize(buffer, size); + if(packet_rtcp) { + tsk_safeobj_lock(self); + OnReceive(self, + (const packet_)packet_rtcp, + (packet_rtcp->header->type == trtp_rtcp_packet_type_bye) ? EVENT_BYE : EVENT_REPORT, + size); + if(packet_rtcp->header->type == trtp_rtcp_packet_type_sr) { + trtp_rtcp_source_t* source; + const trtp_rtcp_report_sr_t* sr = (const trtp_rtcp_report_sr_t*)packet_rtcp; + if((source = _trtp_rtcp_session_find_source(self, sr->ssrc))) { + source->ntp_lsw = sr->sender_info.ntp_lsw; + source->ntp_msw = sr->sender_info.ntp_msw; + source->dlsr = tsk_time_now(); + TSK_OBJECT_SAFE_FREE(source); + } + } + tsk_safeobj_unlock(self); // must be before callback() + + if(self->callback) { + ret = self->callback(self->callback_data, packet_rtcp); + } + TSK_OBJECT_SAFE_FREE(packet_rtcp); + } + + + return ret; } int trtp_rtcp_session_signal_pkt_loss(trtp_rtcp_session_t* self, uint32_t ssrc_media, const uint16_t* seq_nums, tsk_size_t count) { - trtp_rtcp_report_rr_t* rr; - if(!self || !self->source_local || !seq_nums || !count){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(!self->is_started){ - TSK_DEBUG_ERROR("Not started"); - return -1; - } - - tsk_safeobj_lock(self); - - if((rr = trtp_rtcp_report_rr_create_2(self->source_local->ssrc))){ - trtp_rtcp_report_rtpfb_t* rtpfb; - if((rtpfb = trtp_rtcp_report_rtpfb_create_nack(self->source_local->ssrc, ssrc_media, seq_nums, count))){ - trtp_rtcp_packet_add_packet((trtp_rtcp_packet_t*)rr, (trtp_rtcp_packet_t*)rtpfb, tsk_false); - _trtp_rtcp_session_send_pkt(self, (trtp_rtcp_packet_t*)rr); - TSK_OBJECT_SAFE_FREE(rtpfb); - } - TSK_OBJECT_SAFE_FREE(rr); - } - - tsk_safeobj_unlock(self); - - return 0; + trtp_rtcp_report_rr_t* rr; + if(!self || !self->source_local || !seq_nums || !count) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(!self->is_started) { + TSK_DEBUG_ERROR("Not started"); + return -1; + } + + tsk_safeobj_lock(self); + + if((rr = trtp_rtcp_report_rr_create_2(self->source_local->ssrc))) { + trtp_rtcp_report_rtpfb_t* rtpfb; + if((rtpfb = trtp_rtcp_report_rtpfb_create_nack(self->source_local->ssrc, ssrc_media, seq_nums, count))) { + trtp_rtcp_packet_add_packet((trtp_rtcp_packet_t*)rr, (trtp_rtcp_packet_t*)rtpfb, tsk_false); + _trtp_rtcp_session_send_pkt(self, (trtp_rtcp_packet_t*)rr); + TSK_OBJECT_SAFE_FREE(rtpfb); + } + TSK_OBJECT_SAFE_FREE(rr); + } + + tsk_safeobj_unlock(self); + + return 0; } // Frame corrupted means the prediction chain is broken -> Send FIR int trtp_rtcp_session_signal_frame_corrupted(trtp_rtcp_session_t* self, uint32_t ssrc_media) { - trtp_rtcp_report_rr_t* rr; - if(!self || !self->source_local){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(!self->is_started){ - TSK_DEBUG_ERROR("Not started"); - return -1; - } - - tsk_safeobj_lock(self); - - if((rr = trtp_rtcp_report_rr_create_2(self->source_local->ssrc))){ - trtp_rtcp_report_psfb_t* psfb_fir = trtp_rtcp_report_psfb_create_fir(self->fir_seqnr++, self->source_local->ssrc, ssrc_media); - if(psfb_fir){ - trtp_rtcp_packet_add_packet((trtp_rtcp_packet_t*)rr, (trtp_rtcp_packet_t*)psfb_fir, tsk_false); - _trtp_rtcp_session_send_pkt(self, (trtp_rtcp_packet_t*)rr); - TSK_OBJECT_SAFE_FREE(psfb_fir); - } - TSK_OBJECT_SAFE_FREE(rr); - } - - tsk_safeobj_unlock(self); - return 0; + trtp_rtcp_report_rr_t* rr; + if(!self || !self->source_local) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(!self->is_started) { + TSK_DEBUG_ERROR("Not started"); + return -1; + } + + tsk_safeobj_lock(self); + + if((rr = trtp_rtcp_report_rr_create_2(self->source_local->ssrc))) { + trtp_rtcp_report_psfb_t* psfb_fir = trtp_rtcp_report_psfb_create_fir(self->fir_seqnr++, self->source_local->ssrc, ssrc_media); + if(psfb_fir) { + trtp_rtcp_packet_add_packet((trtp_rtcp_packet_t*)rr, (trtp_rtcp_packet_t*)psfb_fir, tsk_false); + _trtp_rtcp_session_send_pkt(self, (trtp_rtcp_packet_t*)rr); + TSK_OBJECT_SAFE_FREE(psfb_fir); + } + TSK_OBJECT_SAFE_FREE(rr); + } + + tsk_safeobj_unlock(self); + return 0; } // for now send just a FIR int trtp_rtcp_session_signal_jb_error(struct trtp_rtcp_session_s* self, uint32_t ssrc_media) { - return trtp_rtcp_session_signal_frame_corrupted(self, ssrc_media); + return trtp_rtcp_session_signal_frame_corrupted(self, ssrc_media); } tnet_fd_t trtp_rtcp_session_get_local_fd(const struct trtp_rtcp_session_s* self) @@ -800,314 +824,329 @@ int trtp_rtcp_session_set_net_transport(struct trtp_rtcp_session_s* self, struct static tsk_bool_t _trtp_rtcp_session_have_source(trtp_rtcp_session_t* self, uint32_t ssrc) { - tsk_list_item_t* item; - tsk_list_foreach(item, self->sources){ - if(TRTP_RTCP_SOURCE(item->data)->ssrc == ssrc){ - return tsk_true; - } - } - return tsk_false; + tsk_list_item_t* item; + tsk_list_foreach(item, self->sources) { + if(TRTP_RTCP_SOURCE(item->data)->ssrc == ssrc) { + return tsk_true; + } + } + return tsk_false; } // find source by ssrc // the caller must release the returned object static trtp_rtcp_source_t* _trtp_rtcp_session_find_source(trtp_rtcp_session_t* self, uint32_t ssrc) { - tsk_list_item_t* item; - tsk_list_foreach(item, self->sources){ - if(TRTP_RTCP_SOURCE(item->data)->ssrc == ssrc){ - return tsk_object_ref(item->data); - } - } - return tsk_null; + tsk_list_item_t* item; + tsk_list_foreach(item, self->sources) { + if(TRTP_RTCP_SOURCE(item->data)->ssrc == ssrc) { + return tsk_object_ref(item->data); + } + } + return tsk_null; } // find or add source by ssrc // the caller must release the returned object static trtp_rtcp_source_t* _trtp_rtcp_session_find_or_add_source(trtp_rtcp_session_t* self, uint32_t ssrc, uint16_t seq_if_add, uint32_t ts_id_add) { - trtp_rtcp_source_t* source; - if((source = _trtp_rtcp_session_find_source(self, ssrc))){ - return source; - } - - if((source = _trtp_rtcp_source_create(ssrc, seq_if_add, ts_id_add))){ - if((_trtp_rtcp_session_add_source(self, source)) != 0){ - TSK_DEBUG_ERROR("Failed to add source"); - TSK_OBJECT_SAFE_FREE(source); - return tsk_null; - } - return tsk_object_ref(source); - } - return tsk_null; + trtp_rtcp_source_t* source; + if((source = _trtp_rtcp_session_find_source(self, ssrc))) { + return source; + } + + if((source = _trtp_rtcp_source_create(ssrc, seq_if_add, ts_id_add))) { + if((_trtp_rtcp_session_add_source(self, source)) != 0) { + TSK_DEBUG_ERROR("Failed to add source"); + TSK_OBJECT_SAFE_FREE(source); + return tsk_null; + } + return tsk_object_ref(source); + } + return tsk_null; } int _trtp_rtcp_session_add_source(trtp_rtcp_session_t* self, trtp_rtcp_source_t* source) { - if(!self || !source){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if(!self || !source) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - tsk_list_lock(self->sources); - source = tsk_object_ref(source); - tsk_list_push_back_data(self->sources, (void**)&source); - tsk_list_unlock(self->sources); + tsk_list_lock(self->sources); + source = tsk_object_ref(source); + tsk_list_push_back_data(self->sources, (void**)&source); + tsk_list_unlock(self->sources); - return 0; + return 0; } // adds a source if doesn't exist static int _trtp_rtcp_session_add_source_2(trtp_rtcp_session_t* self, uint32_t ssrc, uint16_t seq, uint32_t ts, tsk_bool_t *added) { - int ret = 0; - tsk_list_item_t* item; - trtp_rtcp_source_t* source; - - tsk_list_lock(self->sources); - tsk_list_foreach(item, self->sources){ - if(TRTP_RTCP_SOURCE(item->data)->ssrc == ssrc){ - tsk_list_unlock(self->sources); - *added = tsk_false; - return 0; - } - } + int ret = 0; + tsk_list_item_t* item; + trtp_rtcp_source_t* source; + + tsk_list_lock(self->sources); + tsk_list_foreach(item, self->sources) { + if(TRTP_RTCP_SOURCE(item->data)->ssrc == ssrc) { + tsk_list_unlock(self->sources); + *added = tsk_false; + return 0; + } + } - tsk_list_unlock(self->sources); + tsk_list_unlock(self->sources); - if((source = _trtp_rtcp_source_create(ssrc, seq, ts))){ - ret = _trtp_rtcp_session_add_source(self, source); - } + if((source = _trtp_rtcp_source_create(ssrc, seq, ts))) { + ret = _trtp_rtcp_session_add_source(self, source); + } - TSK_OBJECT_SAFE_FREE(source); + TSK_OBJECT_SAFE_FREE(source); - *added = tsk_true; - return ret; + *added = tsk_true; + return ret; } int _trtp_rtcp_session_remove_source(trtp_rtcp_session_t* self, uint32_t ssrc, tsk_bool_t *removed) { - *removed = tsk_false; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - tsk_list_lock(self->sources); - if((*removed = tsk_list_remove_item_by_pred(self->sources, __pred_find_source_by_ssrc, &ssrc)) == tsk_true){ - // ... - } - tsk_list_unlock(self->sources); - return 0; + *removed = tsk_false; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + tsk_list_lock(self->sources); + if((*removed = tsk_list_remove_item_by_pred(self->sources, __pred_find_source_by_ssrc, &ssrc)) == tsk_true) { + // ... + } + tsk_list_unlock(self->sources); + return 0; } static tsk_size_t _trtp_rtcp_session_send_pkt(trtp_rtcp_session_t* self, trtp_rtcp_packet_t* pkt) { - tsk_size_t ret = 0; - tsk_size_t __num_bytes_pad = 0; - tsk_buffer_t* buffer; + tsk_size_t ret = 0; + tsk_size_t __num_bytes_pad = 0; + tsk_buffer_t* buffer; - if(!self->remote_addr || self->local_fd <= 0){ - TSK_DEBUG_ERROR("Invalid network settings"); - return 0; - } + if(!self->remote_addr || self->local_fd <= 0) { + TSK_DEBUG_ERROR("Invalid network settings"); + return 0; + } #if HAVE_SRTP - if(self->srtp.session) __num_bytes_pad = (SRTP_MAX_TRAILER_LEN + 0x4); + if(self->srtp.session) { + __num_bytes_pad = (SRTP_MAX_TRAILER_LEN + 0x4); + } #endif - // SDES - if(!self->sdes && (self->sdes = trtp_rtcp_report_sdes_create_null())){ - trtp_rtcp_sdes_chunck_t* chunck = trtp_rtcp_sdes_chunck_create(self->source_local->ssrc); - if(chunck){ - static const char* _name = "test@doubango.org"; - trtp_rtcp_sdes_chunck_add_item(chunck, trtp_rtcp_sdes_item_type_cname, self->cname, (uint8_t)tsk_strlen(self->cname)); - trtp_rtcp_sdes_chunck_add_item(chunck, trtp_rtcp_sdes_item_type_name, _name, (uint8_t)tsk_strlen(_name)); - trtp_rtcp_report_sdes_add_chunck(self->sdes, chunck); - TSK_OBJECT_SAFE_FREE(chunck); - } - } - if(self->sdes){ - trtp_rtcp_packet_add_packet(pkt, (trtp_rtcp_packet_t*)self->sdes, tsk_true); - } - - if((buffer = trtp_rtcp_packet_serialize(pkt, __num_bytes_pad))){ - void* data = buffer->data; - int size = (int)buffer->size; + // SDES + if(!self->sdes && (self->sdes = trtp_rtcp_report_sdes_create_null())) { + trtp_rtcp_sdes_chunck_t* chunck = trtp_rtcp_sdes_chunck_create(self->source_local->ssrc); + if(chunck) { + static const char* _name = "test@doubango.org"; + trtp_rtcp_sdes_chunck_add_item(chunck, trtp_rtcp_sdes_item_type_cname, self->cname, (uint8_t)tsk_strlen(self->cname)); + trtp_rtcp_sdes_chunck_add_item(chunck, trtp_rtcp_sdes_item_type_name, _name, (uint8_t)tsk_strlen(_name)); + trtp_rtcp_report_sdes_add_chunck(self->sdes, chunck); + TSK_OBJECT_SAFE_FREE(chunck); + } + } + if(self->sdes) { + trtp_rtcp_packet_add_packet(pkt, (trtp_rtcp_packet_t*)self->sdes, tsk_true); + } + + if((buffer = trtp_rtcp_packet_serialize(pkt, __num_bytes_pad))) { + void* data = buffer->data; + int size = (int)buffer->size; #if HAVE_SRTP - if(self->srtp.session){ - if(srtp_protect_rtcp(((srtp_t)*self->srtp.session), data, &size) != err_status_ok){ - TSK_DEBUG_ERROR("srtp_protect_rtcp() failed"); - } - } + if(self->srtp.session) { + if(srtp_protect_rtcp(((srtp_t)*self->srtp.session), data, &size) != err_status_ok) { + TSK_DEBUG_ERROR("srtp_protect_rtcp() failed"); + } + } #endif - ret = _trtp_rtcp_session_send_raw(self, data, size); - TSK_OBJECT_SAFE_FREE(buffer); - } + ret = _trtp_rtcp_session_send_raw(self, data, size); + TSK_OBJECT_SAFE_FREE(buffer); + } - return ret; + return ret; } static tsk_size_t _trtp_rtcp_session_send_raw(trtp_rtcp_session_t* self, const void* data, tsk_size_t size) { - tsk_size_t ret = 0; - if (!self || !data || !size) { - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - if (self->is_ice_turn_active) { - ret = (tnet_ice_ctx_send_turn_rtcp(self->ice_ctx, data, size) == 0) ? size : 0; // returns #0 if ok - } - else { + tsk_size_t ret = 0; + if (!self || !data || !size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + if (self->is_ice_turn_active) { + ret = (tnet_ice_ctx_send_turn_rtcp(self->ice_ctx, data, size) == 0) ? size : 0; // returns #0 if ok + } + else { ret = self->transport - ? tnet_transport_sendto(self->transport, self->local_fd, self->remote_addr, data, size) - : tnet_sockfd_sendto(self->local_fd, self->remote_addr, data, size); - } - return ret; + ? tnet_transport_sendto(self->transport, self->local_fd, self->remote_addr, data, size) + : tnet_sockfd_sendto(self->local_fd, self->remote_addr, data, size); + } + return ret; } static int _trtp_rtcp_session_timer_callback(const void* arg, tsk_timer_id_t timer_id) { - trtp_rtcp_session_t* session = (trtp_rtcp_session_t*)arg; - tsk_safeobj_lock(session); // must - if(session->timer.id_bye == timer_id){ - session->timer.id_bye = TSK_INVALID_TIMER_ID; - OnExpire(session, EVENT_BYE); - } - else if(session->timer.id_report == timer_id){ - session->timer.id_report = TSK_INVALID_TIMER_ID; - OnExpire(session, EVENT_REPORT); - } - tsk_safeobj_unlock(session); - return 0; + trtp_rtcp_session_t* session = (trtp_rtcp_session_t*)arg; + tsk_safeobj_lock(session); // must + if(session->timer.id_bye == timer_id) { + session->timer.id_bye = TSK_INVALID_TIMER_ID; + OnExpire(session, EVENT_BYE); + } + else if(session->timer.id_report == timer_id) { + session->timer.id_report = TSK_INVALID_TIMER_ID; + OnExpire(session, EVENT_REPORT); + } + tsk_safeobj_unlock(session); + return 0; } static tsk_bool_t IsRtpPacket(const packet_ p) { - return (TSK_OBJECT_HEADER(p)->__def__ == trtp_rtp_packet_def_t); + return (TSK_OBJECT_HEADER(p)->__def__ == trtp_rtp_packet_def_t); } static PacketType_ PacketType(const packet_ p) { - if(IsRtpPacket(p)){ - return PACKET_RTP; - } - else{ - switch(((const trtp_rtcp_packet_t*)p)->header->type){ - case trtp_rtcp_packet_type_bye: return PACKET_BYE; - default: return PACKET_RTCP_REPORT; - } - } + if(IsRtpPacket(p)) { + return PACKET_RTP; + } + else { + switch(((const trtp_rtcp_packet_t*)p)->header->type) { + case trtp_rtcp_packet_type_bye: + return PACKET_BYE; + default: + return PACKET_RTCP_REPORT; + } + } } // Returns true if the packet is from a member or not // also checks all csrc static tsk_bool_t NewMember(trtp_rtcp_session_t* session, const packet_ p) { - uint32_t ssrc = 0; - if(IsRtpPacket(p)){ - const trtp_rtp_packet_t* packet_rtp = (const trtp_rtp_packet_t*)p; - tsk_size_t i; - for(i = 0; i < packet_rtp->header->csrc_count && i < sizeof(packet_rtp->header->csrc)/sizeof(packet_rtp->header->csrc[0]); ++i){ - if(!(_trtp_rtcp_session_have_source(session, packet_rtp->header->csrc[i]))){ - return tsk_false; - } - } - ssrc = packet_rtp->header->ssrc; - } - else{ - switch(((const trtp_rtcp_packet_t*)p)->header->type){ - case trtp_rtcp_packet_type_rr: ssrc = ((const trtp_rtcp_report_rr_t*)p)->ssrc; break; - case trtp_rtcp_packet_type_sr: ssrc = ((const trtp_rtcp_report_sr_t*)p)->ssrc; break; - case trtp_rtcp_packet_type_bye: - { - tsk_size_t i; - const trtp_rtcp_report_bye_t* bye = (const trtp_rtcp_report_bye_t*)p; - for(i = 0; i < TRTP_RTCP_PACKET(bye)->header->rc; ++i){ - if(!_trtp_rtcp_session_have_source(session, bye->ssrc_list[i])){ - return tsk_false; - } - } - return tsk_true; - } - default: return tsk_false; - } - } - - return !_trtp_rtcp_session_have_source(session, ssrc); + uint32_t ssrc = 0; + if(IsRtpPacket(p)) { + const trtp_rtp_packet_t* packet_rtp = (const trtp_rtp_packet_t*)p; + tsk_size_t i; + for(i = 0; i < packet_rtp->header->csrc_count && i < sizeof(packet_rtp->header->csrc)/sizeof(packet_rtp->header->csrc[0]); ++i) { + if(!(_trtp_rtcp_session_have_source(session, packet_rtp->header->csrc[i]))) { + return tsk_false; + } + } + ssrc = packet_rtp->header->ssrc; + } + else { + switch(((const trtp_rtcp_packet_t*)p)->header->type) { + case trtp_rtcp_packet_type_rr: + ssrc = ((const trtp_rtcp_report_rr_t*)p)->ssrc; + break; + case trtp_rtcp_packet_type_sr: + ssrc = ((const trtp_rtcp_report_sr_t*)p)->ssrc; + break; + case trtp_rtcp_packet_type_bye: { + tsk_size_t i; + const trtp_rtcp_report_bye_t* bye = (const trtp_rtcp_report_bye_t*)p; + for(i = 0; i < TRTP_RTCP_PACKET(bye)->header->rc; ++i) { + if(!_trtp_rtcp_session_have_source(session, bye->ssrc_list[i])) { + return tsk_false; + } + } + return tsk_true; + } + default: + return tsk_false; + } + } + + return !_trtp_rtcp_session_have_source(session, ssrc); } #define NewSender(session, p) NewMember((session), (p)) static tsk_size_t AddMemberUsingRTCPPacket(trtp_rtcp_session_t* session, const trtp_rtcp_packet_t* p, tsk_bool_t sender) { - trtp_rtcp_packets_L_t* packets = tsk_null; - trtp_rtcp_rblocks_L_t* blocks = tsk_null; - tsk_bool_t added = tsk_false; - tsk_size_t count = 0; - - switch(p->header->type){ - case trtp_rtcp_packet_type_rr: - { - const trtp_rtcp_report_rr_t* rr = (const trtp_rtcp_report_rr_t*)p; - _trtp_rtcp_session_add_source_2(session, ((const trtp_rtcp_report_rr_t*)p)->ssrc, 0, 0, &added); - if(added) ++count; - - packets = rr->packets; - blocks = rr->blocks; - break; - } - case trtp_rtcp_packet_type_sr: - { - const trtp_rtcp_report_sr_t* sr = (const trtp_rtcp_report_sr_t*)p; - _trtp_rtcp_session_add_source_2(session, ((const trtp_rtcp_report_sr_t*)p)->ssrc, 0, 0, &added); - if(added) ++count; - packets = sr->packets; - blocks = sr->blocks; - break; - } - default: - { - break; + trtp_rtcp_packets_L_t* packets = tsk_null; + trtp_rtcp_rblocks_L_t* blocks = tsk_null; + tsk_bool_t added = tsk_false; + tsk_size_t count = 0; + + switch(p->header->type) { + case trtp_rtcp_packet_type_rr: { + const trtp_rtcp_report_rr_t* rr = (const trtp_rtcp_report_rr_t*)p; + _trtp_rtcp_session_add_source_2(session, ((const trtp_rtcp_report_rr_t*)p)->ssrc, 0, 0, &added); + if(added) { + ++count; + } + + packets = rr->packets; + blocks = rr->blocks; + break; + } + case trtp_rtcp_packet_type_sr: { + const trtp_rtcp_report_sr_t* sr = (const trtp_rtcp_report_sr_t*)p; + _trtp_rtcp_session_add_source_2(session, ((const trtp_rtcp_report_sr_t*)p)->ssrc, 0, 0, &added); + if(added) { + ++count; + } + packets = sr->packets; + blocks = sr->blocks; + break; + } + default: { + break; + } + } + + if(!sender) { + if(packets) { + const tsk_list_item_t *item; + tsk_list_foreach(item, packets) { + AddMemberUsingRTCPPacket(session, (const trtp_rtcp_packet_t*)item->data, sender); + } + } + if(blocks) { + const tsk_list_item_t *item; + tsk_list_foreach(item, blocks) { + _trtp_rtcp_session_add_source_2(session, TRTP_RTCP_RBLOCK(item->data)->ssrc, 0, 0, &added); + if(added) { + ++count; + } } - } - - if(!sender){ - if(packets){ - const tsk_list_item_t *item; - tsk_list_foreach(item, packets){ - AddMemberUsingRTCPPacket(session, (const trtp_rtcp_packet_t*)item->data, sender); - } - } - if(blocks){ - const tsk_list_item_t *item; - tsk_list_foreach(item, blocks){ - _trtp_rtcp_session_add_source_2(session, TRTP_RTCP_RBLOCK(item->data)->ssrc, 0, 0, &added); - if(added) ++count; - } - } - } - - return count; + } + } + + return count; } static tsk_size_t AddMember_(trtp_rtcp_session_t* session, const packet_ p, tsk_bool_t sender) { - tsk_size_t count = 0; - if(IsRtpPacket(p)){ - const trtp_rtp_packet_t* packet_rtp = (const trtp_rtp_packet_t*)p; - tsk_size_t i; - tsk_bool_t added = tsk_false; - _trtp_rtcp_session_add_source_2(session, packet_rtp->header->ssrc, packet_rtp->header->seq_num, packet_rtp->header->timestamp, &added); - if(added) ++count; - for(i = 0; i < packet_rtp->header->csrc_count && i < sizeof(packet_rtp->header->csrc)/sizeof(packet_rtp->header->csrc[0]); ++i){ - _trtp_rtcp_session_add_source_2(session, packet_rtp->header->csrc[i], 0, 0, &added); - if(added) ++count; - } - } - else{ - count += AddMemberUsingRTCPPacket(session, (const trtp_rtcp_packet_t*) p, sender); - } - return count; + tsk_size_t count = 0; + if(IsRtpPacket(p)) { + const trtp_rtp_packet_t* packet_rtp = (const trtp_rtp_packet_t*)p; + tsk_size_t i; + tsk_bool_t added = tsk_false; + _trtp_rtcp_session_add_source_2(session, packet_rtp->header->ssrc, packet_rtp->header->seq_num, packet_rtp->header->timestamp, &added); + if(added) { + ++count; + } + for(i = 0; i < packet_rtp->header->csrc_count && i < sizeof(packet_rtp->header->csrc)/sizeof(packet_rtp->header->csrc[0]); ++i) { + _trtp_rtcp_session_add_source_2(session, packet_rtp->header->csrc[i], 0, 0, &added); + if(added) { + ++count; + } + } + } + else { + count += AddMemberUsingRTCPPacket(session, (const trtp_rtcp_packet_t*) p, sender); + } + return count; } #define AddMember(session, p) AddMember_((session), (p), tsk_false) @@ -1116,73 +1155,80 @@ static tsk_size_t AddMember_(trtp_rtcp_session_t* session, const packet_ p, tsk_ static tsk_size_t RemoveMemberUsingRTCPPacket(trtp_rtcp_session_t* session, const trtp_rtcp_packet_t* p) { - trtp_rtcp_packets_L_t* packets = tsk_null; - trtp_rtcp_rblocks_L_t* blocks = tsk_null; - tsk_bool_t removed = tsk_false; - tsk_size_t count = 0; - - switch(p->header->type){ - case trtp_rtcp_packet_type_rr: - { - const trtp_rtcp_report_rr_t* rr = (const trtp_rtcp_report_rr_t*)p; - _trtp_rtcp_session_remove_source(session, ((const trtp_rtcp_report_rr_t*)p)->ssrc, &removed); - if(removed) ++count; - - packets = rr->packets; - blocks = rr->blocks; - break; - } - case trtp_rtcp_packet_type_sr: - { - const trtp_rtcp_report_sr_t* sr = (const trtp_rtcp_report_sr_t*)p; - _trtp_rtcp_session_remove_source(session, ((const trtp_rtcp_report_sr_t*)p)->ssrc, &removed); - if(removed) ++count; - packets = sr->packets; - blocks = sr->blocks; - break; - } - default: - { - break; + trtp_rtcp_packets_L_t* packets = tsk_null; + trtp_rtcp_rblocks_L_t* blocks = tsk_null; + tsk_bool_t removed = tsk_false; + tsk_size_t count = 0; + + switch(p->header->type) { + case trtp_rtcp_packet_type_rr: { + const trtp_rtcp_report_rr_t* rr = (const trtp_rtcp_report_rr_t*)p; + _trtp_rtcp_session_remove_source(session, ((const trtp_rtcp_report_rr_t*)p)->ssrc, &removed); + if(removed) { + ++count; + } + + packets = rr->packets; + blocks = rr->blocks; + break; + } + case trtp_rtcp_packet_type_sr: { + const trtp_rtcp_report_sr_t* sr = (const trtp_rtcp_report_sr_t*)p; + _trtp_rtcp_session_remove_source(session, ((const trtp_rtcp_report_sr_t*)p)->ssrc, &removed); + if(removed) { + ++count; + } + packets = sr->packets; + blocks = sr->blocks; + break; + } + default: { + break; + } + } + + if(packets) { + const tsk_list_item_t *item; + tsk_list_foreach(item, packets) { + RemoveMemberUsingRTCPPacket(session, (const trtp_rtcp_packet_t*)item->data); + } + } + if(blocks) { + const tsk_list_item_t *item; + tsk_list_foreach(item, blocks) { + _trtp_rtcp_session_remove_source(session, TRTP_RTCP_RBLOCK(item->data)->ssrc, &removed); + if(removed) { + ++count; } - } - - if(packets){ - const tsk_list_item_t *item; - tsk_list_foreach(item, packets){ - RemoveMemberUsingRTCPPacket(session, (const trtp_rtcp_packet_t*)item->data); - } - } - if(blocks){ - const tsk_list_item_t *item; - tsk_list_foreach(item, blocks){ - _trtp_rtcp_session_remove_source(session, TRTP_RTCP_RBLOCK(item->data)->ssrc, &removed); - if(removed) ++count; - } - } - - - return count; + } + } + + + return count; } static tsk_size_t RemoveMember(trtp_rtcp_session_t* session, const packet_ p) { - tsk_size_t count = 0; - if(IsRtpPacket(p)){ - const trtp_rtp_packet_t* packet_rtp = (const trtp_rtp_packet_t*)p; - tsk_size_t i; - tsk_bool_t removed = tsk_false; - _trtp_rtcp_session_remove_source(session, packet_rtp->header->ssrc, &removed); - if(removed) ++count; - for(i = 0; i < packet_rtp->header->csrc_count && i < sizeof(packet_rtp->header->csrc)/sizeof(packet_rtp->header->csrc[0]); ++i){ - _trtp_rtcp_session_remove_source(session, packet_rtp->header->csrc[i], &removed); - if(removed) ++count; - } - } - else{ - count += RemoveMemberUsingRTCPPacket(session, (const trtp_rtcp_packet_t*) p); - } - return count; + tsk_size_t count = 0; + if(IsRtpPacket(p)) { + const trtp_rtp_packet_t* packet_rtp = (const trtp_rtp_packet_t*)p; + tsk_size_t i; + tsk_bool_t removed = tsk_false; + _trtp_rtcp_session_remove_source(session, packet_rtp->header->ssrc, &removed); + if(removed) { + ++count; + } + for(i = 0; i < packet_rtp->header->csrc_count && i < sizeof(packet_rtp->header->csrc)/sizeof(packet_rtp->header->csrc[0]); ++i) { + _trtp_rtcp_session_remove_source(session, packet_rtp->header->csrc[i], &removed); + if(removed) { + ++count; + } + } + } + else { + count += RemoveMemberUsingRTCPPacket(session, (const trtp_rtcp_packet_t*) p); + } + return count; } #define RemoveSender(session, p) RemoveMember((session), (p)) @@ -1190,395 +1236,414 @@ static tsk_size_t RemoveMember(trtp_rtcp_session_t* session, const packet_ p) // Sends BYE in synchronous mode static void SendBYEPacket(trtp_rtcp_session_t* session, event_ e) { - trtp_rtcp_report_bye_t* bye; - tsk_size_t __num_bytes_pad = 0; + trtp_rtcp_report_bye_t* bye; + tsk_size_t __num_bytes_pad = 0; - if(!session->remote_addr || session->local_fd <= 0){ - TSK_DEBUG_ERROR("Invalid network settings"); - return; - } + if(!session->remote_addr || session->local_fd <= 0) { + TSK_DEBUG_ERROR("Invalid network settings"); + return; + } - tsk_safeobj_lock(session); + tsk_safeobj_lock(session); #if HAVE_SRTP - if(session->srtp.session) __num_bytes_pad = (SRTP_MAX_TRAILER_LEN + 0x4); + if(session->srtp.session) { + __num_bytes_pad = (SRTP_MAX_TRAILER_LEN + 0x4); + } #endif - if(session->source_local && (bye = trtp_rtcp_report_bye_create_2(session->source_local->ssrc))){ - tsk_buffer_t* buffer; - // serialize and send the packet - if((buffer = trtp_rtcp_packet_serialize((const trtp_rtcp_packet_t*)bye, __num_bytes_pad))){ - void* data = buffer->data; - int size = (int)buffer->size; + if(session->source_local && (bye = trtp_rtcp_report_bye_create_2(session->source_local->ssrc))) { + tsk_buffer_t* buffer; + // serialize and send the packet + if((buffer = trtp_rtcp_packet_serialize((const trtp_rtcp_packet_t*)bye, __num_bytes_pad))) { + void* data = buffer->data; + int size = (int)buffer->size; #if HAVE_SRTP - if(session->srtp.session){ - if(srtp_protect_rtcp(((srtp_t)*session->srtp.session), data, &size) != err_status_ok){ - TSK_DEBUG_ERROR("srtp_protect_rtcp() failed"); - } - } + if(session->srtp.session) { + if(srtp_protect_rtcp(((srtp_t)*session->srtp.session), data, &size) != err_status_ok) { + TSK_DEBUG_ERROR("srtp_protect_rtcp() failed"); + } + } #endif - _trtp_rtcp_session_send_raw(session, data, size); - TSK_OBJECT_SAFE_FREE(buffer); - } - TSK_OBJECT_SAFE_FREE(bye); - } + _trtp_rtcp_session_send_raw(session, data, size); + TSK_OBJECT_SAFE_FREE(buffer); + } + TSK_OBJECT_SAFE_FREE(bye); + } - tsk_safeobj_unlock(session); + tsk_safeobj_unlock(session); } // returns sent packet size static tsk_size_t SendRTCPReport(trtp_rtcp_session_t* session, event_ e) { - tsk_size_t ret = 0; - - tsk_safeobj_lock(session); - - if(session->initial){ - // Send Receiver report (manadatory to be the first on) - trtp_rtcp_report_rr_t* rr = trtp_rtcp_report_rr_create_2(session->source_local->ssrc); - if(rr){ - // serialize and send the packet - ret = _trtp_rtcp_session_send_pkt(session, (trtp_rtcp_packet_t*)rr); - TSK_OBJECT_SAFE_FREE(rr); - } - } - else{ - trtp_rtcp_report_sr_t* sr = trtp_rtcp_report_sr_create_null(); - uint32_t media_ssrc_list[16] = {0}; - uint32_t media_ssrc_list_count = 0; - if(sr){ - uint64_t ntp_now = tsk_time_ntp(); - uint64_t time_now = tsk_time_now(); - trtp_rtcp_rblock_t* rblock; - trtp_rtcp_source_t* source; - tsk_list_item_t *item; - tsk_bool_t packet_lost = tsk_false; - - // sender info - sr->ssrc = session->source_local->ssrc; - sr->sender_info.ntp_msw = (ntp_now >> 32); - sr->sender_info.ntp_lsw = (ntp_now & 0xFFFFFFFF); - sr->sender_info.sender_pcount = session->packets_count; - sr->sender_info.sender_ocount = session->octets_count; - { /* rtp_timestamp */ - struct timeval tv; - uint64_t rtp_timestamp = (time_now - session->time_start) * (session->source_local->rate / 1000); - tv.tv_sec = (long)(rtp_timestamp / 1000); - tv.tv_usec = (long)(rtp_timestamp - ((rtp_timestamp / 1000) * 1000)) * 1000; + tsk_size_t ret = 0; + + tsk_safeobj_lock(session); + + if(session->initial) { + // Send Receiver report (manadatory to be the first on) + trtp_rtcp_report_rr_t* rr = trtp_rtcp_report_rr_create_2(session->source_local->ssrc); + if(rr) { + // serialize and send the packet + ret = _trtp_rtcp_session_send_pkt(session, (trtp_rtcp_packet_t*)rr); + TSK_OBJECT_SAFE_FREE(rr); + } + } + else { + trtp_rtcp_report_sr_t* sr = trtp_rtcp_report_sr_create_null(); + uint32_t media_ssrc_list[16] = {0}; + uint32_t media_ssrc_list_count = 0; + if(sr) { + uint64_t ntp_now = tsk_time_ntp(); + uint64_t time_now = tsk_time_now(); + trtp_rtcp_rblock_t* rblock; + trtp_rtcp_source_t* source; + tsk_list_item_t *item; + tsk_bool_t packet_lost = tsk_false; + + // sender info + sr->ssrc = session->source_local->ssrc; + sr->sender_info.ntp_msw = (ntp_now >> 32); + sr->sender_info.ntp_lsw = (ntp_now & 0xFFFFFFFF); + sr->sender_info.sender_pcount = session->packets_count; + sr->sender_info.sender_ocount = session->octets_count; + { /* rtp_timestamp */ + struct timeval tv; + uint64_t rtp_timestamp = (time_now - session->time_start) * (session->source_local->rate / 1000); + tv.tv_sec = (long)(rtp_timestamp / 1000); + tv.tv_usec = (long)(rtp_timestamp - ((rtp_timestamp / 1000) * 1000)) * 1000; #if 1 - sr->sender_info.rtp_timestamp = (uint32_t)tsk_time_get_ms(&tv); + sr->sender_info.rtp_timestamp = (uint32_t)tsk_time_get_ms(&tv); #else - sr->sender_info.rtp_timestamp = (uint32_t)tsk_time_get_ntp_ms(&tv); + sr->sender_info.rtp_timestamp = (uint32_t)tsk_time_get_ntp_ms(&tv); #endif - } - - // report blocks - tsk_list_foreach(item, session->sources){ - if(!(source = (trtp_rtcp_source_t*)item->data) || !_trtp_rtcp_source_is_probed(source)){ - continue; - } - if((rblock = trtp_rtcp_rblock_create_null())){ - int32_t expected, expected_interval, received_interval, lost_interval; - - rblock->ssrc = source->ssrc; - // RFC 3550 - A.3 Determining Number of Packets Expected and Lost - expected = (source->cycles + source->max_seq) - source->base_seq + 1; - expected_interval = expected - source->expected_prior; - source->expected_prior = expected; - received_interval = source->received - source->received_prior; - source->received_prior = source->received; - lost_interval = expected_interval - received_interval; - if (expected_interval == 0 || lost_interval <= 0) rblock->fraction = 0; - else rblock->fraction = (lost_interval << 8) / expected_interval; - rblock->cumulative_no_lost = ((expected - source->received)); - if(!packet_lost && rblock->fraction) packet_lost = tsk_true; - - rblock->last_seq = ((source->cycles & 0xFFFF) << 16) | source->max_seq; - rblock->jitter = (uint32_t)source->jitter; - rblock->lsr = ((source->ntp_msw & 0xFFFF) << 16) | ((source->ntp_lsw & 0xFFFF0000) >> 16); - if(source->dlsr){ - rblock->dlsr = (uint32_t)(((time_now - source->dlsr) * 65536) / 1000); // in units of 1/65536 seconds - } - - trtp_rtcp_report_sr_add_block(sr, rblock); - TSK_OBJECT_SAFE_FREE(rblock); - } - - if((media_ssrc_list_count + 1) < sizeof(media_ssrc_list)/sizeof(media_ssrc_list[0])){ - media_ssrc_list[media_ssrc_list_count++] = source->ssrc; - } - } - - if(media_ssrc_list_count > 0){ - // draft-alvestrand-rmcat-remb-02 - if(session->app_bw_max_download > 0 && session->app_bw_max_download != INT_MAX){ // INT_MAX or <=0 means undefined - // app_bw_max_download unit is kbps while create_afb_remb() expect bps - trtp_rtcp_report_psfb_t* psfb_afb_remb = trtp_rtcp_report_psfb_create_afb_remb(session->source_local->ssrc/*sender SSRC*/, media_ssrc_list, media_ssrc_list_count, (session->app_bw_max_download * 1024)); - if(psfb_afb_remb){ - TSK_DEBUG_INFO("Packing RTCP-AFB-REMB (bw_dwn=%d kbps) for outgoing RTCP-SR", session->app_bw_max_download); - trtp_rtcp_packet_add_packet((trtp_rtcp_packet_t*)sr, (trtp_rtcp_packet_t*)psfb_afb_remb, tsk_false); - TSK_OBJECT_SAFE_FREE(psfb_afb_remb); - } - } - } - - // serialize and send the packet - ret = _trtp_rtcp_session_send_pkt(session, (trtp_rtcp_packet_t*)sr); - TSK_OBJECT_SAFE_FREE(sr); - } - } - - tsk_safeobj_unlock(session); - return ret; + } + + // report blocks + tsk_list_foreach(item, session->sources) { + if(!(source = (trtp_rtcp_source_t*)item->data) || !_trtp_rtcp_source_is_probed(source)) { + continue; + } + if((rblock = trtp_rtcp_rblock_create_null())) { + int32_t expected, expected_interval, received_interval, lost_interval; + + rblock->ssrc = source->ssrc; + // RFC 3550 - A.3 Determining Number of Packets Expected and Lost + expected = (source->cycles + source->max_seq) - source->base_seq + 1; + expected_interval = expected - source->expected_prior; + source->expected_prior = expected; + received_interval = source->received - source->received_prior; + source->received_prior = source->received; + lost_interval = expected_interval - received_interval; + if (expected_interval == 0 || lost_interval <= 0) { + rblock->fraction = 0; + } + else { + rblock->fraction = (lost_interval << 8) / expected_interval; + } + rblock->cumulative_no_lost = ((expected - source->received)); + if(!packet_lost && rblock->fraction) { + packet_lost = tsk_true; + } + + rblock->last_seq = ((source->cycles & 0xFFFF) << 16) | source->max_seq; + rblock->jitter = (uint32_t)source->jitter; + rblock->lsr = ((source->ntp_msw & 0xFFFF) << 16) | ((source->ntp_lsw & 0xFFFF0000) >> 16); + if(source->dlsr) { + rblock->dlsr = (uint32_t)(((time_now - source->dlsr) * 65536) / 1000); // in units of 1/65536 seconds + } + + trtp_rtcp_report_sr_add_block(sr, rblock); + TSK_OBJECT_SAFE_FREE(rblock); + } + + if((media_ssrc_list_count + 1) < sizeof(media_ssrc_list)/sizeof(media_ssrc_list[0])) { + media_ssrc_list[media_ssrc_list_count++] = source->ssrc; + } + } + + if(media_ssrc_list_count > 0) { + // draft-alvestrand-rmcat-remb-02 + if(session->app_bw_max_download > 0 && session->app_bw_max_download != INT_MAX) { // INT_MAX or <=0 means undefined + // app_bw_max_download unit is kbps while create_afb_remb() expect bps + trtp_rtcp_report_psfb_t* psfb_afb_remb = trtp_rtcp_report_psfb_create_afb_remb(session->source_local->ssrc/*sender SSRC*/, media_ssrc_list, media_ssrc_list_count, (session->app_bw_max_download * 1024)); + if(psfb_afb_remb) { + TSK_DEBUG_INFO("Packing RTCP-AFB-REMB (bw_dwn=%d kbps) for outgoing RTCP-SR", session->app_bw_max_download); + trtp_rtcp_packet_add_packet((trtp_rtcp_packet_t*)sr, (trtp_rtcp_packet_t*)psfb_afb_remb, tsk_false); + TSK_OBJECT_SAFE_FREE(psfb_afb_remb); + } + } + } + + // serialize and send the packet + ret = _trtp_rtcp_session_send_pkt(session, (trtp_rtcp_packet_t*)sr); + TSK_OBJECT_SAFE_FREE(sr); + } + } + + tsk_safeobj_unlock(session); + return ret; } static void Schedule(trtp_rtcp_session_t* session, double tn, event_ e) { - tsk_safeobj_lock(session); // must - switch(e){ - case EVENT_BYE: - if(!TSK_TIMER_ID_IS_VALID(session->timer.id_bye)){ - session->timer.id_bye = tsk_timer_manager_schedule(session->timer.handle_global, (uint64_t)tn, _trtp_rtcp_session_timer_callback, session); - } - break; - case EVENT_REPORT: - if(!TSK_TIMER_ID_IS_VALID(session->timer.id_report)){ - session->timer.id_report = tsk_timer_manager_schedule(session->timer.handle_global, (uint64_t)tn, _trtp_rtcp_session_timer_callback, session); - } - break; - default: TSK_DEBUG_ERROR("Unexpected code called"); break; - } - tsk_safeobj_unlock(session); + tsk_safeobj_lock(session); // must + switch(e) { + case EVENT_BYE: + if(!TSK_TIMER_ID_IS_VALID(session->timer.id_bye)) { + session->timer.id_bye = tsk_timer_manager_schedule(session->timer.handle_global, (uint64_t)tn, _trtp_rtcp_session_timer_callback, session); + } + break; + case EVENT_REPORT: + if(!TSK_TIMER_ID_IS_VALID(session->timer.id_report)) { + session->timer.id_report = tsk_timer_manager_schedule(session->timer.handle_global, (uint64_t)tn, _trtp_rtcp_session_timer_callback, session); + } + break; + default: + TSK_DEBUG_ERROR("Unexpected code called"); + break; + } + tsk_safeobj_unlock(session); } #define Reschedule(session, tn, e) Schedule((session), (tn), (e)) static double rtcp_interval(int32_t members, - int32_t senders, - double rtcp_bw, - int32_t we_sent, - double avg_rtcp_size, - tsk_bool_t initial) + int32_t senders, + double rtcp_bw, + int32_t we_sent, + double avg_rtcp_size, + tsk_bool_t initial) { - /* - * Minimum average time between RTCP packets from this site (in - * seconds). This time prevents the reports from `clumping' when - * sessions are small and the law of large numbers isn't helping - * to smooth out the traffic. It also keeps the report interval - * from becoming ridiculously small during transient outages like - * a network partition. - */ - #define RTCP_MIN_TIME 5. - /* - * Fraction of the RTCP bandwidth to be shared among active - * senders. (This fraction was chosen so that in a typical - * session with one or two active senders, the computed report - * time would be roughly equal to the minimum report time so that - * we don't unnecessarily slow down receiver reports.) The - * receiver fraction must be 1 - the sender fraction. - */ - #define RTCP_SENDER_BW_FRACTION 0.25 - #define RTCP_RCVR_BW_FRACTION (1 - RTCP_SENDER_BW_FRACTION) - /* - * To compensate for "timer reconsideration" converging to a - * value below the intended average. - */ - #define COMPENSATION (2.71828 - 1.5) - - double t; /* interval */ - double rtcp_min_time = RTCP_MIN_TIME; - int n; /* no. of members for computation */ - - /* - * Very first call at application start-up uses half the min - * delay for quicker notification while still allowing some time - * before reporting for randomization and to learn about other - * sources so the report interval will converge to the correct - * interval more quickly. - */ - if (initial) { - rtcp_min_time /= 2; - } - /* - * Dedicate a fraction of the RTCP bandwidth to senders unless - * the number of senders is large enough that their share is - * more than that fraction. - */ - n = members; - if (senders <= members * RTCP_SENDER_BW_FRACTION) { - if (we_sent) { - rtcp_bw *= RTCP_SENDER_BW_FRACTION; - n = senders; - } else { - rtcp_bw *= RTCP_RCVR_BW_FRACTION; - n -= senders; - } - } - - /* - * The effective number of sites times the average packet size is - * the total number of octets sent when each site sends a report. - * Dividing this by the effective bandwidth gives the time - * interval over which those packets must be sent in order to - * meet the bandwidth target, with a minimum enforced. In that - * time interval we send one report so this time is also our - * average time between reports. - */ - t = avg_rtcp_size * n / rtcp_bw; - if (t < rtcp_min_time) t = rtcp_min_time; - - /* - * To avoid traffic bursts from unintended synchronization with - * other sites, we then pick our actual next report interval as a - * random number uniformly distributed between 0.5*t and 1.5*t. - */ - t = t * (drand48() + 0.5); - t = t / COMPENSATION; - - return (t * 1000); + /* + * Minimum average time between RTCP packets from this site (in + * seconds). This time prevents the reports from `clumping' when + * sessions are small and the law of large numbers isn't helping + * to smooth out the traffic. It also keeps the report interval + * from becoming ridiculously small during transient outages like + * a network partition. + */ +#define RTCP_MIN_TIME 5. + /* + * Fraction of the RTCP bandwidth to be shared among active + * senders. (This fraction was chosen so that in a typical + * session with one or two active senders, the computed report + * time would be roughly equal to the minimum report time so that + * we don't unnecessarily slow down receiver reports.) The + * receiver fraction must be 1 - the sender fraction. + */ +#define RTCP_SENDER_BW_FRACTION 0.25 +#define RTCP_RCVR_BW_FRACTION (1 - RTCP_SENDER_BW_FRACTION) + /* + * To compensate for "timer reconsideration" converging to a + * value below the intended average. + */ +#define COMPENSATION (2.71828 - 1.5) + + double t; /* interval */ + double rtcp_min_time = RTCP_MIN_TIME; + int n; /* no. of members for computation */ + + /* + * Very first call at application start-up uses half the min + * delay for quicker notification while still allowing some time + * before reporting for randomization and to learn about other + * sources so the report interval will converge to the correct + * interval more quickly. + */ + if (initial) { + rtcp_min_time /= 2; + } + /* + * Dedicate a fraction of the RTCP bandwidth to senders unless + * the number of senders is large enough that their share is + * more than that fraction. + */ + n = members; + if (senders <= members * RTCP_SENDER_BW_FRACTION) { + if (we_sent) { + rtcp_bw *= RTCP_SENDER_BW_FRACTION; + n = senders; + } + else { + rtcp_bw *= RTCP_RCVR_BW_FRACTION; + n -= senders; + } + } + + /* + * The effective number of sites times the average packet size is + * the total number of octets sent when each site sends a report. + * Dividing this by the effective bandwidth gives the time + * interval over which those packets must be sent in order to + * meet the bandwidth target, with a minimum enforced. In that + * time interval we send one report so this time is also our + * average time between reports. + */ + t = avg_rtcp_size * n / rtcp_bw; + if (t < rtcp_min_time) { + t = rtcp_min_time; + } + + /* + * To avoid traffic bursts from unintended synchronization with + * other sites, we then pick our actual next report interval as a + * random number uniformly distributed between 0.5*t and 1.5*t. + */ + t = t * (drand48() + 0.5); + t = t / COMPENSATION; + + return (t * 1000); } static void OnExpire(trtp_rtcp_session_t* session, event_ e) { - /* This function is responsible for deciding whether to send an - * RTCP report or BYE packet now, or to reschedule transmission. - * It is also responsible for updating the pmembers, initial, tp, - * and avg_rtcp_size state variables. This function should be - * called upon expiration of the event timer used by Schedule(). - */ - - double t; /* Interval */ - double tn; /* Next transmit time */ - double tc; - - /* In the case of a BYE, we use "timer reconsideration" to - * reschedule the transmission of the BYE if necessary */ - - if (TypeOfEvent(e) == EVENT_BYE) { - t = rtcp_interval(session->members, - session->senders, - session->rtcp_bw, - session->we_sent, - session->avg_rtcp_size, - session->initial); - tn = session->tp + t; - if (tn <= session->tc()) { - SendBYEPacket(session, e); + /* This function is responsible for deciding whether to send an + * RTCP report or BYE packet now, or to reschedule transmission. + * It is also responsible for updating the pmembers, initial, tp, + * and avg_rtcp_size state variables. This function should be + * called upon expiration of the event timer used by Schedule(). + */ + + double t; /* Interval */ + double tn; /* Next transmit time */ + double tc; + + /* In the case of a BYE, we use "timer reconsideration" to + * reschedule the transmission of the BYE if necessary */ + + if (TypeOfEvent(e) == EVENT_BYE) { + t = rtcp_interval(session->members, + session->senders, + session->rtcp_bw, + session->we_sent, + session->avg_rtcp_size, + session->initial); + tn = session->tp + t; + if (tn <= session->tc()) { + SendBYEPacket(session, e); #if 0 - exit(1); + exit(1); #endif - } else { + } + else { #if 0 - Schedule(session, tn, e); + Schedule(session, tn, e); #else - Schedule(session, 0, e); + Schedule(session, 0, e); #endif - } - - } else if (TypeOfEvent(e) == EVENT_REPORT) { - t = rtcp_interval(session->members, - session->senders, - session->rtcp_bw, - session->we_sent, - session->avg_rtcp_size, - session->initial); - tn = session->tp + t; - if (tn <= (tc = session->tc())) { - tsk_size_t SentPacketSize = SendRTCPReport(session, e); - session->avg_rtcp_size = (1./16.)*SentPacketSize + (15./16.)*(session->avg_rtcp_size); - session->tp = tc; - - /* We must redraw the interval. Don't reuse the - one computed above, since its not actually - distributed the same, as we are conditioned - on it being small enough to cause a packet to - be sent */ - - t = rtcp_interval(session->members, - session->senders, - session->rtcp_bw, - session->we_sent, - session->avg_rtcp_size, - session->initial); + } + + } + else if (TypeOfEvent(e) == EVENT_REPORT) { + t = rtcp_interval(session->members, + session->senders, + session->rtcp_bw, + session->we_sent, + session->avg_rtcp_size, + session->initial); + tn = session->tp + t; + if (tn <= (tc = session->tc())) { + tsk_size_t SentPacketSize = SendRTCPReport(session, e); + session->avg_rtcp_size = (1./16.)*SentPacketSize + (15./16.)*(session->avg_rtcp_size); + session->tp = tc; + + /* We must redraw the interval. Don't reuse the + one computed above, since its not actually + distributed the same, as we are conditioned + on it being small enough to cause a packet to + be sent */ + + t = rtcp_interval(session->members, + session->senders, + session->rtcp_bw, + session->we_sent, + session->avg_rtcp_size, + session->initial); #if 0 - Schedule(session, t+tc, e); + Schedule(session, t+tc, e); #else - Schedule(session, t, e); + Schedule(session, t, e); #endif - session->initial = tsk_false; - } else { + session->initial = tsk_false; + } + else { #if 0 - Schedule(session, tn, e); + Schedule(session, tn, e); #else - Schedule(session, 0, e); + Schedule(session, 0, e); #endif - } - session->pmembers = session->members; - } + } + session->pmembers = session->members; + } } static void OnReceive(trtp_rtcp_session_t* session, const packet_ p, event_ e, tsk_size_t ReceivedPacketSize) { - /* What we do depends on whether we have left the group, and are - * waiting to send a BYE (TypeOfEvent(e) == EVENT_BYE) or an RTCP - * report. p represents the packet that was just received. */ - - if (PacketType(p) == PACKET_RTCP_REPORT) { - if (NewMember(session, p) && (TypeOfEvent(e) == EVENT_REPORT)) { - session->members += (int32_t)AddMember(session, p); - } - session->avg_rtcp_size = (1./16.)*ReceivedPacketSize + (15./16.)*(session->avg_rtcp_size); - } else if (PacketType(p) == PACKET_RTP) { + /* What we do depends on whether we have left the group, and are + * waiting to send a BYE (TypeOfEvent(e) == EVENT_BYE) or an RTCP + * report. p represents the packet that was just received. */ + + if (PacketType(p) == PACKET_RTCP_REPORT) { + if (NewMember(session, p) && (TypeOfEvent(e) == EVENT_REPORT)) { + session->members += (int32_t)AddMember(session, p); + } + session->avg_rtcp_size = (1./16.)*ReceivedPacketSize + (15./16.)*(session->avg_rtcp_size); + } + else if (PacketType(p) == PACKET_RTP) { #if 0 - if (NewMember(session, p) && (TypeOfEvent(e) == EVENT_REPORT)) { - session->members += AddMember(session, p); - } - if (NewSender(session, p) && (TypeOfEvent(e) == EVENT_REPORT)) { - tsk_size_t count = AddSender(session, p); - session->senders += count; - session->members += count; - } + if (NewMember(session, p) && (TypeOfEvent(e) == EVENT_REPORT)) { + session->members += AddMember(session, p); + } + if (NewSender(session, p) && (TypeOfEvent(e) == EVENT_REPORT)) { + tsk_size_t count = AddSender(session, p); + session->senders += count; + session->members += count; + } #else - if (NewSender(session, p)) { - tsk_size_t count = AddSender(session, p); - session->senders += (int32_t)count; - session->members += (int32_t)count; - } + if (NewSender(session, p)) { + tsk_size_t count = AddSender(session, p); + session->senders += (int32_t)count; + session->members += (int32_t)count; + } #endif - } else if (PacketType(p) == PACKET_BYE) { - session->avg_rtcp_size = (1./16.)*ReceivedPacketSize + (15./16.)*(session->avg_rtcp_size); - - if (TypeOfEvent(e) == EVENT_REPORT) { - double tc = session->tc(); - tsk_size_t count = RemoveMember(session, p); - session->senders -= (int32_t)count; - session->members -= (int32_t)count; + } + else if (PacketType(p) == PACKET_BYE) { + session->avg_rtcp_size = (1./16.)*ReceivedPacketSize + (15./16.)*(session->avg_rtcp_size); + + if (TypeOfEvent(e) == EVENT_REPORT) { + double tc = session->tc(); + tsk_size_t count = RemoveMember(session, p); + session->senders -= (int32_t)count; + session->members -= (int32_t)count; #if 0 - if (NewSender(session, p) == tsk_false) { - RemoveSender(p); - session->senders -= 1; - } - if (NewMember(session, p) == tsk_false) { - RemoveMember(p); - session->members -= 1; - } + if (NewSender(session, p) == tsk_false) { + RemoveSender(p); + session->senders -= 1; + } + if (NewMember(session, p) == tsk_false) { + RemoveMember(p); + session->members -= 1; + } #endif - if (session->members < session->pmembers && session->pmembers) { - session->tn = (time_tp)(tc + - (((double) session->members)/(session->pmembers))*(session->tn - tc)); - session->tp = (time_tp)(tc - - (((double) session->members)/(session->pmembers))*(tc - session->tp)); + if (session->members < session->pmembers && session->pmembers) { + session->tn = (time_tp)(tc + + (((double) session->members)/(session->pmembers))*(session->tn - tc)); + session->tp = (time_tp)(tc - + (((double) session->members)/(session->pmembers))*(tc - session->tp)); - /* Reschedule the next report for time tn */ + /* Reschedule the next report for time tn */ - Reschedule(session, session->tn, e); - session->pmembers = session->members; - } + Reschedule(session, session->tn, e); + session->pmembers = session->members; + } - } else if (TypeOfEvent(e) == EVENT_BYE) { - session->members += 1; - } - } + } + else if (TypeOfEvent(e) == EVENT_BYE) { + session->members += 1; + } + } } |