diff options
Diffstat (limited to 'tinyRTP/src')
-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 | ||||
-rwxr-xr-x | tinyRTP/src/rtp/trtp_rtp_header.c | 353 | ||||
-rwxr-xr-x | tinyRTP/src/rtp/trtp_rtp_packet.c | 339 | ||||
-rwxr-xr-x | tinyRTP/src/rtp/trtp_rtp_session.c | 6 | ||||
-rwxr-xr-x | tinyRTP/src/trtp.c | 6 | ||||
-rwxr-xr-x | tinyRTP/src/trtp_manager.c | 2932 | ||||
-rwxr-xr-x | tinyRTP/src/trtp_srtp.c | 208 |
19 files changed, 4979 insertions, 4807 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; + } + } } diff --git a/tinyRTP/src/rtp/trtp_rtp_header.c b/tinyRTP/src/rtp/trtp_rtp_header.c index e833b10..7843d1b 100755 --- a/tinyRTP/src/rtp/trtp_rtp_header.c +++ b/tinyRTP/src/rtp/trtp_rtp_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. * @@ -33,49 +33,49 @@ #include "tsk_memory.h" #include "tsk_debug.h" - /* RFC 3550 section 5.1 - RTP Fixed Header Fields - 0 1 2 3 - 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 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |V=2|P|X| CC |M| PT | sequence number | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | timestamp | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | synchronization source (SSRC) identifier | - +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ - | contributing source (CSRC) identifiers | - | .... | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ +/* RFC 3550 section 5.1 - RTP Fixed Header Fields + 0 1 2 3 + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V=2|P|X| CC |M| PT | sequence number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | timestamp | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | synchronization source (SSRC) identifier | + +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + | contributing source (CSRC) identifiers | + | .... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ /* Create new RTP header */ trtp_rtp_header_t* trtp_rtp_header_create_null() { - return tsk_object_new(trtp_rtp_header_def_t); + return tsk_object_new(trtp_rtp_header_def_t); } trtp_rtp_header_t* trtp_rtp_header_create(uint32_t ssrc, uint16_t seq_num, uint32_t timestamp, uint8_t payload_type, tsk_bool_t marker) { - trtp_rtp_header_t* header; - if((header = trtp_rtp_header_create_null())){ - header->version = TRTP_RTP_VERSION; - header->marker = marker ? 1 : 0; - header->payload_type = payload_type; - header->seq_num = seq_num; - header->timestamp = timestamp; - header->ssrc = ssrc; - } - return header; + trtp_rtp_header_t* header; + if((header = trtp_rtp_header_create_null())) { + header->version = TRTP_RTP_VERSION; + header->marker = marker ? 1 : 0; + header->payload_type = payload_type; + header->seq_num = seq_num; + header->timestamp = timestamp; + header->ssrc = ssrc; + } + return header; } /* guess what is the minimum required size to serialize the header */ tsk_size_t trtp_rtp_header_guess_serialbuff_size(const trtp_rtp_header_t *self) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - return (TRTP_RTP_HEADER_MIN_SIZE + (self->csrc_count << 2)); + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + return (TRTP_RTP_HEADER_MIN_SIZE + (self->csrc_count << 2)); } /* serialize the RTP header to a buffer */ @@ -83,145 +83,145 @@ tsk_size_t trtp_rtp_header_guess_serialbuff_size(const trtp_rtp_header_t *self) // returns the number of written bytes tsk_size_t trtp_rtp_header_serialize_to(const trtp_rtp_header_t *self, void *buffer, tsk_size_t size) { - tsk_size_t ret; - tsk_size_t i, j; - uint8_t* pbuff = (uint8_t*)buffer; - - if(!buffer || (size < (ret = trtp_rtp_header_guess_serialbuff_size(self)))){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - - // Octet-0: version(2), Padding(1), Extension(1), CSRC Count(4) - pbuff[0] = (((uint8_t)self->version)<< 6) | - (((uint8_t)self->padding)<< 5) | - (((uint8_t)self->extension)<< 4) | - ((uint8_t)self->csrc_count); - // Octet-1: Marker(1), Payload Type(7) - pbuff[1] = (((uint8_t)self->marker)<< 7) | - ((uint8_t)self->payload_type); - // Octet-2-3: Sequence number (16) - // *((uint16_t*)&pbuff[2]) = tnet_htons(self->seq_num); - pbuff[2] = self->seq_num >> 8; - pbuff[3] = self->seq_num & 0xFF; - // Octet-4-5-6-7: timestamp (32) - // ((uint32_t*)&pbuff[4]) = tnet_htonl(self->timestamp); - pbuff[4] = self->timestamp >> 24; - pbuff[5] = (self->timestamp >> 16) & 0xFF; - pbuff[6] = (self->timestamp >> 8) & 0xFF; - pbuff[7] = self->timestamp & 0xFF; - // Octet-8-9-10-11: SSRC (32) - //((uint32_t*)&pbuff[8]) = tnet_htonl(self->ssrc); - pbuff[8] = self->ssrc >> 24; - pbuff[9] = (self->ssrc >> 16) & 0xFF; - pbuff[10] = (self->ssrc >> 8) & 0xFF; - pbuff[11] = self->ssrc & 0xFF; - - // Octet-12-13-14-15-****: CSRC - for(i = 0, j = 12; i<self->csrc_count; ++i, ++j){ - // *((uint32_t*)&pbuff[12+i]) = tnet_htonl(self->csrc[i]); - pbuff[j] = self->csrc[i] >> 24; - pbuff[j + 1] = (self->csrc[i] >> 16) & 0xFF; - pbuff[j + 2] = (self->csrc[i] >> 8) & 0xFF; - pbuff[j + 3] = self->csrc[i] & 0xFF; - } - - return ret; + tsk_size_t ret; + tsk_size_t i, j; + uint8_t* pbuff = (uint8_t*)buffer; + + if(!buffer || (size < (ret = trtp_rtp_header_guess_serialbuff_size(self)))) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + // Octet-0: version(2), Padding(1), Extension(1), CSRC Count(4) + pbuff[0] = (((uint8_t)self->version)<< 6) | + (((uint8_t)self->padding)<< 5) | + (((uint8_t)self->extension)<< 4) | + ((uint8_t)self->csrc_count); + // Octet-1: Marker(1), Payload Type(7) + pbuff[1] = (((uint8_t)self->marker)<< 7) | + ((uint8_t)self->payload_type); + // Octet-2-3: Sequence number (16) + // *((uint16_t*)&pbuff[2]) = tnet_htons(self->seq_num); + pbuff[2] = self->seq_num >> 8; + pbuff[3] = self->seq_num & 0xFF; + // Octet-4-5-6-7: timestamp (32) + // ((uint32_t*)&pbuff[4]) = tnet_htonl(self->timestamp); + pbuff[4] = self->timestamp >> 24; + pbuff[5] = (self->timestamp >> 16) & 0xFF; + pbuff[6] = (self->timestamp >> 8) & 0xFF; + pbuff[7] = self->timestamp & 0xFF; + // Octet-8-9-10-11: SSRC (32) + //((uint32_t*)&pbuff[8]) = tnet_htonl(self->ssrc); + pbuff[8] = self->ssrc >> 24; + pbuff[9] = (self->ssrc >> 16) & 0xFF; + pbuff[10] = (self->ssrc >> 8) & 0xFF; + pbuff[11] = self->ssrc & 0xFF; + + // Octet-12-13-14-15-****: CSRC + for(i = 0, j = 12; i<self->csrc_count; ++i, ++j) { + // *((uint32_t*)&pbuff[12+i]) = tnet_htonl(self->csrc[i]); + pbuff[j] = self->csrc[i] >> 24; + pbuff[j + 1] = (self->csrc[i] >> 16) & 0xFF; + pbuff[j + 2] = (self->csrc[i] >> 8) & 0xFF; + pbuff[j + 3] = self->csrc[i] & 0xFF; + } + + return ret; } /** Serialize rtp header object into binary buffer */ tsk_buffer_t* trtp_rtp_header_serialize(const trtp_rtp_header_t *self) { - tsk_buffer_t* buffer; - tsk_size_t size; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - size = trtp_rtp_header_guess_serialbuff_size(self); - if(!(buffer = tsk_buffer_create(tsk_null, size))){ - TSK_DEBUG_ERROR("Failed to create new buffer"); - TSK_OBJECT_SAFE_FREE(buffer); - } - else{ - size = trtp_rtp_header_serialize_to(self, buffer->data, buffer->size); - } - - return buffer; + tsk_buffer_t* buffer; + tsk_size_t size; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + size = trtp_rtp_header_guess_serialbuff_size(self); + if(!(buffer = tsk_buffer_create(tsk_null, size))) { + TSK_DEBUG_ERROR("Failed to create new buffer"); + TSK_OBJECT_SAFE_FREE(buffer); + } + else { + size = trtp_rtp_header_serialize_to(self, buffer->data, buffer->size); + } + + return buffer; } /** Deserialize rtp header object from binary buffer */ trtp_rtp_header_t* trtp_rtp_header_deserialize(const void *data, tsk_size_t size) { - trtp_rtp_header_t* header = tsk_null; - const uint8_t* pdata = (const uint8_t*)data; - uint8_t csrc_count, i; - - if(!data){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - if(size <TRTP_RTP_HEADER_MIN_SIZE){ - TSK_DEBUG_ERROR("Too short to contain RTP header"); - return tsk_null; - } - - /* Before starting to deserialize, get the "csrc_count" and check the length validity - * CSRC count (4 last bits) - */ - csrc_count = (*pdata & 0x0F); - if(size <(tsk_size_t)TRTP_RTP_HEADER_MIN_SIZE + (csrc_count << 2)){ - TSK_DEBUG_ERROR("Too short to contain RTP header"); - return tsk_null; - } - - if(!(header = trtp_rtp_header_create_null())){ - TSK_DEBUG_ERROR("Failed to create new RTP header"); - return tsk_null; - } - - /* version (2bits) */ - header->version = (*pdata >> 6); - /* Padding (1bit) */ - header->padding = ((*pdata >>5) & 0x01); - /* Extension (1bit) */ - header->extension = ((*pdata >>4) & 0x01); - /* CSRC Count (4bits) */ - header->csrc_count = csrc_count; - // skip octet - ++pdata; - - /* Marker (1bit) */ - header->marker = (*pdata >> 7); - /* Payload Type (7bits) */ - header->payload_type = (*pdata & 0x7F); - // skip octet - ++pdata; - - /* Sequence Number (16bits) */ - header->seq_num = pdata[0] << 8 | pdata[1]; - // skip octets - pdata += 2; - - /* timestamp (32bits) */ - header->timestamp = pdata[0] << 24 | pdata[1] << 16 | pdata[2] << 8 | pdata[3]; - // skip octets - pdata += 4; - - /* synchronization source (SSRC) identifier (32bits) */ - header->ssrc = pdata[0] << 24 | pdata[1] << 16 | pdata[2] << 8 | pdata[3]; - // skip octets - pdata += 4; - - /* contributing source (CSRC) identifiers */ - for(i=0; i<csrc_count; i++, pdata += 4){ - header->csrc[i] = pdata[0] << 24 | pdata[1] << 16 | pdata[2] << 8 | pdata[3]; - } - - return header; + trtp_rtp_header_t* header = tsk_null; + const uint8_t* pdata = (const uint8_t*)data; + uint8_t csrc_count, i; + + if(!data) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + if(size <TRTP_RTP_HEADER_MIN_SIZE) { + TSK_DEBUG_ERROR("Too short to contain RTP header"); + return tsk_null; + } + + /* Before starting to deserialize, get the "csrc_count" and check the length validity + * CSRC count (4 last bits) + */ + csrc_count = (*pdata & 0x0F); + if(size <(tsk_size_t)TRTP_RTP_HEADER_MIN_SIZE + (csrc_count << 2)) { + TSK_DEBUG_ERROR("Too short to contain RTP header"); + return tsk_null; + } + + if(!(header = trtp_rtp_header_create_null())) { + TSK_DEBUG_ERROR("Failed to create new RTP header"); + return tsk_null; + } + + /* version (2bits) */ + header->version = (*pdata >> 6); + /* Padding (1bit) */ + header->padding = ((*pdata >>5) & 0x01); + /* Extension (1bit) */ + header->extension = ((*pdata >>4) & 0x01); + /* CSRC Count (4bits) */ + header->csrc_count = csrc_count; + // skip octet + ++pdata; + + /* Marker (1bit) */ + header->marker = (*pdata >> 7); + /* Payload Type (7bits) */ + header->payload_type = (*pdata & 0x7F); + // skip octet + ++pdata; + + /* Sequence Number (16bits) */ + header->seq_num = pdata[0] << 8 | pdata[1]; + // skip octets + pdata += 2; + + /* timestamp (32bits) */ + header->timestamp = pdata[0] << 24 | pdata[1] << 16 | pdata[2] << 8 | pdata[3]; + // skip octets + pdata += 4; + + /* synchronization source (SSRC) identifier (32bits) */ + header->ssrc = pdata[0] << 24 | pdata[1] << 16 | pdata[2] << 8 | pdata[3]; + // skip octets + pdata += 4; + + /* contributing source (CSRC) identifiers */ + for(i=0; i<csrc_count; i++, pdata += 4) { + header->csrc[i] = pdata[0] << 24 | pdata[1] << 16 | pdata[2] << 8 | pdata[3]; + } + + return header; } @@ -234,26 +234,25 @@ trtp_rtp_header_t* trtp_rtp_header_deserialize(const void *data, tsk_size_t size // static tsk_object_t* trtp_rtp_header_ctor(tsk_object_t * self, va_list * app) { - trtp_rtp_header_t *header = self; - if(header){ - } - return self; + trtp_rtp_header_t *header = self; + if(header) { + } + return self; } static tsk_object_t* trtp_rtp_header_dtor(tsk_object_t * self) -{ - trtp_rtp_header_t *header = self; - if(header){ - } +{ + trtp_rtp_header_t *header = self; + if(header) { + } - return self; + return self; } -static const tsk_object_def_t trtp_rtp_header_def_s = -{ - sizeof(trtp_rtp_header_t), - trtp_rtp_header_ctor, - trtp_rtp_header_dtor, - tsk_null, +static const tsk_object_def_t trtp_rtp_header_def_s = { + sizeof(trtp_rtp_header_t), + trtp_rtp_header_ctor, + trtp_rtp_header_dtor, + tsk_null, }; const tsk_object_def_t *trtp_rtp_header_def_t = &trtp_rtp_header_def_s; diff --git a/tinyRTP/src/rtp/trtp_rtp_packet.c b/tinyRTP/src/rtp/trtp_rtp_packet.c index dc5c7ea..4d10023 100755 --- a/tinyRTP/src/rtp/trtp_rtp_packet.c +++ b/tinyRTP/src/rtp/trtp_rtp_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. * @@ -38,46 +38,46 @@ /** Create new RTP packet */ trtp_rtp_packet_t* trtp_rtp_packet_create_null() { - return tsk_object_new(trtp_rtp_packet_def_t); + return tsk_object_new(trtp_rtp_packet_def_t); } trtp_rtp_packet_t* trtp_rtp_packet_create(uint32_t ssrc, uint16_t seq_num, uint32_t timestamp, uint8_t payload_type, tsk_bool_t marker) { - trtp_rtp_packet_t* packet; - if((packet = tsk_object_new(trtp_rtp_packet_def_t))){ - packet->header = trtp_rtp_header_create(ssrc, seq_num, timestamp, payload_type, marker); - } - return packet; + trtp_rtp_packet_t* packet; + if((packet = tsk_object_new(trtp_rtp_packet_def_t))) { + packet->header = trtp_rtp_header_create(ssrc, seq_num, timestamp, payload_type, marker); + } + return packet; } trtp_rtp_packet_t* trtp_rtp_packet_create_2(const trtp_rtp_header_t* header) { - trtp_rtp_packet_t* packet; - - if(!header){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - if((packet = tsk_object_new(trtp_rtp_packet_def_t))){ - packet->header = tsk_object_ref(TSK_OBJECT(header)); - } - return packet; + trtp_rtp_packet_t* packet; + + if(!header) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + if((packet = tsk_object_new(trtp_rtp_packet_def_t))) { + packet->header = tsk_object_ref(TSK_OBJECT(header)); + } + return packet; } /* guess what is the minimum required size to serialize the packet */ tsk_size_t trtp_rtp_packet_guess_serialbuff_size(const trtp_rtp_packet_t *self) -{ - tsk_size_t size = 0; - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - size += trtp_rtp_header_guess_serialbuff_size(self->header); - if(self->extension.data && self->extension.size && self->header->extension){ - size += self->extension.size; - } - size += self->payload.size; - return size; +{ + tsk_size_t size = 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + size += trtp_rtp_header_guess_serialbuff_size(self->header); + if(self->extension.data && self->extension.size && self->header->extension) { + size += self->extension.size; + } + size += self->payload.size; + return size; } /* serialize the RTP packet to a buffer */ @@ -85,27 +85,27 @@ tsk_size_t trtp_rtp_packet_guess_serialbuff_size(const trtp_rtp_packet_t *self) // returns the number of written bytes tsk_size_t trtp_rtp_packet_serialize_to(const trtp_rtp_packet_t *self, void* buffer, tsk_size_t size) { - tsk_size_t ret; - tsk_size_t s; - uint8_t* pbuff = (uint8_t*)buffer; - - if(!buffer || (size < (ret = trtp_rtp_packet_guess_serialbuff_size(self)))){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - - s = trtp_rtp_header_serialize_to(self->header, pbuff, size); - pbuff += s; - - /* extension */ - if(self->extension.data && self->extension.size && self->header->extension){ - memcpy(pbuff, self->extension.data, self->extension.size); - pbuff += self->extension.size; - } - /* append payload */ - memcpy(pbuff, self->payload.data_const ? self->payload.data_const : self->payload.data, self->payload.size); - - return ret; + tsk_size_t ret; + tsk_size_t s; + uint8_t* pbuff = (uint8_t*)buffer; + + if(!buffer || (size < (ret = trtp_rtp_packet_guess_serialbuff_size(self)))) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + s = trtp_rtp_header_serialize_to(self->header, pbuff, size); + pbuff += s; + + /* extension */ + if(self->extension.data && self->extension.size && self->header->extension) { + memcpy(pbuff, self->extension.data, self->extension.size); + pbuff += self->extension.size; + } + /* append payload */ + memcpy(pbuff, self->payload.data_const ? self->payload.data_const : self->payload.data, self->payload.size); + + return ret; } /** Serialize rtp packet object into binary buffer */ @@ -113,98 +113,100 @@ tsk_size_t trtp_rtp_packet_serialize_to(const trtp_rtp_packet_t *self, void* buf // the padding bytes will not be added to the final buffer size tsk_buffer_t* trtp_rtp_packet_serialize(const trtp_rtp_packet_t *self, tsk_size_t num_bytes_pad) { - tsk_buffer_t* buffer = tsk_null; - tsk_size_t size; - - if(!self || !self->header){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - size = (trtp_rtp_packet_guess_serialbuff_size(self) + num_bytes_pad); - if(size & 0x03) size += (4 - (size & 0x03)); - - if(!(buffer = tsk_buffer_create(tsk_null, size))){ - TSK_DEBUG_ERROR("Failed to create buffer with size = %u", (unsigned)size); - return tsk_null; - } - // shorten the buffer to hide the padding - buffer->size = trtp_rtp_packet_serialize_to(self, buffer->data, buffer->size); - return buffer; + tsk_buffer_t* buffer = tsk_null; + tsk_size_t size; + + if(!self || !self->header) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + size = (trtp_rtp_packet_guess_serialbuff_size(self) + num_bytes_pad); + if(size & 0x03) { + size += (4 - (size & 0x03)); + } + + if(!(buffer = tsk_buffer_create(tsk_null, size))) { + TSK_DEBUG_ERROR("Failed to create buffer with size = %u", (unsigned)size); + return tsk_null; + } + // shorten the buffer to hide the padding + buffer->size = trtp_rtp_packet_serialize_to(self, buffer->data, buffer->size); + return buffer; } /** Deserialize rtp packet object from binary buffer */ trtp_rtp_packet_t* trtp_rtp_packet_deserialize(const void *data, tsk_size_t size) { - trtp_rtp_packet_t* packet = tsk_null; - trtp_rtp_header_t *header; - tsk_size_t payload_size; - const uint8_t* pdata = data; - - if(!data){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - if(size< TRTP_RTP_HEADER_MIN_SIZE){ - TSK_DEBUG_ERROR("Too short to contain RTP message"); - return tsk_null; - } - - /* deserialize the RTP header (the packet itsel will be deserialized only if the header deserialization succeed) */ - if(!(header = trtp_rtp_header_deserialize(data, size))){ - TSK_DEBUG_ERROR("Failed to deserialize RTP header"); - return tsk_null; - } - else{ - /* create the packet */ - if(!(packet = trtp_rtp_packet_create_null())){ - TSK_DEBUG_ERROR("Failed to create new RTP packet"); - TSK_OBJECT_SAFE_FREE(header); - return tsk_null; - } - /* set the header */ - packet->header = header, - header = tsk_null; - - /* do not need to check overflow (have been done by trtp_rtp_header_deserialize()) */ - payload_size = (size - TRTP_RTP_HEADER_MIN_SIZE - (packet->header->csrc_count << 2)); - pdata = ((const uint8_t*)data) + (size - payload_size); - - /* RFC 3550 - 5.3.1 RTP Header Extension - If the X bit in the RTP header is one, a variable-length header - extension MUST be appended to the RTP header, following the CSRC list - if present. The header extension contains a 16-bit length field that - counts the number of 32-bit words in the extension, excluding the - four-octet extension header (therefore zero is a valid length). Only - a single extension can be appended to the RTP data header. - 0 1 2 3 - 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 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | defined by profile | length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | header extension | - | .... | - */ - if(packet->header->extension && payload_size>=4 /* extension min-size */){ - packet->extension.size = 4 /* first two 16-bit fields */ + (tnet_ntohs(*((uint16_t*)&pdata[2])) << 2/*words(32-bit)*/); - if((packet->extension.data = tsk_calloc(packet->extension.size, sizeof(uint8_t)))){ - memcpy(packet->extension.data, pdata, packet->extension.size); - } - payload_size -= packet->extension.size; - } - - packet->payload.size = payload_size; - if(payload_size && (packet->payload.data = tsk_calloc(packet->payload.size, sizeof(uint8_t)))){ - memcpy(packet->payload.data, (pdata + packet->extension.size), packet->payload.size); - } - else{ - TSK_DEBUG_ERROR("Failed to allocate new buffer"); - packet->payload.size = 0; - } - } - - return packet; + trtp_rtp_packet_t* packet = tsk_null; + trtp_rtp_header_t *header; + tsk_size_t payload_size; + const uint8_t* pdata = data; + + if(!data) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + if(size< TRTP_RTP_HEADER_MIN_SIZE) { + TSK_DEBUG_ERROR("Too short to contain RTP message"); + return tsk_null; + } + + /* deserialize the RTP header (the packet itsel will be deserialized only if the header deserialization succeed) */ + if(!(header = trtp_rtp_header_deserialize(data, size))) { + TSK_DEBUG_ERROR("Failed to deserialize RTP header"); + return tsk_null; + } + else { + /* create the packet */ + if(!(packet = trtp_rtp_packet_create_null())) { + TSK_DEBUG_ERROR("Failed to create new RTP packet"); + TSK_OBJECT_SAFE_FREE(header); + return tsk_null; + } + /* set the header */ + packet->header = header, + header = tsk_null; + + /* do not need to check overflow (have been done by trtp_rtp_header_deserialize()) */ + payload_size = (size - TRTP_RTP_HEADER_MIN_SIZE - (packet->header->csrc_count << 2)); + pdata = ((const uint8_t*)data) + (size - payload_size); + + /* RFC 3550 - 5.3.1 RTP Header Extension + If the X bit in the RTP header is one, a variable-length header + extension MUST be appended to the RTP header, following the CSRC list + if present. The header extension contains a 16-bit length field that + counts the number of 32-bit words in the extension, excluding the + four-octet extension header (therefore zero is a valid length). Only + a single extension can be appended to the RTP data header. + 0 1 2 3 + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | defined by profile | length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | header extension | + | .... | + */ + if(packet->header->extension && payload_size>=4 /* extension min-size */) { + packet->extension.size = 4 /* first two 16-bit fields */ + (tnet_ntohs(*((uint16_t*)&pdata[2])) << 2/*words(32-bit)*/); + if((packet->extension.data = tsk_calloc(packet->extension.size, sizeof(uint8_t)))) { + memcpy(packet->extension.data, pdata, packet->extension.size); + } + payload_size -= packet->extension.size; + } + + packet->payload.size = payload_size; + if(payload_size && (packet->payload.data = tsk_calloc(packet->payload.size, sizeof(uint8_t)))) { + memcpy(packet->payload.data, (pdata + packet->extension.size), packet->payload.size); + } + else { + TSK_DEBUG_ERROR("Failed to allocate new buffer"); + packet->payload.size = 0; + } + } + + return packet; } @@ -220,41 +222,44 @@ trtp_rtp_packet_t* trtp_rtp_packet_deserialize(const void *data, tsk_size_t size // static tsk_object_t* trtp_rtp_packet_ctor(tsk_object_t * self, va_list * app) { - trtp_rtp_packet_t *packet = self; - if(packet){ - } - return self; + trtp_rtp_packet_t *packet = self; + if(packet) { + } + return self; } static tsk_object_t* trtp_rtp_packet_dtor(tsk_object_t * self) -{ - trtp_rtp_packet_t *packet = self; - if(packet){ - TSK_OBJECT_SAFE_FREE(packet->header); - TSK_FREE(packet->payload.data); - TSK_FREE(packet->extension.data); - packet->payload.data_const = tsk_null; - } - - return self; +{ + trtp_rtp_packet_t *packet = self; + if(packet) { + TSK_OBJECT_SAFE_FREE(packet->header); + TSK_FREE(packet->payload.data); + TSK_FREE(packet->extension.data); + packet->payload.data_const = tsk_null; + } + + return self; } // comparison must be by sequence number because of the jb static int trtp_rtp_packet_cmp(const tsk_object_t *_p1, const tsk_object_t *_p2) { - const trtp_rtp_packet_t *p1 = _p1; - const trtp_rtp_packet_t *p2 = _p2; - - if(p1 && p1->header && p2 && p2->header){ - return (int)(p1->header->seq_num - p2->header->seq_num); - } - else if(!p1 && !p2) return 0; - else return -1; + const trtp_rtp_packet_t *p1 = _p1; + const trtp_rtp_packet_t *p2 = _p2; + + if(p1 && p1->header && p2 && p2->header) { + return (int)(p1->header->seq_num - p2->header->seq_num); + } + else if(!p1 && !p2) { + return 0; + } + else { + return -1; + } } -static const tsk_object_def_t trtp_rtp_packet_def_s = -{ - sizeof(trtp_rtp_packet_t), - trtp_rtp_packet_ctor, - trtp_rtp_packet_dtor, - trtp_rtp_packet_cmp, +static const tsk_object_def_t trtp_rtp_packet_def_s = { + sizeof(trtp_rtp_packet_t), + trtp_rtp_packet_ctor, + trtp_rtp_packet_dtor, + trtp_rtp_packet_cmp, }; const tsk_object_def_t *trtp_rtp_packet_def_t = &trtp_rtp_packet_def_s; diff --git a/tinyRTP/src/rtp/trtp_rtp_session.c b/tinyRTP/src/rtp/trtp_rtp_session.c index 3ebfe03..919a888 100755 --- a/tinyRTP/src/rtp/trtp_rtp_session.c +++ b/tinyRTP/src/rtp/trtp_rtp_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. * diff --git a/tinyRTP/src/trtp.c b/tinyRTP/src/trtp.c index a0150d9..6581304 100755 --- a/tinyRTP/src/trtp.c +++ b/tinyRTP/src/trtp.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/trtp_manager.c b/tinyRTP/src/trtp_manager.c index 70968d3..16aeab1 100755 --- a/tinyRTP/src/trtp_manager.c +++ b/tinyRTP/src/trtp_manager.c @@ -1,19 +1,19 @@ /* * Copyright (C) 2012 Mamadou Diop * Copyright (C) 2012-2013 Doubango Telecom <http://www.doubango.org> -* +* * This file is part of Open Source Doubango Framework. * * DOUBANGO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. -* +* * DOUBANGO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. -* +* * You should have received a copy of the GNU General Public License * along with DOUBANGO. * @@ -86,381 +86,388 @@ static int _trtp_manager_srtp_start(trtp_manager_t* self, tmedia_srtp_type_t srt /* ======================= Transport callback ========================== */ static int _trtp_transport_layer_cb(const tnet_transport_event_t* e) { - trtp_manager_t* manager = (trtp_manager_t*)e->callback_data; - - switch(e->type){ - case event_data: - { - return _trtp_manager_recv_data(manager, e->data, e->size, e->local_fd, &e->remote_addr); - } - case event_brokenpipe: - { - tnet_fd_t broken_fd; - tnet_socket_t* socket; - tsk_bool_t is_rtcp_socket; - - tsk_safeobj_lock(manager); - broken_fd = e->local_fd; - socket = tsk_null; - is_rtcp_socket = tsk_false; - - if (manager->transport && manager->transport->master && manager->transport->master->fd == broken_fd) { - socket = manager->transport->master; - } - else if (manager->rtcp.local_socket && manager->rtcp.local_socket->fd == broken_fd) { - socket = manager->rtcp.local_socket; - is_rtcp_socket = tsk_true; + trtp_manager_t* manager = (trtp_manager_t*)e->callback_data; + + switch(e->type) { + case event_data: { + return _trtp_manager_recv_data(manager, e->data, e->size, e->local_fd, &e->remote_addr); + } + case event_brokenpipe: { + tnet_fd_t broken_fd; + tnet_socket_t* socket; + tsk_bool_t is_rtcp_socket; + + tsk_safeobj_lock(manager); + broken_fd = e->local_fd; + socket = tsk_null; + is_rtcp_socket = tsk_false; + + if (manager->transport && manager->transport->master && manager->transport->master->fd == broken_fd) { + socket = manager->transport->master; + } + else if (manager->rtcp.local_socket && manager->rtcp.local_socket->fd == broken_fd) { + socket = manager->rtcp.local_socket; + is_rtcp_socket = tsk_true; + } + if (socket) { + tsk_bool_t registered_fd = !!tnet_transport_have_socket(manager->transport, broken_fd); + if (registered_fd) { + tnet_transport_remove_socket(manager->transport, &broken_fd); // broken_fd=-1 + broken_fd = e->local_fd; // restore + } + if (tnet_socket_handle_brokenpipe(socket) == 0) { + if (registered_fd) { + tnet_transport_add_socket(manager->transport, socket->fd, socket->type, tsk_false/* do not take ownership */, tsk_true/* only Meaningful for tls*/, tsk_null); } - if (socket) { - tsk_bool_t registered_fd = !!tnet_transport_have_socket(manager->transport, broken_fd); - if (registered_fd) { - tnet_transport_remove_socket(manager->transport, &broken_fd); // broken_fd=-1 - broken_fd = e->local_fd; // restore - } - if (tnet_socket_handle_brokenpipe(socket) == 0) { - if (registered_fd) { - tnet_transport_add_socket(manager->transport, socket->fd, socket->type, tsk_false/* do not take ownership */, tsk_true/* only Meaningful for tls*/, tsk_null); - } - if (manager->rtcp.session && trtp_rtcp_session_get_local_fd(manager->rtcp.session) == broken_fd) { - trtp_rtcp_session_set_local_fd(manager->rtcp.session, socket->fd); - } - } + if (manager->rtcp.session && trtp_rtcp_session_get_local_fd(manager->rtcp.session) == broken_fd) { + trtp_rtcp_session_set_local_fd(manager->rtcp.session, socket->fd); } - tsk_safeobj_unlock(manager); - return 0; } + } + tsk_safeobj_unlock(manager); + return 0; + } #if HAVE_SRTP - /* DTLS - SRTP events */ - case event_dtls_handshake_succeed: - { - const tnet_socket_t* socket = manager->transport && manager->transport->master && (manager->transport->master->fd == e->local_fd) - ? manager->transport->master - : ((manager->rtcp.local_socket && manager->rtcp.local_socket->fd == e->local_fd) ? manager->rtcp.local_socket : tsk_null); - if(!socket){ - TSK_DEBUG_ERROR("DTLS data from unknown socket"); - break; - } - - if (!manager->dtls.srtp_handshake_succeed) { - manager->dtls.srtp_handshake_succeed = (socket == manager->transport->master); - } - if (!manager->dtls.srtcp_handshake_succeed) { - manager->dtls.srtcp_handshake_succeed = (socket == manager->rtcp.local_socket) || _trtp_manager_is_rtcpmux_active(manager); - } - - TSK_DEBUG_INFO("dtls.srtp_handshake_succeed=%d, dtls.srtcp_handshake_succeed=%d", manager->dtls.srtp_handshake_succeed, manager->dtls.srtcp_handshake_succeed); - TSK_DEBUG_INFO("DTLS-DTLS-SRTP socket [%s]:%d handshake succeed", socket->ip, socket->port); - - if(manager->dtls.srtp_handshake_succeed && manager->dtls.srtcp_handshake_succeed){ - // alter listeners - if(manager->dtls.cb.fun){ - manager->dtls.cb.fun(manager->dtls.cb.usrdata, trtp_srtp_dtls_event_type_handshake_succeed, "DTLS handshake succeed"); - } - } - break; - } - case event_dtls_fingerprint_mismatch: - case event_dtls_handshake_failed: - case event_dtls_error: - { - // alter listeners - if(manager->dtls.cb.fun){ - const char* reason = (e->type == event_dtls_fingerprint_mismatch) - ? "DTLS-SRTP fingerprint mismatch" - : (e->type == event_dtls_handshake_failed ? "DTLS-SRTP handshake failed" : "DTLS error"); - manager->dtls.cb.fun(manager->dtls.cb.usrdata, trtp_srtp_dtls_event_type_handshake_failed, reason); - } - break; - } - case event_dtls_srtp_data: - { - /* KEY||SALT */ - /* rfc 5764 - 4.2. Key Derivation */ - tsk_bool_t is_rtp = (manager->transport->master && manager->transport->master->fd == e->local_fd); - tsk_bool_t is_rtcp = (manager->rtcp.local_socket && manager->rtcp.local_socket->fd == e->local_fd); - if(is_rtp || is_rtcp){ - unsigned int master_salt_length, master_key_length; - + /* DTLS - SRTP events */ + case event_dtls_handshake_succeed: { + const tnet_socket_t* socket = manager->transport && manager->transport->master && (manager->transport->master->fd == e->local_fd) + ? manager->transport->master + : ((manager->rtcp.local_socket && manager->rtcp.local_socket->fd == e->local_fd) ? manager->rtcp.local_socket : tsk_null); + if(!socket) { + TSK_DEBUG_ERROR("DTLS data from unknown socket"); + break; + } + + if (!manager->dtls.srtp_handshake_succeed) { + manager->dtls.srtp_handshake_succeed = (socket == manager->transport->master); + } + if (!manager->dtls.srtcp_handshake_succeed) { + manager->dtls.srtcp_handshake_succeed = (socket == manager->rtcp.local_socket) || _trtp_manager_is_rtcpmux_active(manager); + } + + TSK_DEBUG_INFO("dtls.srtp_handshake_succeed=%d, dtls.srtcp_handshake_succeed=%d", manager->dtls.srtp_handshake_succeed, manager->dtls.srtcp_handshake_succeed); + TSK_DEBUG_INFO("DTLS-DTLS-SRTP socket [%s]:%d handshake succeed", socket->ip, socket->port); + + if(manager->dtls.srtp_handshake_succeed && manager->dtls.srtcp_handshake_succeed) { + // alter listeners + if(manager->dtls.cb.fun) { + manager->dtls.cb.fun(manager->dtls.cb.usrdata, trtp_srtp_dtls_event_type_handshake_succeed, "DTLS handshake succeed"); + } + } + break; + } + case event_dtls_fingerprint_mismatch: + case event_dtls_handshake_failed: + case event_dtls_error: { + // alter listeners + if(manager->dtls.cb.fun) { + const char* reason = (e->type == event_dtls_fingerprint_mismatch) + ? "DTLS-SRTP fingerprint mismatch" + : (e->type == event_dtls_handshake_failed ? "DTLS-SRTP handshake failed" : "DTLS error"); + manager->dtls.cb.fun(manager->dtls.cb.usrdata, trtp_srtp_dtls_event_type_handshake_failed, reason); + } + break; + } + case event_dtls_srtp_data: { + /* KEY||SALT */ + /* rfc 5764 - 4.2. Key Derivation */ + tsk_bool_t is_rtp = (manager->transport->master && manager->transport->master->fd == e->local_fd); + tsk_bool_t is_rtcp = (manager->rtcp.local_socket && manager->rtcp.local_socket->fd == e->local_fd); + if(is_rtp || is_rtcp) { + unsigned int master_salt_length, master_key_length; + #if HAVE_SRTP_PROFILE_GET_MASTER_KEY_LENGTH - master_key_length = srtp_profile_get_master_key_length(manager->dtls.crypto_selected == HMAC_SHA1_32 ? srtp_profile_aes128_cm_sha1_32 : srtp_profile_aes128_cm_sha1_80); + master_key_length = srtp_profile_get_master_key_length(manager->dtls.crypto_selected == HMAC_SHA1_32 ? srtp_profile_aes128_cm_sha1_32 : srtp_profile_aes128_cm_sha1_80); #else - master_key_length = (128 >> 3); // cipher_key_length - rfc5764 4.1.2. SRTP Protection Profiles + master_key_length = (128 >> 3); // cipher_key_length - rfc5764 4.1.2. SRTP Protection Profiles #endif #if HAVE_SRTP_PROFILE_GET_MASTER_SALT_LENGTH - master_salt_length = srtp_profile_get_master_salt_length(manager->dtls.crypto_selected == HMAC_SHA1_32 ? srtp_profile_aes128_cm_sha1_32 : srtp_profile_aes128_cm_sha1_80); + master_salt_length = srtp_profile_get_master_salt_length(manager->dtls.crypto_selected == HMAC_SHA1_32 ? srtp_profile_aes128_cm_sha1_32 : srtp_profile_aes128_cm_sha1_80); #else - master_salt_length = (112 >> 3); // cipher_salt_length - rfc5764 4.1.2. SRTP Protection Profiles + master_salt_length = (112 >> 3); // cipher_salt_length - rfc5764 4.1.2. SRTP Protection Profiles #endif - if(((master_key_length + master_salt_length) << 1) > e->size){ - TSK_DEBUG_ERROR("%d not a valid size for this profile", (int)e->size); - } - else{ - int ret; - const uint8_t* data_ptr = e->data; - const uint8_t *lk, *ls, *rk, *rs; - if(manager->dtls.local.setup == tnet_dtls_setup_passive){ - rk = &data_ptr[0]; - lk = rk + master_key_length; - rs = (lk + master_key_length); - ls = (rs + master_salt_length); - } - else{ - lk = &data_ptr[0]; - rk = lk + master_key_length; - ls = (rk + master_key_length); - rs = (ls + master_salt_length); - } - // set key||salt - if((ret = trtp_srtp_set_key_and_salt_remote(manager, manager->dtls.crypto_selected, rk, master_key_length, rs, master_salt_length, is_rtp))){ - if(manager->dtls.cb.fun) manager->dtls.cb.fun(manager->dtls.cb.usrdata, trtp_srtp_dtls_event_type_fatal_error, "Failed to set remote DTSL-SRTP key||salt"); - return ret; - } - if((ret = trtp_srtp_set_key_and_salt_local(manager, manager->dtls.crypto_selected, lk, master_key_length, ls, master_salt_length, is_rtp))){ - if(manager->dtls.cb.fun) manager->dtls.cb.fun(manager->dtls.cb.usrdata, trtp_srtp_dtls_event_type_fatal_error, "Failed to set local DTSL-SRTP key||salt"); - return ret; - } - - if(is_rtp){ - manager->dtls.srtp_connected = manager->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][manager->dtls.crypto_selected].rtp.initialized; - if(_trtp_manager_is_rtcpmux_active(manager)){ - manager->dtls.srtcp_connected = tsk_true; - } - } - else{ // rtcp - manager->dtls.srtcp_connected = manager->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][manager->dtls.crypto_selected].rtcp.initialized; - } - TSK_DEBUG_INFO("dtls.srtp_connected=%d, dtls.srtcp_connected=%d", manager->dtls.srtp_connected, manager->dtls.srtcp_connected); - - if(manager->dtls.srtp_connected && manager->dtls.srtcp_connected){ - // start DTLS-SRTP - if((ret = _trtp_manager_srtp_start(manager, manager->srtp_type))){ - if(manager->dtls.cb.fun) manager->dtls.cb.fun(manager->dtls.cb.usrdata, trtp_srtp_dtls_event_type_fatal_error, "Failed to set start DTSL-SRTP engine"); - return ret; - } - - TSK_DEBUG_INFO("!!DTLS-SRTP started!!"); - - // alter listeners - if(manager->dtls.cb.fun){ - manager->dtls.cb.fun(manager->dtls.cb.usrdata, trtp_srtp_dtls_event_type_started, "DTLS started"); - } - } - } - } - - break; - } - case event_dtls_srtp_profile_selected: - { - if(manager->transport->master && manager->transport->master->fd == e->local_fd){ - /* Only (SRTP_AES128_CM_SHA1_80 | SRTP_AES128_CM_SHA1_32) because of _trtp_manager_srtp_activate() */ - TSK_DEBUG_INFO("event_dtls_srtp_profile_selected: %.*s", 22, (const char*)e->data); - manager->dtls.crypto_selected = HMAC_SHA1_80; - if(tsk_strnequals(e->data, "SRTP_AES128_CM_SHA1_32", 22)){ - manager->dtls.crypto_selected = HMAC_SHA1_32; - } - } - break; - } + if(((master_key_length + master_salt_length) << 1) > e->size) { + TSK_DEBUG_ERROR("%d not a valid size for this profile", (int)e->size); + } + else { + int ret; + const uint8_t* data_ptr = e->data; + const uint8_t *lk, *ls, *rk, *rs; + if(manager->dtls.local.setup == tnet_dtls_setup_passive) { + rk = &data_ptr[0]; + lk = rk + master_key_length; + rs = (lk + master_key_length); + ls = (rs + master_salt_length); + } + else { + lk = &data_ptr[0]; + rk = lk + master_key_length; + ls = (rk + master_key_length); + rs = (ls + master_salt_length); + } + // set key||salt + if((ret = trtp_srtp_set_key_and_salt_remote(manager, manager->dtls.crypto_selected, rk, master_key_length, rs, master_salt_length, is_rtp))) { + if(manager->dtls.cb.fun) { + manager->dtls.cb.fun(manager->dtls.cb.usrdata, trtp_srtp_dtls_event_type_fatal_error, "Failed to set remote DTSL-SRTP key||salt"); + } + return ret; + } + if((ret = trtp_srtp_set_key_and_salt_local(manager, manager->dtls.crypto_selected, lk, master_key_length, ls, master_salt_length, is_rtp))) { + if(manager->dtls.cb.fun) { + manager->dtls.cb.fun(manager->dtls.cb.usrdata, trtp_srtp_dtls_event_type_fatal_error, "Failed to set local DTSL-SRTP key||salt"); + } + return ret; + } + + if(is_rtp) { + manager->dtls.srtp_connected = manager->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][manager->dtls.crypto_selected].rtp.initialized; + if(_trtp_manager_is_rtcpmux_active(manager)) { + manager->dtls.srtcp_connected = tsk_true; + } + } + else { // rtcp + manager->dtls.srtcp_connected = manager->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][manager->dtls.crypto_selected].rtcp.initialized; + } + TSK_DEBUG_INFO("dtls.srtp_connected=%d, dtls.srtcp_connected=%d", manager->dtls.srtp_connected, manager->dtls.srtcp_connected); + + if(manager->dtls.srtp_connected && manager->dtls.srtcp_connected) { + // start DTLS-SRTP + if((ret = _trtp_manager_srtp_start(manager, manager->srtp_type))) { + if(manager->dtls.cb.fun) { + manager->dtls.cb.fun(manager->dtls.cb.usrdata, trtp_srtp_dtls_event_type_fatal_error, "Failed to set start DTSL-SRTP engine"); + } + return ret; + } + + TSK_DEBUG_INFO("!!DTLS-SRTP started!!"); + + // alter listeners + if(manager->dtls.cb.fun) { + manager->dtls.cb.fun(manager->dtls.cb.usrdata, trtp_srtp_dtls_event_type_started, "DTLS started"); + } + } + } + } + + break; + } + case event_dtls_srtp_profile_selected: { + if(manager->transport->master && manager->transport->master->fd == e->local_fd) { + /* Only (SRTP_AES128_CM_SHA1_80 | SRTP_AES128_CM_SHA1_32) because of _trtp_manager_srtp_activate() */ + TSK_DEBUG_INFO("event_dtls_srtp_profile_selected: %.*s", 22, (const char*)e->data); + manager->dtls.crypto_selected = HMAC_SHA1_80; + if(tsk_strnequals(e->data, "SRTP_AES128_CM_SHA1_32", 22)) { + manager->dtls.crypto_selected = HMAC_SHA1_32; + } + } + break; + } #endif /* HAVE_SRTP */ - case event_connected: - case event_closed: - { - - break; - } - default: - break; - } - return 0; + case event_connected: + case event_closed: { + + break; + } + default: + break; + } + return 0; } static int _trtp_transport_dtls_handshaking_timer_cb(const void* arg, tsk_timer_id_t timer_id) { - int ret = 0; + int ret = 0; #if HAVE_SRTP - trtp_manager_t* manager = (trtp_manager_t*)arg; - - tsk_safeobj_lock(manager); - if (manager->is_started && manager->dtls.timer_hanshaking.id == timer_id && manager->srtp_state == trtp_srtp_state_activated && manager->srtp_type == tmedia_srtp_type_dtls) { - // retry DTLS-SRTP handshaking if srtp-type is DTLS-SRTP and the engine is activated - struct tnet_socket_s* sockets[] = { manager->dtls.srtp_connected ? tsk_null : manager->transport->master , manager->dtls.srtcp_connected ? tsk_null : manager->rtcp.local_socket }; - const struct sockaddr_storage* remote_addrs[] = { &manager->rtp.remote_addr, &manager->rtcp.remote_addr }; - TSK_DEBUG_INFO("_trtp_transport_dtls_handshaking_timer_cb(timeout=%llu)", manager->dtls.timer_hanshaking.timeout); - tnet_transport_dtls_do_handshake(manager->transport, sockets, 2, remote_addrs, 2); - if (manager->is_ice_turn_active) { - // means TURN is active and handshaking data must be sent using this channel - const void* data[] = { tsk_null, tsk_null }; - tsk_size_t size[] = { 0, 0 }; - if ((ret = tnet_transport_dtls_get_handshakingdata(manager->transport, (const struct tnet_socket_s**)sockets, 2, data, size))) { - return ret; - } - if (data[0] && size[0]) { - ret = _trtp_manager_send_turn_dtls_rtp(manager->ice_ctx, data[0], size[0]); - } - if (data[1] && size[1]) { - ret = _trtp_manager_send_turn_dtls_rtcp(manager->ice_ctx, data[1], size[1]); - } - } - // increase timeout - manager->dtls.timer_hanshaking.timeout += (TRTP_DTLS_HANDSHAKING_TIMEOUT >> 1); - if ((manager->dtls.timer_hanshaking.timeout < TRTP_DTLS_HANDSHAKING_TIMEOUT_MAX) && !(manager->dtls.srtp_connected && manager->dtls.srtcp_connected)) { - manager->dtls.timer_hanshaking.id = tsk_timer_manager_schedule(manager->timer_mgr_global, manager->dtls.timer_hanshaking.timeout, _trtp_transport_dtls_handshaking_timer_cb, manager); - } - else { - manager->dtls.timer_hanshaking.id = TSK_INVALID_TIMER_ID; // invalidate timer id (not required but should be done by good citizen) - manager->dtls.timer_hanshaking.timeout = TRTP_DTLS_HANDSHAKING_TIMEOUT; // reset timeout - } - } - tsk_safeobj_unlock(manager); + trtp_manager_t* manager = (trtp_manager_t*)arg; + + tsk_safeobj_lock(manager); + if (manager->is_started && manager->dtls.timer_hanshaking.id == timer_id && manager->srtp_state == trtp_srtp_state_activated && manager->srtp_type == tmedia_srtp_type_dtls) { + // retry DTLS-SRTP handshaking if srtp-type is DTLS-SRTP and the engine is activated + struct tnet_socket_s* sockets[] = { manager->dtls.srtp_connected ? tsk_null : manager->transport->master , manager->dtls.srtcp_connected ? tsk_null : manager->rtcp.local_socket }; + const struct sockaddr_storage* remote_addrs[] = { &manager->rtp.remote_addr, &manager->rtcp.remote_addr }; + TSK_DEBUG_INFO("_trtp_transport_dtls_handshaking_timer_cb(timeout=%llu)", manager->dtls.timer_hanshaking.timeout); + tnet_transport_dtls_do_handshake(manager->transport, sockets, 2, remote_addrs, 2); + if (manager->is_ice_turn_active) { + // means TURN is active and handshaking data must be sent using this channel + const void* data[] = { tsk_null, tsk_null }; + tsk_size_t size[] = { 0, 0 }; + if ((ret = tnet_transport_dtls_get_handshakingdata(manager->transport, (const struct tnet_socket_s**)sockets, 2, data, size))) { + return ret; + } + if (data[0] && size[0]) { + ret = _trtp_manager_send_turn_dtls_rtp(manager->ice_ctx, data[0], size[0]); + } + if (data[1] && size[1]) { + ret = _trtp_manager_send_turn_dtls_rtcp(manager->ice_ctx, data[1], size[1]); + } + } + // increase timeout + manager->dtls.timer_hanshaking.timeout += (TRTP_DTLS_HANDSHAKING_TIMEOUT >> 1); + if ((manager->dtls.timer_hanshaking.timeout < TRTP_DTLS_HANDSHAKING_TIMEOUT_MAX) && !(manager->dtls.srtp_connected && manager->dtls.srtcp_connected)) { + manager->dtls.timer_hanshaking.id = tsk_timer_manager_schedule(manager->timer_mgr_global, manager->dtls.timer_hanshaking.timeout, _trtp_transport_dtls_handshaking_timer_cb, manager); + } + else { + manager->dtls.timer_hanshaking.id = TSK_INVALID_TIMER_ID; // invalidate timer id (not required but should be done by good citizen) + manager->dtls.timer_hanshaking.timeout = TRTP_DTLS_HANDSHAKING_TIMEOUT; // reset timeout + } + } + tsk_safeobj_unlock(manager); #endif - - return ret; + + return ret; } #if 0 static int _trtp_manager_enable_sockets(trtp_manager_t* self) { - int rcv_buf = tmedia_defaults_get_rtpbuff_size(); - int snd_buf = tmedia_defaults_get_rtpbuff_size(); - int ret; - - if(!self->socket_disabled){ - return 0; - } - - if(!self || !self->transport){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if((ret = setsockopt(self->transport->master->fd, SOL_SOCKET, SO_RCVBUF, (char*)&rcv_buf, sizeof(rcv_buf)))){ - TNET_PRINT_LAST_ERROR("setsockopt(SOL_SOCKET, SO_RCVBUF) has failed with error code %d", ret); - return ret; - } - if((ret = setsockopt(self->transport->master->fd, SOL_SOCKET, SO_SNDBUF, (char*)&snd_buf, sizeof(snd_buf)))){ - TNET_PRINT_LAST_ERROR("setsockopt(SOL_SOCKET, SO_RCVBUF) has failed with error code %d", ret); - return ret; - } - - self->socket_disabled = tsk_false; - return 0; + int rcv_buf = tmedia_defaults_get_rtpbuff_size(); + int snd_buf = tmedia_defaults_get_rtpbuff_size(); + int ret; + + if(!self->socket_disabled) { + return 0; + } + + if(!self || !self->transport) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if((ret = setsockopt(self->transport->master->fd, SOL_SOCKET, SO_RCVBUF, (char*)&rcv_buf, sizeof(rcv_buf)))) { + TNET_PRINT_LAST_ERROR("setsockopt(SOL_SOCKET, SO_RCVBUF) has failed with error code %d", ret); + return ret; + } + if((ret = setsockopt(self->transport->master->fd, SOL_SOCKET, SO_SNDBUF, (char*)&snd_buf, sizeof(snd_buf)))) { + TNET_PRINT_LAST_ERROR("setsockopt(SOL_SOCKET, SO_RCVBUF) has failed with error code %d", ret); + return ret; + } + + self->socket_disabled = tsk_false; + return 0; } #endif static trtp_manager_t* _trtp_manager_create(tsk_bool_t use_rtcp, const char* local_ip, tsk_bool_t ipv6, tmedia_srtp_type_t srtp_type, tmedia_srtp_mode_t srtp_mode) { - trtp_manager_t* manager; + trtp_manager_t* manager; #if HAVE_SRTP - static tsk_bool_t __strp_initialized = tsk_false; - err_status_t srtp_err; - if(!__strp_initialized){ - if((srtp_err = srtp_init()) != err_status_ok){ - TSK_DEBUG_ERROR("srtp_init() failed with error code = %d", srtp_err); - } - __strp_initialized = (srtp_err == err_status_ok); - } + static tsk_bool_t __strp_initialized = tsk_false; + err_status_t srtp_err; + if(!__strp_initialized) { + if((srtp_err = srtp_init()) != err_status_ok) { + TSK_DEBUG_ERROR("srtp_init() failed with error code = %d", srtp_err); + } + __strp_initialized = (srtp_err == err_status_ok); + } #endif - if((manager = tsk_object_new(trtp_manager_def_t))){ - manager->use_rtcp = use_rtcp; - manager->local_ip = tsk_strdup(local_ip); - manager->use_ipv6 = ipv6; + if((manager = tsk_object_new(trtp_manager_def_t))) { + manager->use_rtcp = use_rtcp; + manager->local_ip = tsk_strdup(local_ip); + manager->use_ipv6 = ipv6; #if HAVE_SRTP - manager->srtp_type = srtp_type; - manager->srtp_mode = srtp_mode; + manager->srtp_type = srtp_type; + manager->srtp_mode = srtp_mode; #endif - manager->rtp.payload_type = 127; - } - return manager; + manager->rtp.payload_type = 127; + } + return manager; } static int _trtp_manager_recv_data(const trtp_manager_t* self, const uint8_t* data_ptr, tsk_size_t data_size, tnet_fd_t local_fd, const struct sockaddr_storage* remote_addr) { - tsk_bool_t is_rtp_rtcp, is_rtcp = tsk_false, is_rtp = tsk_false, is_stun, is_dtls; - - if (!self->is_started) { - TSK_DEBUG_INFO("RTP manager not started yet"); - return 0; - } - - // defined when RTCP-MUX is disabled and RTCP port is equal to "RTP Port + 1" - - // rfc5764 - 5.1.2. Reception - // rfc5761 - 4. Distinguishable RTP and RTCP Packets - - is_rtp_rtcp = (127 < *data_ptr && *data_ptr < 192); - if(is_rtp_rtcp){ - is_stun = is_dtls = tsk_false; - is_rtcp = (self->rtcp.local_socket && self->rtcp.local_socket->fd == local_fd); - if(!is_rtcp && data_size >= 2 && (data_ptr[1] & 0x80)){ - if(is_rtp_rtcp){ - switch((data_ptr[1] & 0x7F)){ - case 64: case 65: - case 72: case 73: case 74: case 75: case 76: - case 77: case 78: - case 79: is_rtcp = tsk_true; break; - } - } - } - is_rtp = !is_rtcp; - } - else{ - is_dtls = !is_rtp_rtcp && (19 < *data_ptr && *data_ptr < 64); - is_stun = !is_dtls && TNET_STUN_BUFF_IS_STUN2(data_ptr, data_size); /* MUST NOT USE: "(*data_ptr < 2)" beacause of "Old VAT" which starts with "0x00" */; - } - - if(is_dtls){ - tnet_socket_t* socket = (self->transport && self->transport->master && self->transport->master->fd == local_fd) - ? self->transport->master - : ((self->rtcp.local_socket && self->rtcp.local_socket->fd == local_fd) ? self->rtcp.local_socket : tsk_null); - if (socket && socket->dtlshandle) { - TSK_DEBUG_INFO("Receive %s-DTLS data on ip=%s and port=%d", (socket == self->transport->master) ? "RTP" : "RTCP", socket->ip, socket->port); - // Handle incoming data then do handshaking - tnet_dtls_socket_handle_incoming_data(socket->dtlshandle, data_ptr, data_size); - if (self->is_ice_turn_active) { - // means TURN is active and handshaking data must be sent using the channel - const void* data = tsk_null; - tsk_size_t size = 0; - if (tnet_transport_dtls_get_handshakingdata(self->transport, (const struct tnet_socket_s**)&socket, 1, &data, &size) == 0) { - if (data && size > 0){ - if (self->rtcp.local_socket == socket) { - /*ret = */_trtp_manager_send_turn_dtls_rtcp(self->ice_ctx, data, size); - } - else { - /*ret = */_trtp_manager_send_turn_dtls_rtp(self->ice_ctx, data, size); - } - } - } - } - } - return 0; - } - - if(is_stun){ - static tsk_bool_t role_conflict = tsk_false; - if(self->ice_ctx){ - return tnet_ice_ctx_recv_stun_message(self->ice_ctx, data_ptr, data_size, local_fd, remote_addr, &role_conflict); - } - return 0; - } - if(is_rtcp){ - if(!self->is_symetric_rtcp_checked && self->is_force_symetric_rtp){ - ((trtp_manager_t*)self)->is_symetric_rtcp_checked = tsk_true; - if(!self->is_ice_neg_ok && remote_addr){ // do not force symetric RTCP is ICE negotiation succeed - TSK_DEBUG_INFO("Using symetric RTCP for [%s]:%d", self->rtcp.remote_ip, self->rtcp.remote_port); - ((trtp_manager_t*)self)->rtcp.remote_addr = *remote_addr; - } - } - - if(self->rtcp.session){ - #if HAVE_SRTP - err_status_t status; - if(self->srtp_ctx_neg_remote){ - srtp_t session = self->srtp_ctx_neg_remote->rtcp.initialized ? self->srtp_ctx_neg_remote->rtcp.session : self->srtp_ctx_neg_remote->rtp.session; - if((status = srtp_unprotect_rtcp(session, (void*)data_ptr, (int*)&data_size)) != err_status_ok){ + tsk_bool_t is_rtp_rtcp, is_rtcp = tsk_false, is_rtp = tsk_false, is_stun, is_dtls; + + if (!self->is_started) { + TSK_DEBUG_INFO("RTP manager not started yet"); + return 0; + } + + // defined when RTCP-MUX is disabled and RTCP port is equal to "RTP Port + 1" + + // rfc5764 - 5.1.2. Reception + // rfc5761 - 4. Distinguishable RTP and RTCP Packets + + is_rtp_rtcp = (127 < *data_ptr && *data_ptr < 192); + if(is_rtp_rtcp) { + is_stun = is_dtls = tsk_false; + is_rtcp = (self->rtcp.local_socket && self->rtcp.local_socket->fd == local_fd); + if(!is_rtcp && data_size >= 2 && (data_ptr[1] & 0x80)) { + if(is_rtp_rtcp) { + switch((data_ptr[1] & 0x7F)) { + case 64: + case 65: + case 72: + case 73: + case 74: + case 75: + case 76: + case 77: + case 78: + case 79: + is_rtcp = tsk_true; + break; + } + } + } + is_rtp = !is_rtcp; + } + else { + is_dtls = !is_rtp_rtcp && (19 < *data_ptr && *data_ptr < 64); + is_stun = !is_dtls && TNET_STUN_BUFF_IS_STUN2(data_ptr, data_size); /* MUST NOT USE: "(*data_ptr < 2)" beacause of "Old VAT" which starts with "0x00" */; + } + + if(is_dtls) { + tnet_socket_t* socket = (self->transport && self->transport->master && self->transport->master->fd == local_fd) + ? self->transport->master + : ((self->rtcp.local_socket && self->rtcp.local_socket->fd == local_fd) ? self->rtcp.local_socket : tsk_null); + if (socket && socket->dtlshandle) { + TSK_DEBUG_INFO("Receive %s-DTLS data on ip=%s and port=%d", (socket == self->transport->master) ? "RTP" : "RTCP", socket->ip, socket->port); + // Handle incoming data then do handshaking + tnet_dtls_socket_handle_incoming_data(socket->dtlshandle, data_ptr, data_size); + if (self->is_ice_turn_active) { + // means TURN is active and handshaking data must be sent using the channel + const void* data = tsk_null; + tsk_size_t size = 0; + if (tnet_transport_dtls_get_handshakingdata(self->transport, (const struct tnet_socket_s**)&socket, 1, &data, &size) == 0) { + if (data && size > 0) { + if (self->rtcp.local_socket == socket) { + /*ret = */_trtp_manager_send_turn_dtls_rtcp(self->ice_ctx, data, size); + } + else { + /*ret = */_trtp_manager_send_turn_dtls_rtp(self->ice_ctx, data, size); + } + } + } + } + } + return 0; + } + + if(is_stun) { + static tsk_bool_t role_conflict = tsk_false; + if(self->ice_ctx) { + return tnet_ice_ctx_recv_stun_message(self->ice_ctx, data_ptr, data_size, local_fd, remote_addr, &role_conflict); + } + return 0; + } + if(is_rtcp) { + if(!self->is_symetric_rtcp_checked && self->is_force_symetric_rtp) { + ((trtp_manager_t*)self)->is_symetric_rtcp_checked = tsk_true; + if(!self->is_ice_neg_ok && remote_addr) { // do not force symetric RTCP is ICE negotiation succeed + TSK_DEBUG_INFO("Using symetric RTCP for [%s]:%d", self->rtcp.remote_ip, self->rtcp.remote_port); + ((trtp_manager_t*)self)->rtcp.remote_addr = *remote_addr; + } + } + + if(self->rtcp.session) { +#if HAVE_SRTP + err_status_t status; + if(self->srtp_ctx_neg_remote) { + srtp_t session = self->srtp_ctx_neg_remote->rtcp.initialized ? self->srtp_ctx_neg_remote->rtcp.session : self->srtp_ctx_neg_remote->rtp.session; + if((status = srtp_unprotect_rtcp(session, (void*)data_ptr, (int*)&data_size)) != err_status_ok) { if (status == err_status_replay_fail) { // replay (because of RTCP-NACK nothing to worry about) TSK_DEBUG_INFO("srtp_unprotect(RTCP) returned 'err_status_replay_fail'"); @@ -470,29 +477,29 @@ static int _trtp_manager_recv_data(const trtp_manager_t* self, const uint8_t* da TSK_DEBUG_ERROR("srtp_unprotect(RTCP) failed with error code=%d", (int)status); return -1; } - } - } - #endif - return trtp_rtcp_session_process_rtcp_in(self->rtcp.session, data_ptr, data_size); - } - TSK_DEBUG_WARN("No RTCP session"); - return 0; - } - if(is_rtp){ - if(!self->is_symetric_rtp_checked && self->is_force_symetric_rtp){ - ((trtp_manager_t*)self)->is_symetric_rtp_checked = tsk_true; - if(!self->is_ice_neg_ok && remote_addr){ // do not force symetric RTP is ICE negotiation succeed - TSK_DEBUG_INFO("Using symetric RTP for [%s]:%d", self->rtp.remote_ip, self->rtp.remote_port); - ((trtp_manager_t*)self)->rtp.remote_addr = *remote_addr; - } - } - - if(self->rtp.cb.fun){ - trtp_rtp_packet_t* packet_rtp = tsk_null; - #if HAVE_SRTP - err_status_t status; - if(self->srtp_ctx_neg_remote){ - if((status = srtp_unprotect(self->srtp_ctx_neg_remote->rtp.session, (void*)data_ptr, (int*)&data_size)) != err_status_ok){ + } + } +#endif + return trtp_rtcp_session_process_rtcp_in(self->rtcp.session, data_ptr, data_size); + } + TSK_DEBUG_WARN("No RTCP session"); + return 0; + } + if(is_rtp) { + if(!self->is_symetric_rtp_checked && self->is_force_symetric_rtp) { + ((trtp_manager_t*)self)->is_symetric_rtp_checked = tsk_true; + if(!self->is_ice_neg_ok && remote_addr) { // do not force symetric RTP is ICE negotiation succeed + TSK_DEBUG_INFO("Using symetric RTP for [%s]:%d", self->rtp.remote_ip, self->rtp.remote_port); + ((trtp_manager_t*)self)->rtp.remote_addr = *remote_addr; + } + } + + if(self->rtp.cb.fun) { + trtp_rtp_packet_t* packet_rtp = tsk_null; +#if HAVE_SRTP + err_status_t status; + if(self->srtp_ctx_neg_remote) { + if((status = srtp_unprotect(self->srtp_ctx_neg_remote->rtp.session, (void*)data_ptr, (int*)&data_size)) != err_status_ok) { if (status == err_status_replay_fail) { // replay (because of RTCP-NACK nothing to worry about) TSK_DEBUG_INFO("srtp_unprotect(RTP) returned 'err_status_replay_fail'"); @@ -502,52 +509,52 @@ static int _trtp_manager_recv_data(const trtp_manager_t* self, const uint8_t* da TSK_DEBUG_ERROR("srtp_unprotect(RTP) failed with error code=%d, seq_num=%u", (int)status, (data_size > 4 ? tnet_ntohs_2(&data_ptr[2]) : 0x0000)); return -1; } - } - } - #endif - if((packet_rtp = trtp_rtp_packet_deserialize(data_ptr, data_size))){ - // update remote SSRC based on received RTP packet - ((trtp_manager_t*)self)->rtp.ssrc.remote = packet_rtp->header->ssrc; - // forward to the callback function (most likely "session_av") - self->rtp.cb.fun(self->rtp.cb.usrdata, packet_rtp); - // forward packet to the RTCP session - if(self->rtcp.session){ - trtp_rtcp_session_process_rtp_in(self->rtcp.session, packet_rtp, data_size); - } - TSK_OBJECT_SAFE_FREE(packet_rtp); - return 0; - } - else{ - TSK_DEBUG_ERROR("RTP packet === NOK"); - return -1; - } - } - return 0; - } - - TSK_DEBUG_INFO("Received unknown packet type"); - return 0; + } + } +#endif + if((packet_rtp = trtp_rtp_packet_deserialize(data_ptr, data_size))) { + // update remote SSRC based on received RTP packet + ((trtp_manager_t*)self)->rtp.ssrc.remote = packet_rtp->header->ssrc; + // forward to the callback function (most likely "session_av") + self->rtp.cb.fun(self->rtp.cb.usrdata, packet_rtp); + // forward packet to the RTCP session + if(self->rtcp.session) { + trtp_rtcp_session_process_rtp_in(self->rtcp.session, packet_rtp, data_size); + } + TSK_OBJECT_SAFE_FREE(packet_rtp); + return 0; + } + else { + TSK_DEBUG_ERROR("RTP packet === NOK"); + return -1; + } + } + return 0; + } + + TSK_DEBUG_INFO("Received unknown packet type"); + return 0; } // Sends DTLS handshaking data record by record to avoid UDP IP fragmentation issues (each record length will be < Length(MTU)) //!\ This is required even if the local transport is TCP/TLS because the relayed (TURN) transport could be UDP static int _trtp_manager_send_turn_dtls(struct tnet_ice_ctx_s* ice_ctx, const void* handshaking_data_ptr, tsk_size_t handshaking_data_size, tsk_bool_t use_rtcp_channel) { - const uint8_t *record_ptr, *records_ptr = handshaking_data_ptr; - tsk_size_t record_size; - int records_len = (int)handshaking_data_size, ret = 0; - int(*_ice_ctx_send_turn_data)(struct tnet_ice_ctx_s* self, const void* data, tsk_size_t size) = use_rtcp_channel ? tnet_ice_ctx_send_turn_rtcp : tnet_ice_ctx_send_turn_rtp; - if (!ice_ctx || !handshaking_data_ptr || !handshaking_data_size) { - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - while (records_len > 0 && (ret = tnet_dtls_socket_get_record_first(records_ptr, (tsk_size_t)records_len, &record_ptr, &record_size)) == 0) { - ret = _ice_ctx_send_turn_data(ice_ctx, record_ptr, record_size); - - records_len -= (int)record_size; - records_ptr += record_size; - } - return ret; + const uint8_t *record_ptr, *records_ptr = handshaking_data_ptr; + tsk_size_t record_size; + int records_len = (int)handshaking_data_size, ret = 0; + int(*_ice_ctx_send_turn_data)(struct tnet_ice_ctx_s* self, const void* data, tsk_size_t size) = use_rtcp_channel ? tnet_ice_ctx_send_turn_rtcp : tnet_ice_ctx_send_turn_rtp; + if (!ice_ctx || !handshaking_data_ptr || !handshaking_data_size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + while (records_len > 0 && (ret = tnet_dtls_socket_get_record_first(records_ptr, (tsk_size_t)records_len, &record_ptr, &record_size)) == 0) { + ret = _ice_ctx_send_turn_data(ice_ctx, record_ptr, record_size); + + records_len -= (int)record_size; + records_ptr += record_size; + } + return ret; } #if HAVE_SRTP @@ -559,634 +566,634 @@ If ICE is enabled DTLS-SRTP will not be enabled as the transport is "null" */ static int _trtp_manager_srtp_set_enabled(trtp_manager_t* self, tmedia_srtp_type_t srtp_type, struct tnet_socket_s** sockets, tsk_size_t count, tsk_bool_t enabled) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if((self->srtp_mode == tmedia_srtp_mode_optional || self->srtp_mode == tmedia_srtp_mode_mandatory)){ - int ret; - if(enabled){ - if(srtp_type & tmedia_srtp_type_sdes){ - trtp_srtp_ctx_init( - &self->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80], - 1, - HMAC_SHA1_80, - self->rtp.ssrc.local - ); - trtp_srtp_ctx_init( - &self->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32], - 2, - HMAC_SHA1_32, - self->rtp.ssrc.local - ); - } - - if(srtp_type & tmedia_srtp_type_dtls){ - /* - Enables DTLS on the transport without activating it on the sockets - Enabling DTLS will allow us to get the certificate fingerprints for negotiation - At this stage the sockets are not ready to send DTLS datagrams -> Good for ICE negotiation - */ - if(self->transport){ - if((ret = tnet_transport_dtls_set_enabled(self->transport, enabled, tsk_null, 0))){ - return ret; - } - if((ret = trtp_manager_set_dtls_certs(self, self->dtls.file_ca, self->dtls.file_pbk, self->dtls.file_pvk, self->dtls.cert_verif))){ - return ret; - } - self->dtls.state = trtp_srtp_state_enabled; - } - else{ - self->dtls.enable_postponed = tsk_true; - } - } - self->srtp_state = trtp_srtp_state_enabled; - } - else { - if (srtp_type & tmedia_srtp_type_dtls) { - if (self->transport) { - ret = tnet_transport_dtls_set_enabled(self->transport, tsk_false, sockets, count); - } - self->dtls.state = trtp_srtp_state_none; - self->dtls.enable_postponed = tsk_false; - self->dtls.srtp_connected = self->dtls.srtp_handshake_succeed = tsk_false; - self->dtls.srtcp_connected = self->dtls.srtcp_handshake_succeed = tsk_false; - } - - // SRTP context is used by both DTLS and SDES -> only destroy them if requested to be disabled on both - if((~srtp_type & self->srtp_type) == tmedia_srtp_type_none){ - trtp_srtp_ctx_deinit(&self->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][0]); - trtp_srtp_ctx_deinit(&self->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][1]); - self->srtp_ctx_neg_local = tsk_null; - self->srtp_ctx_neg_remote = tsk_null; - self->srtp_state = trtp_srtp_state_none; - // Reset SRTP session to the RTCP session manager - if (self->rtcp.session) { - trtp_rtcp_session_set_srtp_sess(self->rtcp.session, tsk_null); - } - } - } - } - - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if((self->srtp_mode == tmedia_srtp_mode_optional || self->srtp_mode == tmedia_srtp_mode_mandatory)) { + int ret; + if(enabled) { + if(srtp_type & tmedia_srtp_type_sdes) { + trtp_srtp_ctx_init( + &self->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80], + 1, + HMAC_SHA1_80, + self->rtp.ssrc.local + ); + trtp_srtp_ctx_init( + &self->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32], + 2, + HMAC_SHA1_32, + self->rtp.ssrc.local + ); + } + + if(srtp_type & tmedia_srtp_type_dtls) { + /* + Enables DTLS on the transport without activating it on the sockets + Enabling DTLS will allow us to get the certificate fingerprints for negotiation + At this stage the sockets are not ready to send DTLS datagrams -> Good for ICE negotiation + */ + if(self->transport) { + if((ret = tnet_transport_dtls_set_enabled(self->transport, enabled, tsk_null, 0))) { + return ret; + } + if((ret = trtp_manager_set_dtls_certs(self, self->dtls.file_ca, self->dtls.file_pbk, self->dtls.file_pvk, self->dtls.cert_verif))) { + return ret; + } + self->dtls.state = trtp_srtp_state_enabled; + } + else { + self->dtls.enable_postponed = tsk_true; + } + } + self->srtp_state = trtp_srtp_state_enabled; + } + else { + if (srtp_type & tmedia_srtp_type_dtls) { + if (self->transport) { + ret = tnet_transport_dtls_set_enabled(self->transport, tsk_false, sockets, count); + } + self->dtls.state = trtp_srtp_state_none; + self->dtls.enable_postponed = tsk_false; + self->dtls.srtp_connected = self->dtls.srtp_handshake_succeed = tsk_false; + self->dtls.srtcp_connected = self->dtls.srtcp_handshake_succeed = tsk_false; + } + + // SRTP context is used by both DTLS and SDES -> only destroy them if requested to be disabled on both + if((~srtp_type & self->srtp_type) == tmedia_srtp_type_none) { + trtp_srtp_ctx_deinit(&self->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][0]); + trtp_srtp_ctx_deinit(&self->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][1]); + self->srtp_ctx_neg_local = tsk_null; + self->srtp_ctx_neg_remote = tsk_null; + self->srtp_state = trtp_srtp_state_none; + // Reset SRTP session to the RTCP session manager + if (self->rtcp.session) { + trtp_rtcp_session_set_srtp_sess(self->rtcp.session, tsk_null); + } + } + } + } + + return 0; } static int _trtp_manager_srtp_activate(trtp_manager_t* self, tmedia_srtp_type_t srtp_type) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(srtp_type != tmedia_srtp_type_none && (self->srtp_mode == tmedia_srtp_mode_optional || self->srtp_mode == tmedia_srtp_mode_mandatory)){ - int ret; - if(self->srtp_state < trtp_srtp_state_enabled){ - TSK_DEBUG_ERROR("SRTP engine not enabled yet"); - return -2; - } - if((srtp_type & tmedia_srtp_type_dtls) && (self->dtls.state >= trtp_srtp_state_enabled || self->dtls.enable_postponed)){ - /* - Activates DTLS on the transport and on both RTP and RTCP sockets - At this stage the sockets are ready to send/recv DTLS datagrams - */ - struct tnet_socket_s* sockets[] = { self->transport->master , self->rtcp.local_socket }; - const struct sockaddr_storage* remote_addrs[] = { &self->rtp.remote_addr, &self->rtcp.remote_addr }; - tsk_bool_t store_handshakingdata[] = { self->is_ice_turn_active, self->is_ice_turn_active }; - - // check if DTLS-SRTP enabling was postponed because the net transport was not ready (could happen if ICE is ON) - if(self->dtls.enable_postponed){ - if ((ret = _trtp_manager_srtp_set_enabled(self, self->srtp_type, sockets, sizeof(sockets) / sizeof(sockets[0]), tsk_true))) { - return ret; - } - self->dtls.enable_postponed = tsk_false; - } - - // activate "use_srtp" (rfc5764 section 4.1) on the transport - // this should be done before enabling DTLS sockets to be sure that newly created/enabled ones will use "use_srtp" extension - if((ret = tnet_transport_dtls_use_srtp(self->transport, "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32", sockets, 2))){ - return ret; - } - // enabling DTLS on the sockets will create the "dtlshandle" field and change the type from UDP to DTLS - if((ret = tnet_transport_dtls_set_enabled(self->transport, tsk_true, sockets, 2))){ - return ret; - } - - /* At this step the DTLS "dtlshandle" is created and the socket types changed from UDP to DTLS */ - - // pass the remote certificate fingerprint to both SRTP and SRTCP sockets - // the fingerprint will be verified if this option is enabled on the SSL context - // we'll be notified via the callback if there are fingerprint mismatch after the begining of the handshaking - if((ret = tnet_transport_dtls_set_remote_fingerprint(self->transport, &self->dtls.remote.fp, self->dtls.remote.fp_hash, sockets, 2))){ - return ret; - } - // setting the "setup" allow each DTLS socket to know if it's a client or server - // setup="active" means it's up to us to send the "DTLS client hello" message (otherwise "server hello" will be sent) - if((ret = tnet_transport_dtls_set_setup(self->transport, self->dtls.local.setup, sockets, 2))){ - return ret; - } - // whether to send DTLS handshaking data using the provided sockets or TURN session - if ((ret = tnet_transport_dtls_set_store_handshakingdata(self->transport, store_handshakingdata[0], sockets, 2))) { - return ret; - } - // start handshaking process (will do nothing if already completed) - if ((ret = tnet_transport_dtls_do_handshake(self->transport, sockets, 2, remote_addrs, 2))) { - return ret; - } - if (store_handshakingdata[0]) { - // means TURN is active and handshaking data must be sent using the channel - const void* data[] = { tsk_null, tsk_null }; - tsk_size_t size[] = { 0, 0 }; - if ((ret = tnet_transport_dtls_get_handshakingdata(self->transport, (const struct tnet_socket_s**)sockets, 2, data, size))) { - return ret; - } - if (data[0] && size[0]) { - ret = tnet_ice_ctx_send_turn_rtp(self->ice_ctx, data[0], size[0]); - } - if (data[1] && size[1]) { - ret = tnet_ice_ctx_send_turn_rtcp(self->ice_ctx, data[1], size[1]); - } - } - - self->dtls.state = trtp_srtp_state_activated; - } - - self->srtp_state = trtp_srtp_state_activated; - - // SDES-SRTP could be started right now while DTLS requires the handshaking to terminate - if (srtp_type & tmedia_srtp_type_sdes) { - return _trtp_manager_srtp_start(self, self->srtp_type); - } - } - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(srtp_type != tmedia_srtp_type_none && (self->srtp_mode == tmedia_srtp_mode_optional || self->srtp_mode == tmedia_srtp_mode_mandatory)) { + int ret; + if(self->srtp_state < trtp_srtp_state_enabled) { + TSK_DEBUG_ERROR("SRTP engine not enabled yet"); + return -2; + } + if((srtp_type & tmedia_srtp_type_dtls) && (self->dtls.state >= trtp_srtp_state_enabled || self->dtls.enable_postponed)) { + /* + Activates DTLS on the transport and on both RTP and RTCP sockets + At this stage the sockets are ready to send/recv DTLS datagrams + */ + struct tnet_socket_s* sockets[] = { self->transport->master , self->rtcp.local_socket }; + const struct sockaddr_storage* remote_addrs[] = { &self->rtp.remote_addr, &self->rtcp.remote_addr }; + tsk_bool_t store_handshakingdata[] = { self->is_ice_turn_active, self->is_ice_turn_active }; + + // check if DTLS-SRTP enabling was postponed because the net transport was not ready (could happen if ICE is ON) + if(self->dtls.enable_postponed) { + if ((ret = _trtp_manager_srtp_set_enabled(self, self->srtp_type, sockets, sizeof(sockets) / sizeof(sockets[0]), tsk_true))) { + return ret; + } + self->dtls.enable_postponed = tsk_false; + } + + // activate "use_srtp" (rfc5764 section 4.1) on the transport + // this should be done before enabling DTLS sockets to be sure that newly created/enabled ones will use "use_srtp" extension + if((ret = tnet_transport_dtls_use_srtp(self->transport, "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32", sockets, 2))) { + return ret; + } + // enabling DTLS on the sockets will create the "dtlshandle" field and change the type from UDP to DTLS + if((ret = tnet_transport_dtls_set_enabled(self->transport, tsk_true, sockets, 2))) { + return ret; + } + + /* At this step the DTLS "dtlshandle" is created and the socket types changed from UDP to DTLS */ + + // pass the remote certificate fingerprint to both SRTP and SRTCP sockets + // the fingerprint will be verified if this option is enabled on the SSL context + // we'll be notified via the callback if there are fingerprint mismatch after the begining of the handshaking + if((ret = tnet_transport_dtls_set_remote_fingerprint(self->transport, &self->dtls.remote.fp, self->dtls.remote.fp_hash, sockets, 2))) { + return ret; + } + // setting the "setup" allow each DTLS socket to know if it's a client or server + // setup="active" means it's up to us to send the "DTLS client hello" message (otherwise "server hello" will be sent) + if((ret = tnet_transport_dtls_set_setup(self->transport, self->dtls.local.setup, sockets, 2))) { + return ret; + } + // whether to send DTLS handshaking data using the provided sockets or TURN session + if ((ret = tnet_transport_dtls_set_store_handshakingdata(self->transport, store_handshakingdata[0], sockets, 2))) { + return ret; + } + // start handshaking process (will do nothing if already completed) + if ((ret = tnet_transport_dtls_do_handshake(self->transport, sockets, 2, remote_addrs, 2))) { + return ret; + } + if (store_handshakingdata[0]) { + // means TURN is active and handshaking data must be sent using the channel + const void* data[] = { tsk_null, tsk_null }; + tsk_size_t size[] = { 0, 0 }; + if ((ret = tnet_transport_dtls_get_handshakingdata(self->transport, (const struct tnet_socket_s**)sockets, 2, data, size))) { + return ret; + } + if (data[0] && size[0]) { + ret = tnet_ice_ctx_send_turn_rtp(self->ice_ctx, data[0], size[0]); + } + if (data[1] && size[1]) { + ret = tnet_ice_ctx_send_turn_rtcp(self->ice_ctx, data[1], size[1]); + } + } + + self->dtls.state = trtp_srtp_state_activated; + } + + self->srtp_state = trtp_srtp_state_activated; + + // SDES-SRTP could be started right now while DTLS requires the handshaking to terminate + if (srtp_type & tmedia_srtp_type_sdes) { + return _trtp_manager_srtp_start(self, self->srtp_type); + } + } + return 0; } static int _trtp_manager_srtp_start(trtp_manager_t* self, tmedia_srtp_type_t srtp_type) { - const trtp_srtp_ctx_xt *ctx_remote, *ctx_local; - tsk_bool_t use_different_keys; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(self->srtp_state < trtp_srtp_state_activated){ - TSK_DEBUG_ERROR("SRTP engine not activated yet"); - return -2; - } - - ctx_remote = self->srtp_contexts[TRTP_SRTP_LINE_IDX_REMOTE][HMAC_SHA1_80].rtp.initialized - ? &self->srtp_contexts[TRTP_SRTP_LINE_IDX_REMOTE][HMAC_SHA1_80] - : &self->srtp_contexts[TRTP_SRTP_LINE_IDX_REMOTE][HMAC_SHA1_32]; - - // dtls uses different keys for rtp and srtp which is not the case for sdes - use_different_keys = !_trtp_manager_is_rtcpmux_active(self) && ((srtp_type & tmedia_srtp_type_dtls) == tmedia_srtp_type_dtls); - TSK_DEBUG_INFO("srtp_use_different_keys=%s", use_different_keys ? "true" : "false"); - - if(!ctx_remote->rtp.initialized || (use_different_keys && !ctx_remote->rtcp.initialized)){ - TSK_DEBUG_ERROR("SRTP remote context not initialized: Not expected at this state"); - return -2; - } - - // use same crypto type on both sides - ctx_local = &self->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][(int32_t)ctx_remote->rtp.crypto_type]; - if(!ctx_local->rtp.initialized || (use_different_keys && !ctx_local->rtcp.initialized)){ - TSK_DEBUG_ERROR("SRTP local context not initialized: Not expected at this state"); - return -2; - } - - // update negotiated crypto contexts used to encrypt()/decrypt() SRTP data - self->srtp_ctx_neg_remote = ctx_remote; - self->srtp_ctx_neg_local = ctx_local; - - self->srtp_state = trtp_srtp_state_started; - if(self->dtls.state >= trtp_srtp_state_activated){ - // this means the DTLS-SRTP is the active type intead of SDES - self->dtls.state = trtp_srtp_state_started; - } - - // Pass SRTP session to the RTCP session manager - trtp_rtcp_session_set_srtp_sess( - self->rtcp.session, - self->srtp_ctx_neg_local ? (use_different_keys ? &self->srtp_ctx_neg_local->rtcp.session : &self->srtp_ctx_neg_local->rtp.session) : tsk_null - ); - - /* At this step we are able to encrypt()/decrypt() SRTP data */ - - return 0; + const trtp_srtp_ctx_xt *ctx_remote, *ctx_local; + tsk_bool_t use_different_keys; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(self->srtp_state < trtp_srtp_state_activated) { + TSK_DEBUG_ERROR("SRTP engine not activated yet"); + return -2; + } + + ctx_remote = self->srtp_contexts[TRTP_SRTP_LINE_IDX_REMOTE][HMAC_SHA1_80].rtp.initialized + ? &self->srtp_contexts[TRTP_SRTP_LINE_IDX_REMOTE][HMAC_SHA1_80] + : &self->srtp_contexts[TRTP_SRTP_LINE_IDX_REMOTE][HMAC_SHA1_32]; + + // dtls uses different keys for rtp and srtp which is not the case for sdes + use_different_keys = !_trtp_manager_is_rtcpmux_active(self) && ((srtp_type & tmedia_srtp_type_dtls) == tmedia_srtp_type_dtls); + TSK_DEBUG_INFO("srtp_use_different_keys=%s", use_different_keys ? "true" : "false"); + + if(!ctx_remote->rtp.initialized || (use_different_keys && !ctx_remote->rtcp.initialized)) { + TSK_DEBUG_ERROR("SRTP remote context not initialized: Not expected at this state"); + return -2; + } + + // use same crypto type on both sides + ctx_local = &self->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][(int32_t)ctx_remote->rtp.crypto_type]; + if(!ctx_local->rtp.initialized || (use_different_keys && !ctx_local->rtcp.initialized)) { + TSK_DEBUG_ERROR("SRTP local context not initialized: Not expected at this state"); + return -2; + } + + // update negotiated crypto contexts used to encrypt()/decrypt() SRTP data + self->srtp_ctx_neg_remote = ctx_remote; + self->srtp_ctx_neg_local = ctx_local; + + self->srtp_state = trtp_srtp_state_started; + if(self->dtls.state >= trtp_srtp_state_activated) { + // this means the DTLS-SRTP is the active type intead of SDES + self->dtls.state = trtp_srtp_state_started; + } + + // Pass SRTP session to the RTCP session manager + trtp_rtcp_session_set_srtp_sess( + self->rtcp.session, + self->srtp_ctx_neg_local ? (use_different_keys ? &self->srtp_ctx_neg_local->rtcp.session : &self->srtp_ctx_neg_local->rtp.session) : tsk_null + ); + + /* At this step we are able to encrypt()/decrypt() SRTP data */ + + return 0; } #endif /* HAVE_SRTP */ static int _trtp_manager_ice_init(trtp_manager_t* self) { - int ret = 0; - const tnet_ice_candidate_t *candidate_offer, *candidate_answer_src, *candidate_answer_dest; - struct tnet_socket_s *rtp_socket = tsk_null; - - if (!self || !self->ice_ctx) { - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if (!self->transport) { - // get rtp nominated symetric candidates - ret = tnet_ice_ctx_get_nominated_symetric_candidates(self->ice_ctx, TNET_ICE_CANDIDATE_COMPID_RTP, - &candidate_offer, &candidate_answer_src, &candidate_answer_dest); - self->is_ice_neg_ok = (ret == 0 && candidate_offer && candidate_answer_src && candidate_answer_dest); - self->is_ice_turn_active = self->is_ice_neg_ok && tnet_ice_ctx_is_turn_rtp_active(self->ice_ctx); - if (!self->is_ice_neg_ok) { - // If this code is called this means that ICE negotiation has failed - // This is not really an error because it could happen if the remote peer is not an ICE agent or is an ICE-lite - // in this case, use the first offered candidate which is the best one and already used in the "c=" line - if (!(candidate_offer = tnet_ice_ctx_get_local_candidate_first(self->ice_ctx))) { - // Must never happen as we always have at least one local "host" candidate - TSK_DEBUG_ERROR("ICE context not ready"); - ret = -3; - goto bail; - } - } - - // Get RTP socket - if (self->is_ice_turn_active && candidate_offer->turn.ss) { - if ((ret = tnet_turn_session_get_socket_local(candidate_offer->turn.ss, &rtp_socket))) { - goto bail; - } - } - else { - rtp_socket = tsk_object_ref(candidate_offer->socket); - } - - // create transport - if (!(self->transport = tnet_transport_create_2(rtp_socket, TRTP_TRANSPORT_NAME))) { - TSK_DEBUG_ERROR("Failed to create transport(%s:%u)", rtp_socket->ip, rtp_socket->port); - ret = -4; - goto bail; - } - // set rtp local and remote IPs and ports - if (candidate_answer_dest) { // could be "null" if remote peer is ICE-lite - tsk_strupdate(&self->rtp.remote_ip, candidate_answer_dest->connection_addr); - self->rtp.remote_port = candidate_answer_dest->port; - tsk_strupdate(&self->rtp.public_ip, candidate_offer->connection_addr); - self->rtp.public_port = candidate_offer->port; - } - - // get rtp nominated symetric candidates - if (self->use_rtcp) { - ret = tnet_ice_ctx_get_nominated_symetric_candidates(self->ice_ctx, TNET_ICE_CANDIDATE_COMPID_RTCP, - &candidate_offer, &candidate_answer_src, &candidate_answer_dest); - if (ret == 0 && candidate_offer && candidate_answer_src && candidate_answer_dest) { - // set rtp local and remote IPs and ports - tsk_strupdate(&self->rtcp.remote_ip, candidate_answer_dest->connection_addr); - self->rtcp.remote_port = candidate_answer_dest->port; - tsk_strupdate(&self->rtcp.public_ip, candidate_offer->connection_addr); - self->rtcp.public_port = candidate_offer->port; - TSK_OBJECT_SAFE_FREE(self->rtcp.local_socket); - // Get RTCP socket - if (self->is_ice_turn_active && candidate_offer->turn.ss) { - ret = tnet_turn_session_get_socket_local(candidate_offer->turn.ss, &self->rtcp.local_socket); - if (ret) { - goto bail; - } - } - else { - self->rtcp.local_socket = tsk_object_ref(candidate_offer->socket); - } - } - } - } - - // set callback functions - ret = tnet_transport_set_callback(self->transport, _trtp_transport_layer_cb, self); // NetTransport -> RtpManager - ret = tnet_ice_ctx_rtp_callback(self->ice_ctx, (tnet_ice_rtp_callback_f)_trtp_manager_recv_data, self); // ICE -> RtpManager + int ret = 0; + const tnet_ice_candidate_t *candidate_offer, *candidate_answer_src, *candidate_answer_dest; + struct tnet_socket_s *rtp_socket = tsk_null; + + if (!self || !self->ice_ctx) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if (!self->transport) { + // get rtp nominated symetric candidates + ret = tnet_ice_ctx_get_nominated_symetric_candidates(self->ice_ctx, TNET_ICE_CANDIDATE_COMPID_RTP, + &candidate_offer, &candidate_answer_src, &candidate_answer_dest); + self->is_ice_neg_ok = (ret == 0 && candidate_offer && candidate_answer_src && candidate_answer_dest); + self->is_ice_turn_active = self->is_ice_neg_ok && tnet_ice_ctx_is_turn_rtp_active(self->ice_ctx); + if (!self->is_ice_neg_ok) { + // If this code is called this means that ICE negotiation has failed + // This is not really an error because it could happen if the remote peer is not an ICE agent or is an ICE-lite + // in this case, use the first offered candidate which is the best one and already used in the "c=" line + if (!(candidate_offer = tnet_ice_ctx_get_local_candidate_first(self->ice_ctx))) { + // Must never happen as we always have at least one local "host" candidate + TSK_DEBUG_ERROR("ICE context not ready"); + ret = -3; + goto bail; + } + } + + // Get RTP socket + if (self->is_ice_turn_active && candidate_offer->turn.ss) { + if ((ret = tnet_turn_session_get_socket_local(candidate_offer->turn.ss, &rtp_socket))) { + goto bail; + } + } + else { + rtp_socket = tsk_object_ref(candidate_offer->socket); + } + + // create transport + if (!(self->transport = tnet_transport_create_2(rtp_socket, TRTP_TRANSPORT_NAME))) { + TSK_DEBUG_ERROR("Failed to create transport(%s:%u)", rtp_socket->ip, rtp_socket->port); + ret = -4; + goto bail; + } + // set rtp local and remote IPs and ports + if (candidate_answer_dest) { // could be "null" if remote peer is ICE-lite + tsk_strupdate(&self->rtp.remote_ip, candidate_answer_dest->connection_addr); + self->rtp.remote_port = candidate_answer_dest->port; + tsk_strupdate(&self->rtp.public_ip, candidate_offer->connection_addr); + self->rtp.public_port = candidate_offer->port; + } + + // get rtp nominated symetric candidates + if (self->use_rtcp) { + ret = tnet_ice_ctx_get_nominated_symetric_candidates(self->ice_ctx, TNET_ICE_CANDIDATE_COMPID_RTCP, + &candidate_offer, &candidate_answer_src, &candidate_answer_dest); + if (ret == 0 && candidate_offer && candidate_answer_src && candidate_answer_dest) { + // set rtp local and remote IPs and ports + tsk_strupdate(&self->rtcp.remote_ip, candidate_answer_dest->connection_addr); + self->rtcp.remote_port = candidate_answer_dest->port; + tsk_strupdate(&self->rtcp.public_ip, candidate_offer->connection_addr); + self->rtcp.public_port = candidate_offer->port; + TSK_OBJECT_SAFE_FREE(self->rtcp.local_socket); + // Get RTCP socket + if (self->is_ice_turn_active && candidate_offer->turn.ss) { + ret = tnet_turn_session_get_socket_local(candidate_offer->turn.ss, &self->rtcp.local_socket); + if (ret) { + goto bail; + } + } + else { + self->rtcp.local_socket = tsk_object_ref(candidate_offer->socket); + } + } + } + } + + // set callback functions + ret = tnet_transport_set_callback(self->transport, _trtp_transport_layer_cb, self); // NetTransport -> RtpManager + ret = tnet_ice_ctx_rtp_callback(self->ice_ctx, (tnet_ice_rtp_callback_f)_trtp_manager_recv_data, self); // ICE -> RtpManager bail: - TSK_OBJECT_SAFE_FREE(rtp_socket); - return ret; + TSK_OBJECT_SAFE_FREE(rtp_socket); + return ret; } /** Create RTP/RTCP manager */ trtp_manager_t* trtp_manager_create(tsk_bool_t use_rtcp, const char* local_ip, tsk_bool_t ipv6, tmedia_srtp_type_t srtp_type, tmedia_srtp_mode_t srtp_mode) { - trtp_manager_t* manager; - if((manager = _trtp_manager_create(use_rtcp, local_ip, ipv6, srtp_type, srtp_mode))){ - } - return manager; + trtp_manager_t* manager; + if((manager = _trtp_manager_create(use_rtcp, local_ip, ipv6, srtp_type, srtp_mode))) { + } + return manager; } /** Create RTP/RTCP manager */ trtp_manager_t* trtp_manager_create_2(struct tnet_ice_ctx_s* ice_ctx, tmedia_srtp_type_t srtp_type, tmedia_srtp_mode_t srtp_mode) { - trtp_manager_t* manager; - const char* local_ip; - tsk_bool_t use_ipv6, use_rtcp; - - if(!ice_ctx){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - local_ip = (use_ipv6 = tnet_ice_ctx_use_ipv6(ice_ctx)) ? "::1" : "127.0.0.1"; - use_rtcp = tnet_ice_ctx_use_rtcp(ice_ctx); - - if((manager = _trtp_manager_create(use_rtcp, local_ip, use_ipv6, srtp_type, srtp_mode))){ - manager->ice_ctx = tsk_object_ref(ice_ctx); - } - return manager; + trtp_manager_t* manager; + const char* local_ip; + tsk_bool_t use_ipv6, use_rtcp; + + if(!ice_ctx) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + local_ip = (use_ipv6 = tnet_ice_ctx_use_ipv6(ice_ctx)) ? "::1" : "127.0.0.1"; + use_rtcp = tnet_ice_ctx_use_rtcp(ice_ctx); + + if((manager = _trtp_manager_create(use_rtcp, local_ip, use_ipv6, srtp_type, srtp_mode))) { + manager->ice_ctx = tsk_object_ref(ice_ctx); + } + return manager; } int trtp_manager_set_ice_ctx(trtp_manager_t* self, struct tnet_ice_ctx_s* ice_ctx) { - if(!self){ - TSK_DEBUG_ERROR("Invalid ICE context"); - return -1; - } - TSK_OBJECT_SAFE_FREE(self->ice_ctx); - self->ice_ctx = tsk_object_ref(ice_ctx); - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid ICE context"); + return -1; + } + TSK_OBJECT_SAFE_FREE(self->ice_ctx); + self->ice_ctx = tsk_object_ref(ice_ctx); + return 0; } /** Prepares the RTP/RTCP manager */ int trtp_manager_prepare(trtp_manager_t* self) { - const char *rtp_local_ip = tsk_null, *rtcp_local_ip = tsk_null; - tnet_port_t rtp_local_port = 0, rtcp_local_port = 0; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(self->transport){ - TSK_DEBUG_ERROR("RTP/RTCP manager already prepared"); - return -2; - } - - if(self->ice_ctx){ - TSK_DEBUG_INFO("ICE enabled on RTP manager"); - // Get Sockets when the transport is started - rtp_local_ip = rtcp_local_ip = self->use_ipv6 ? "::1" : "127.0.0.1"; - rtp_local_port = 2; // ICE default rtp port, do not use zero which is reserved to disabled medias - rtcp_local_port = 1; // ICE default rtcp port, do not use zero which is reserved to disabled medias - } - else{ - #define __retry_count_max 5 - #define __retry_count_max_minus1 (__retry_count_max - 1) - uint8_t retry_count = __retry_count_max; - tnet_socket_type_t socket_type = self->use_ipv6 ? tnet_socket_type_udp_ipv6 : tnet_socket_type_udp_ipv4; - - /* Creates local rtp and rtcp sockets */ - while(retry_count--){ - /* random number in the range 1024 to 65535 */ - static int counter = 0; + const char *rtp_local_ip = tsk_null, *rtcp_local_ip = tsk_null; + tnet_port_t rtp_local_port = 0, rtcp_local_port = 0; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(self->transport) { + TSK_DEBUG_ERROR("RTP/RTCP manager already prepared"); + return -2; + } + + if(self->ice_ctx) { + TSK_DEBUG_INFO("ICE enabled on RTP manager"); + // Get Sockets when the transport is started + rtp_local_ip = rtcp_local_ip = self->use_ipv6 ? "::1" : "127.0.0.1"; + rtp_local_port = 2; // ICE default rtp port, do not use zero which is reserved to disabled medias + rtcp_local_port = 1; // ICE default rtcp port, do not use zero which is reserved to disabled medias + } + else { +#define __retry_count_max 5 +#define __retry_count_max_minus1 (__retry_count_max - 1) + uint8_t retry_count = __retry_count_max; + tnet_socket_type_t socket_type = self->use_ipv6 ? tnet_socket_type_udp_ipv6 : tnet_socket_type_udp_ipv4; + + /* Creates local rtp and rtcp sockets */ + while(retry_count--) { + /* random number in the range 1024 to 65535 */ + static int counter = 0; #if 0 - tnet_port_t local_port = 6060; + tnet_port_t local_port = 6060; #else - // first check => try to use port from latest active session if exist - tnet_port_t local_port = (retry_count == __retry_count_max_minus1 && (self->port_range.start <= self->rtp.public_port && self->rtp.public_port <= self->port_range.stop)) - ? self->rtp.public_port - : (((rand() ^ ++counter) % (self->port_range.stop - self->port_range.start)) + self->port_range.start); + // first check => try to use port from latest active session if exist + tnet_port_t local_port = (retry_count == __retry_count_max_minus1 && (self->port_range.start <= self->rtp.public_port && self->rtp.public_port <= self->port_range.stop)) + ? self->rtp.public_port + : (((rand() ^ ++counter) % (self->port_range.stop - self->port_range.start)) + self->port_range.start); #endif - local_port = (local_port & 0xFFFE); /* turn to even number */ - - /* beacuse failure will cause errors in the log, print a message to alert that there is - * nothing to worry about */ - TSK_DEBUG_INFO("RTP/RTCP manager[Begin]: Trying to bind to random ports"); - - /* RTP */ - if(!(self->transport = tnet_transport_create(self->local_ip, local_port, socket_type, TRTP_TRANSPORT_NAME))){ - TSK_DEBUG_ERROR("Failed to create RTP/RTCP Transport"); - return -3; - } - - /* RTCP */ - if (self->use_rtcp) { - if(!(self->rtcp.local_socket = tnet_socket_create(self->local_ip, local_port+1, socket_type))){ - TSK_DEBUG_WARN("Failed to bind to %d", local_port+1); - TSK_OBJECT_SAFE_FREE(self->transport); - continue; - } - } - - TSK_DEBUG_INFO("RTP/RTCP manager[End]: Trying to bind to random ports"); - break; - }// end-of-while(retry_count) - - rtp_local_ip = self->transport->master->ip; - rtp_local_port = self->transport->master->port; - if(self->rtcp.local_socket){ - rtcp_local_ip = self->rtcp.local_socket->ip; - rtcp_local_port = self->rtcp.local_socket->port; - - } - }// end-of-else(!ice) - - tsk_strupdate(&self->rtp.public_ip, rtp_local_ip); - self->rtp.public_port = rtp_local_port; - - tsk_strupdate(&self->rtcp.public_ip, rtcp_local_ip); - self->rtcp.public_port = rtcp_local_port; - - if(self->transport){ - /* set callback function */ - tnet_transport_set_callback(self->transport, _trtp_transport_layer_cb, self); - /* Disable receiving until we start the transport (To avoid buffering) */ + local_port = (local_port & 0xFFFE); /* turn to even number */ + + /* beacuse failure will cause errors in the log, print a message to alert that there is + * nothing to worry about */ + TSK_DEBUG_INFO("RTP/RTCP manager[Begin]: Trying to bind to random ports"); + + /* RTP */ + if(!(self->transport = tnet_transport_create(self->local_ip, local_port, socket_type, TRTP_TRANSPORT_NAME))) { + TSK_DEBUG_ERROR("Failed to create RTP/RTCP Transport"); + return -3; + } + + /* RTCP */ + if (self->use_rtcp) { + if(!(self->rtcp.local_socket = tnet_socket_create(self->local_ip, local_port+1, socket_type))) { + TSK_DEBUG_WARN("Failed to bind to %d", local_port+1); + TSK_OBJECT_SAFE_FREE(self->transport); + continue; + } + } + + TSK_DEBUG_INFO("RTP/RTCP manager[End]: Trying to bind to random ports"); + break; + }// end-of-while(retry_count) + + rtp_local_ip = self->transport->master->ip; + rtp_local_port = self->transport->master->port; + if(self->rtcp.local_socket) { + rtcp_local_ip = self->rtcp.local_socket->ip; + rtcp_local_port = self->rtcp.local_socket->port; + + } + }// end-of-else(!ice) + + tsk_strupdate(&self->rtp.public_ip, rtp_local_ip); + self->rtp.public_port = rtp_local_port; + + tsk_strupdate(&self->rtcp.public_ip, rtcp_local_ip); + self->rtcp.public_port = rtcp_local_port; + + if(self->transport) { + /* set callback function */ + tnet_transport_set_callback(self->transport, _trtp_transport_layer_cb, self); + /* Disable receiving until we start the transport (To avoid buffering) */ #if TRTP_DISABLE_SOCKETS_BEFORE_START - if(!self->socket_disabled){ - int err, optval = TRTP_TINY_RCVBUF; - if((err = setsockopt(self->transport->master->fd, SOL_SOCKET, SO_RCVBUF, (char*)&optval, sizeof(optval)))){ - TNET_PRINT_LAST_ERROR("setsockopt(SOL_SOCKET, SO_RCVBUF) has failed with error code %d", err); - } - self->socket_disabled = (err == 0); - } + if(!self->socket_disabled) { + int err, optval = TRTP_TINY_RCVBUF; + if((err = setsockopt(self->transport->master->fd, SOL_SOCKET, SO_RCVBUF, (char*)&optval, sizeof(optval)))) { + TNET_PRINT_LAST_ERROR("setsockopt(SOL_SOCKET, SO_RCVBUF) has failed with error code %d", err); + } + self->socket_disabled = (err == 0); + } #endif - } + } - /* SRTP */ + /* SRTP */ #if HAVE_SRTP - { - // enable SRTP to allow negotiation - if (self->srtp_type != tmedia_srtp_mode_none) { - struct tnet_socket_s* sockets[] = { self->transport ? self->transport->master : tsk_null, self->rtcp.local_socket }; - _trtp_manager_srtp_set_enabled(self, self->srtp_type, sockets, sizeof(sockets)/sizeof(sockets[0]), tsk_true); - } - } + { + // enable SRTP to allow negotiation + if (self->srtp_type != tmedia_srtp_mode_none) { + struct tnet_socket_s* sockets[] = { self->transport ? self->transport->master : tsk_null, self->rtcp.local_socket }; + _trtp_manager_srtp_set_enabled(self, self->srtp_type, sockets, sizeof(sockets)/sizeof(sockets[0]), tsk_true); + } + } #endif - return 0; + return 0; } #if HAVE_SRTP int trtp_manager_set_dtls_certs(trtp_manager_t* self, const char* ca, const char* pbk, const char* pvk, tsk_bool_t verify) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - // always save certificates even if not DTLS-SRTP transport - tsk_strupdate(&self->dtls.file_ca, ca); - tsk_strupdate(&self->dtls.file_pbk, pbk); - tsk_strupdate(&self->dtls.file_pvk, pvk); - self->dtls.cert_verif = verify; - - if((self->srtp_type & tmedia_srtp_type_dtls) && (self->srtp_mode == tmedia_srtp_mode_optional || self->srtp_mode == tmedia_srtp_mode_mandatory)){ - if(self->transport && tnet_transport_dtls_is_enabled(self->transport)){ - return tnet_transport_dtls_srtp_set_certs(self->transport, self->dtls.file_ca, self->dtls.file_pbk, self->dtls.file_pvk, self->dtls.cert_verif); - } - } - else{ - TSK_DEBUG_ERROR("DTLS certificates setting ignored for non-DTLS-SRTP transport"); - return -2; - } - - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + // always save certificates even if not DTLS-SRTP transport + tsk_strupdate(&self->dtls.file_ca, ca); + tsk_strupdate(&self->dtls.file_pbk, pbk); + tsk_strupdate(&self->dtls.file_pvk, pvk); + self->dtls.cert_verif = verify; + + if((self->srtp_type & tmedia_srtp_type_dtls) && (self->srtp_mode == tmedia_srtp_mode_optional || self->srtp_mode == tmedia_srtp_mode_mandatory)) { + if(self->transport && tnet_transport_dtls_is_enabled(self->transport)) { + return tnet_transport_dtls_srtp_set_certs(self->transport, self->dtls.file_ca, self->dtls.file_pbk, self->dtls.file_pvk, self->dtls.cert_verif); + } + } + else { + TSK_DEBUG_ERROR("DTLS certificates setting ignored for non-DTLS-SRTP transport"); + return -2; + } + + return 0; } int trtp_manager_set_dtls_callback(trtp_manager_t* self, const void* usrdata, trtp_srtp_dtls_cb_f fun) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - self->dtls.cb.usrdata = usrdata; - self->dtls.cb.fun = fun; - - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + self->dtls.cb.usrdata = usrdata; + self->dtls.cb.fun = fun; + + return 0; } int trtp_manager_set_dtls_remote_fingerprint(trtp_manager_t* self, const tnet_fingerprint_t* fp, const char* fp_hash) { - tnet_dtls_hash_type_t hash; - if(!self || !fp || !fp_hash){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - hash = tnet_dtls_get_hash_from_string(fp_hash); - if(hash != tnet_dtls_hash_type_sha1 && hash != tnet_dtls_hash_type_sha256){ - TSK_DEBUG_ERROR("%s not supported as fingerprint hash", fp_hash); - return -2; - } - self->dtls.remote.fp_hash = hash; - memcpy(self->dtls.remote.fp, &(*fp)[0], sizeof(tnet_fingerprint_t)); - return 0; + tnet_dtls_hash_type_t hash; + if(!self || !fp || !fp_hash) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + hash = tnet_dtls_get_hash_from_string(fp_hash); + if(hash != tnet_dtls_hash_type_sha1 && hash != tnet_dtls_hash_type_sha256) { + TSK_DEBUG_ERROR("%s not supported as fingerprint hash", fp_hash); + return -2; + } + self->dtls.remote.fp_hash = hash; + memcpy(self->dtls.remote.fp, &(*fp)[0], sizeof(tnet_fingerprint_t)); + return 0; } enum tnet_dtls_hash_type_e trtp_manager_get_dtls_remote_fingerprint_hash(trtp_manager_t* self) { - return (self ? self->dtls.remote.fp_hash : tnet_dtls_hash_type_none); + return (self ? self->dtls.remote.fp_hash : tnet_dtls_hash_type_none); } int trtp_manager_set_dtls_local_setup(trtp_manager_t* self, tnet_dtls_setup_t setup, tsk_bool_t connection_new) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - self->dtls.local.setup = setup; - self->dtls.local.connection_new = connection_new; - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + self->dtls.local.setup = setup; + self->dtls.local.connection_new = connection_new; + return 0; } const char* trtp_manager_get_dtls_local_fingerprint(trtp_manager_t* self, enum tnet_dtls_hash_type_e hash) { - if(!self || (int32_t)hash < 0 || (int32_t)hash >= TNET_DTLS_HASH_TYPE_MAX){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - if(!self->transport && self->dtls.file_pbk){ - static tnet_fingerprint_t fingerprint[TNET_DTLS_HASH_TYPE_MAX]; - if(tnet_dtls_get_fingerprint(self->dtls.file_pbk, &fingerprint[hash], hash) == 0){ - return (const char*)fingerprint[hash]; - } - } - return tnet_transport_dtls_get_local_fingerprint(self->transport, hash); + if(!self || (int32_t)hash < 0 || (int32_t)hash >= TNET_DTLS_HASH_TYPE_MAX) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + if(!self->transport && self->dtls.file_pbk) { + static tnet_fingerprint_t fingerprint[TNET_DTLS_HASH_TYPE_MAX]; + if(tnet_dtls_get_fingerprint(self->dtls.file_pbk, &fingerprint[hash], hash) == 0) { + return (const char*)fingerprint[hash]; + } + } + return tnet_transport_dtls_get_local_fingerprint(self->transport, hash); } tsk_bool_t trtp_manager_is_dtls_enabled(trtp_manager_t* self) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_false; - } - return (self->dtls.state >= trtp_srtp_state_enabled); + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_false; + } + return (self->dtls.state >= trtp_srtp_state_enabled); } tsk_bool_t trtp_manager_is_dtls_activated(trtp_manager_t* self) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_false; - } - return (self->dtls.state >= trtp_srtp_state_activated); + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_false; + } + return (self->dtls.state >= trtp_srtp_state_activated); } tsk_bool_t trtp_manager_is_dtls_started(trtp_manager_t* self) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_false; - } - return (self->dtls.state >= trtp_srtp_state_started); + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_false; + } + return (self->dtls.state >= trtp_srtp_state_started); } tsk_bool_t trtp_manager_is_srtp_activated(trtp_manager_t* self) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_false; - } - return (self->srtp_state >= trtp_srtp_state_activated); + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_false; + } + return (self->srtp_state >= trtp_srtp_state_activated); } tsk_bool_t trtp_manager_is_srtp_started(trtp_manager_t* self) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_false; - } - return (self->srtp_state >= trtp_srtp_state_started); + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_false; + } + return (self->srtp_state >= trtp_srtp_state_started); } /** Sets SRTP type used by the remote party */ int trtp_manager_set_srtp_type_remote(trtp_manager_t* self, tmedia_srtp_type_t srtp_type_remote) { - tsk_size_t i; - int ret; - - if (!self) { - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - for(i = 0; i < sizeof(__srtp_types)/sizeof(__srtp_types[i]); ++i) { - if ((self->srtp_type & __srtp_types[i]) && !(srtp_type_remote & __srtp_types[i])) { - struct tnet_socket_s* sockets[] = { self->transport ? self->transport->master : tsk_null, self->rtcp.local_socket }; - if ((ret = _trtp_manager_srtp_set_enabled(self, __srtp_types[i], sockets, sizeof(sockets) / sizeof(sockets[0]), tsk_false))) { - return ret; - } - self->srtp_type &= ~__srtp_types[i]; - } - } - return 0; + tsk_size_t i; + int ret; + + if (!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + for(i = 0; i < sizeof(__srtp_types)/sizeof(__srtp_types[i]); ++i) { + if ((self->srtp_type & __srtp_types[i]) && !(srtp_type_remote & __srtp_types[i])) { + struct tnet_socket_s* sockets[] = { self->transport ? self->transport->master : tsk_null, self->rtcp.local_socket }; + if ((ret = _trtp_manager_srtp_set_enabled(self, __srtp_types[i], sockets, sizeof(sockets) / sizeof(sockets[0]), tsk_false))) { + return ret; + } + self->srtp_type &= ~__srtp_types[i]; + } + } + return 0; } int trtp_manager_set_srtp_type_local(trtp_manager_t* self, enum tmedia_srtp_type_e srtp_type, enum tmedia_srtp_mode_e srtp_mode) { - if (!self) { - TSK_DEBUG_ERROR("Invalid ICE context"); - return -1; - } - if (srtp_mode == tmedia_srtp_mode_none || srtp_type == tmedia_srtp_type_none) { - struct tnet_socket_s* sockets[] = { self->transport ? self->transport->master : tsk_null, self->rtcp.local_socket }; - _trtp_manager_srtp_set_enabled(self, self->srtp_type, sockets, sizeof(sockets) / sizeof(sockets[0]), tsk_false); - self->srtp_type = srtp_type; - self->srtp_mode = srtp_mode; - return 0; - } - - self->srtp_mode = srtp_mode; - return trtp_manager_set_srtp_type_remote(self, srtp_type); + if (!self) { + TSK_DEBUG_ERROR("Invalid ICE context"); + return -1; + } + if (srtp_mode == tmedia_srtp_mode_none || srtp_type == tmedia_srtp_type_none) { + struct tnet_socket_s* sockets[] = { self->transport ? self->transport->master : tsk_null, self->rtcp.local_socket }; + _trtp_manager_srtp_set_enabled(self, self->srtp_type, sockets, sizeof(sockets) / sizeof(sockets[0]), tsk_false); + self->srtp_type = srtp_type; + self->srtp_mode = srtp_mode; + return 0; + } + + self->srtp_mode = srtp_mode; + return trtp_manager_set_srtp_type_remote(self, srtp_type); } #endif /* HAVE_SRTP */ @@ -1194,152 +1201,152 @@ int trtp_manager_set_srtp_type_local(trtp_manager_t* self, enum tmedia_srtp_type /** Indicates whether the manager is already ready or not */ tsk_bool_t trtp_manager_is_ready(trtp_manager_t* self) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_false; - } - return (self->transport != tsk_null); + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_false; + } + return (self->transport != tsk_null); } /** Sets NAT Traversal context */ int trtp_manager_set_natt_ctx(trtp_manager_t* self, struct tnet_nat_ctx_s* natt_ctx) { - int ret; - - if(!self || !self->transport || !natt_ctx){ - if(self && self->ice_ctx){ - return 0; // Nat context is not needed when ICE is enabled - } - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(!(ret = tnet_transport_set_natt_ctx(self->transport, natt_ctx))){ - tnet_ip_t public_ip = {0}; - tnet_port_t public_port = 0; - // get RTP public IP and Port - if(!tnet_transport_get_public_ip_n_port(self->transport, self->transport->master->fd, &public_ip, &public_port)){ - tsk_strupdate(&self->rtp.public_ip, public_ip); - self->rtp.public_port = public_port; - } - // get RTCP public IP and Port - memset(public_ip, 0, sizeof(public_ip)); - public_port = 0; - if(self->rtcp.local_socket && !tnet_transport_get_public_ip_n_port(self->transport, self->rtcp.local_socket->fd, &public_ip, &public_port)){ - tsk_strupdate(&self->rtcp.public_ip, public_ip); - self->rtcp.public_port = public_port; - } - // re-enable sockets to be able to receive STUN packets + int ret; + + if(!self || !self->transport || !natt_ctx) { + if(self && self->ice_ctx) { + return 0; // Nat context is not needed when ICE is enabled + } + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(!(ret = tnet_transport_set_natt_ctx(self->transport, natt_ctx))) { + tnet_ip_t public_ip = {0}; + tnet_port_t public_port = 0; + // get RTP public IP and Port + if(!tnet_transport_get_public_ip_n_port(self->transport, self->transport->master->fd, &public_ip, &public_port)) { + tsk_strupdate(&self->rtp.public_ip, public_ip); + self->rtp.public_port = public_port; + } + // get RTCP public IP and Port + memset(public_ip, 0, sizeof(public_ip)); + public_port = 0; + if(self->rtcp.local_socket && !tnet_transport_get_public_ip_n_port(self->transport, self->rtcp.local_socket->fd, &public_ip, &public_port)) { + tsk_strupdate(&self->rtcp.public_ip, public_ip); + self->rtcp.public_port = public_port; + } + // re-enable sockets to be able to receive STUN packets #if 0 - _trtp_manager_enable_sockets(self); + _trtp_manager_enable_sockets(self); #endif - } - return ret; + } + return ret; } /** Sets RTP callback */ int trtp_manager_set_rtp_callback(trtp_manager_t* self, trtp_rtp_cb_f fun, const void* usrdata) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - self->rtp.cb.fun = fun; - self->rtp.cb.usrdata = usrdata; + self->rtp.cb.fun = fun; + self->rtp.cb.usrdata = usrdata; - return 0; + return 0; } /** Sets RTCP callback */ int trtp_manager_set_rtcp_callback(trtp_manager_t* self, trtp_rtcp_cb_f fun, const void* usrdata) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - self->rtcp.cb.fun = fun; - self->rtcp.cb.usrdata = usrdata; - if(self->rtcp.session){ - return trtp_rtcp_session_set_callback(self->rtcp.session, fun, usrdata); - } - - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + self->rtcp.cb.fun = fun; + self->rtcp.cb.usrdata = usrdata; + if(self->rtcp.session) { + return trtp_rtcp_session_set_callback(self->rtcp.session, fun, usrdata); + } + + return 0; } /** Sets the payload type */ int trtp_manager_set_payload_type(trtp_manager_t* self, uint8_t payload_type) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - self->rtp.payload_type = payload_type; - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + self->rtp.payload_type = payload_type; + return 0; } int trtp_manager_set_rtp_dscp(trtp_manager_t* self, int32_t dscp) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - self->rtp.dscp = dscp; - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + self->rtp.dscp = dscp; + return 0; } /** Sets remote parameters for rtp session */ int trtp_manager_set_rtp_remote(trtp_manager_t* self, const char* remote_ip, tnet_port_t remote_port) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - // if ICE is enabled then, these values will be updated when the manager start()s and call ice_init() - tsk_strupdate(&self->rtp.remote_ip, remote_ip); - self->rtp.remote_port = remote_port; - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + // if ICE is enabled then, these values will be updated when the manager start()s and call ice_init() + tsk_strupdate(&self->rtp.remote_ip, remote_ip); + self->rtp.remote_port = remote_port; + return 0; } /** Sets remote parameters for rtcp session */ int trtp_manager_set_rtcp_remote(trtp_manager_t* self, const char* remote_ip, tnet_port_t remote_port) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(self->ice_ctx){ - TSK_DEBUG_WARN("Manually setting RTCP remote IP and Port while ICE is enabled"); - } - tsk_strupdate(&self->rtcp.remote_ip, remote_ip); - self->rtcp.remote_port = remote_port; - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(self->ice_ctx) { + TSK_DEBUG_WARN("Manually setting RTCP remote IP and Port while ICE is enabled"); + } + tsk_strupdate(&self->rtcp.remote_ip, remote_ip); + self->rtcp.remote_port = remote_port; + return 0; } int trtp_manager_set_port_range(trtp_manager_t* self, uint16_t start, uint16_t stop) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - self->port_range.start = start; - self->port_range.stop = stop; - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + self->port_range.start = start; + self->port_range.stop = stop; + return 0; } int trtp_manager_set_rtcweb_type_remote(trtp_manager_t* self, tmedia_rtcweb_type_t rtcweb_type) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - self->rtcweb_type.remote = rtcweb_type; - return 0; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + self->rtcweb_type.remote = rtcweb_type; + return 0; } int trtp_manager_set_proxy_auto_detect(trtp_manager_t* self, tsk_bool_t auto_detect) { - if (!self){ + if (!self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } @@ -1349,7 +1356,7 @@ int trtp_manager_set_proxy_auto_detect(trtp_manager_t* self, tsk_bool_t auto_det int trtp_manager_set_proxy_info(trtp_manager_t* self, enum tnet_proxy_type_e type, const char* host, tnet_port_t port, const char* login, const char* password) { - if (!self){ + if (!self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } @@ -1367,41 +1374,41 @@ int trtp_manager_set_proxy_info(trtp_manager_t* self, enum tnet_proxy_type_e typ /** Starts the RTP/RTCP manager */ int trtp_manager_start(trtp_manager_t* self) { - int ret = 0; - int rcv_buf = (int)tmedia_defaults_get_rtpbuff_size(); - int snd_buf = (int)tmedia_defaults_get_rtpbuff_size(); + int ret = 0; + int rcv_buf = (int)tmedia_defaults_get_rtpbuff_size(); + int snd_buf = (int)tmedia_defaults_get_rtpbuff_size(); #if !TRTP_UNDER_WINDOWS_CE int32_t dscp_rtp; #endif - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - tsk_safeobj_lock(self); - - if (self->is_started) { - goto bail; - } - - // Initialize transport with ICE context - if (self->ice_ctx && (ret = _trtp_manager_ice_init(self)) != 0) { - TSK_DEBUG_ERROR("_trtp_manager_ice_init() failed"); - goto bail; - } - - if(!self->transport && (ret = trtp_manager_prepare(self))){ - TSK_DEBUG_ERROR("Failed to prepare RTP/RTCP mamanger"); - goto bail; - } - - if(!self->transport || !self->transport->master){ - TSK_DEBUG_ERROR("RTP/RTCP manager not prepared"); - ret = -2; - goto bail; - } - + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + tsk_safeobj_lock(self); + + if (self->is_started) { + goto bail; + } + + // Initialize transport with ICE context + if (self->ice_ctx && (ret = _trtp_manager_ice_init(self)) != 0) { + TSK_DEBUG_ERROR("_trtp_manager_ice_init() failed"); + goto bail; + } + + if(!self->transport && (ret = trtp_manager_prepare(self))) { + TSK_DEBUG_ERROR("Failed to prepare RTP/RTCP mamanger"); + goto bail; + } + + if(!self->transport || !self->transport->master) { + TSK_DEBUG_ERROR("RTP/RTCP manager not prepared"); + ret = -2; + goto bail; + } + /* Proxy */ // Proxy info if ((ret = tnet_transport_set_proxy_auto_detect(self->transport, self->proxy.auto_detect))) { @@ -1415,289 +1422,291 @@ int trtp_manager_start(trtp_manager_t* self) } } - /* Flush buffers and re-enable sockets */ - if(self->transport->master && self->is_socket_disabled){ - static char buff[1024]; - tsk_size_t guard_count = 0; + /* Flush buffers and re-enable sockets */ + if(self->transport->master && self->is_socket_disabled) { + static char buff[1024]; + tsk_size_t guard_count = 0; #if 0 - // re-enable sockets - _trtp_manager_enable_sockets(self); + // re-enable sockets + _trtp_manager_enable_sockets(self); #endif - TSK_DEBUG_INFO("Start flushing RTP socket..."); - // Buffer should be empty ...but who know? - // rcv() should never block() as we are always using non-blocking sockets - while ((ret = (int)recv(self->transport->master->fd, buff, sizeof(buff), 0)) > 0 && ++guard_count < 0xF0){ - TSK_DEBUG_INFO("Flushing RTP Buffer %d", ret); - } - TSK_DEBUG_INFO("End flushing RTP socket"); - } + TSK_DEBUG_INFO("Start flushing RTP socket..."); + // Buffer should be empty ...but who know? + // rcv() should never block() as we are always using non-blocking sockets + while ((ret = (int)recv(self->transport->master->fd, buff, sizeof(buff), 0)) > 0 && ++guard_count < 0xF0) { + TSK_DEBUG_INFO("Flushing RTP Buffer %d", ret); + } + TSK_DEBUG_INFO("End flushing RTP socket"); + } - /* enlarge socket buffer */ + /* enlarge socket buffer */ #if !TRTP_UNDER_WINDOWS_CE - TSK_DEBUG_INFO("SO_RCVBUF = %d, SO_SNDBUF = %d", rcv_buf, snd_buf); - if ((ret = setsockopt(self->transport->master->fd, SOL_SOCKET, SO_RCVBUF, (char*)&rcv_buf, sizeof(rcv_buf)))) { - TNET_PRINT_LAST_ERROR("setsockopt(SOL_SOCKET, SO_RCVBUF, %d) has failed with error code %d", rcv_buf, ret); - } - if ((ret = setsockopt(self->transport->master->fd, SOL_SOCKET, SO_SNDBUF, (char*)&snd_buf, sizeof(snd_buf)))) { - TNET_PRINT_LAST_ERROR("setsockopt(SOL_SOCKET, SO_SNDBUF, %d) has failed with error code %d", snd_buf, ret); - } - dscp_rtp = (self->rtp.dscp << 2); - if ((ret = setsockopt(self->transport->master->fd, IPPROTO_IP, IP_TOS, (char*)&dscp_rtp, sizeof(dscp_rtp)))) { - TNET_PRINT_LAST_ERROR("setsockopt(IPPROTO_IP, IP_TOS) has failed with error code %d", ret); - } + TSK_DEBUG_INFO("SO_RCVBUF = %d, SO_SNDBUF = %d", rcv_buf, snd_buf); + if ((ret = setsockopt(self->transport->master->fd, SOL_SOCKET, SO_RCVBUF, (char*)&rcv_buf, sizeof(rcv_buf)))) { + TNET_PRINT_LAST_ERROR("setsockopt(SOL_SOCKET, SO_RCVBUF, %d) has failed with error code %d", rcv_buf, ret); + } + if ((ret = setsockopt(self->transport->master->fd, SOL_SOCKET, SO_SNDBUF, (char*)&snd_buf, sizeof(snd_buf)))) { + TNET_PRINT_LAST_ERROR("setsockopt(SOL_SOCKET, SO_SNDBUF, %d) has failed with error code %d", snd_buf, ret); + } + dscp_rtp = (self->rtp.dscp << 2); + if ((ret = setsockopt(self->transport->master->fd, IPPROTO_IP, IP_TOS, (char*)&dscp_rtp, sizeof(dscp_rtp)))) { + TNET_PRINT_LAST_ERROR("setsockopt(IPPROTO_IP, IP_TOS) has failed with error code %d", ret); + } #endif /* !TRTP_UNDER_WINDOWS_CE */ - /* RTP */ - - // check remote IP address validity - if((tsk_striequals(self->rtp.remote_ip, "0.0.0.0") || tsk_striequals(self->rtp.remote_ip, "::"))) { // most likely loopback testing - tnet_ip_t source = {0}; - tsk_bool_t updated = tsk_false; - if(self->transport && self->transport->master){ - updated = (tnet_getbestsource(self->transport->master->ip, self->transport->master->port, self->transport->master->type, &source) == 0); - } - // Not allowed to send data to "0.0.0.0" - TSK_DEBUG_INFO("RTP remote IP contains not allowed value ...changing to '%s'", updated ? source : "oops"); - if(updated){ - tsk_strupdate(&self->rtp.remote_ip, source); - } - } - if((ret = tnet_sockaddr_init(self->rtp.remote_ip, self->rtp.remote_port, self->transport->master->type, &self->rtp.remote_addr))){ - tnet_transport_shutdown(self->transport); - TSK_OBJECT_SAFE_FREE(self->transport); - TSK_DEBUG_ERROR("Invalid RTP host:port [%s:%u]", self->rtp.remote_ip, self->rtp.remote_port); - goto bail; - } - TSK_DEBUG_INFO("rtp.remote_ip=%s, rtp.remote_port=%d, rtp.local_fd=%d", self->rtp.remote_ip, self->rtp.remote_port, self->transport->master->fd); - - /* RTCP */ - if(self->use_rtcp){ - tnet_fd_t local_rtcp_fd = self->rtcp.local_socket ? self->rtcp.local_socket->fd : -1; - if(local_rtcp_fd < 0 || self->use_rtcpmux){ // use RTP local port to send RTCP packets - local_rtcp_fd = self->transport->master->fd; - } - - if(!self->rtcp.remote_ip){ - self->rtcp.remote_ip = tsk_strdup(self->rtcp.remote_ip ? self->rtcp.remote_ip : self->rtp.remote_ip); - } - if(!self->rtcp.remote_port){ - self->rtcp.remote_port = self->rtcp.remote_port ? self->rtcp.remote_port : (self->use_rtcpmux ? self->rtp.remote_port : (self->rtp.remote_port + 1)); - } - - TSK_DEBUG_INFO("rtcp.remote_ip=%s, rtcp.remote_port=%d, rtcp.local_fd=%d", self->rtcp.remote_ip, self->rtcp.remote_port, local_rtcp_fd); - if((ret = tnet_sockaddr_init(self->rtcp.remote_ip, self->rtcp.remote_port, self->transport->master->type, &self->rtcp.remote_addr))){ - TSK_DEBUG_ERROR("Invalid RTCP host:port [%s:%u]", self->rtcp.remote_ip, self->rtcp.remote_port); - /* do not exit */ - } - - /* add RTCP socket to the transport */ - if(self->rtcp.local_socket){ - TSK_DEBUG_INFO("rtcp.local_ip=%s, rtcp.local_port=%d, rtcp.local_fd=%d", self->rtcp.local_socket->ip, self->rtcp.local_socket->port, self->rtcp.local_socket->fd); - if(ret == 0 && (ret = tnet_transport_add_socket(self->transport, self->rtcp.local_socket->fd, self->rtcp.local_socket->type, tsk_false/* do not take ownership */, tsk_true/* only Meaningful for tls*/, tsk_null))){ - TSK_DEBUG_ERROR("Failed to add RTCP socket"); - /* do not exit */ - } - } - /* create and start RTCP session */ - if(!self->rtcp.session && ret == 0){ - self->rtcp.session = trtp_rtcp_session_create_2(self->ice_ctx, self->rtp.ssrc.local, self->rtcp.cname); - } - if(self->rtcp.session){ - ret = trtp_rtcp_session_set_callback(self->rtcp.session, self->rtcp.cb.fun, self->rtcp.cb.usrdata); - ret = trtp_rtcp_session_set_app_bandwidth_max(self->rtcp.session, self->app_bw_max_upload, self->app_bw_max_download); + /* RTP */ + + // check remote IP address validity + if((tsk_striequals(self->rtp.remote_ip, "0.0.0.0") || tsk_striequals(self->rtp.remote_ip, "::"))) { // most likely loopback testing + tnet_ip_t source = {0}; + tsk_bool_t updated = tsk_false; + if(self->transport && self->transport->master) { + updated = (tnet_getbestsource(self->transport->master->ip, self->transport->master->port, self->transport->master->type, &source) == 0); + } + // Not allowed to send data to "0.0.0.0" + TSK_DEBUG_INFO("RTP remote IP contains not allowed value ...changing to '%s'", updated ? source : "oops"); + if(updated) { + tsk_strupdate(&self->rtp.remote_ip, source); + } + } + if((ret = tnet_sockaddr_init(self->rtp.remote_ip, self->rtp.remote_port, self->transport->master->type, &self->rtp.remote_addr))) { + tnet_transport_shutdown(self->transport); + TSK_OBJECT_SAFE_FREE(self->transport); + TSK_DEBUG_ERROR("Invalid RTP host:port [%s:%u]", self->rtp.remote_ip, self->rtp.remote_port); + goto bail; + } + TSK_DEBUG_INFO("rtp.remote_ip=%s, rtp.remote_port=%d, rtp.local_fd=%d", self->rtp.remote_ip, self->rtp.remote_port, self->transport->master->fd); + + /* RTCP */ + if(self->use_rtcp) { + tnet_fd_t local_rtcp_fd = self->rtcp.local_socket ? self->rtcp.local_socket->fd : -1; + if(local_rtcp_fd < 0 || self->use_rtcpmux) { // use RTP local port to send RTCP packets + local_rtcp_fd = self->transport->master->fd; + } + + if(!self->rtcp.remote_ip) { + self->rtcp.remote_ip = tsk_strdup(self->rtcp.remote_ip ? self->rtcp.remote_ip : self->rtp.remote_ip); + } + if(!self->rtcp.remote_port) { + self->rtcp.remote_port = self->rtcp.remote_port ? self->rtcp.remote_port : (self->use_rtcpmux ? self->rtp.remote_port : (self->rtp.remote_port + 1)); + } + + TSK_DEBUG_INFO("rtcp.remote_ip=%s, rtcp.remote_port=%d, rtcp.local_fd=%d", self->rtcp.remote_ip, self->rtcp.remote_port, local_rtcp_fd); + if((ret = tnet_sockaddr_init(self->rtcp.remote_ip, self->rtcp.remote_port, self->transport->master->type, &self->rtcp.remote_addr))) { + TSK_DEBUG_ERROR("Invalid RTCP host:port [%s:%u]", self->rtcp.remote_ip, self->rtcp.remote_port); + /* do not exit */ + } + + /* add RTCP socket to the transport */ + if(self->rtcp.local_socket) { + TSK_DEBUG_INFO("rtcp.local_ip=%s, rtcp.local_port=%d, rtcp.local_fd=%d", self->rtcp.local_socket->ip, self->rtcp.local_socket->port, self->rtcp.local_socket->fd); + if(ret == 0 && (ret = tnet_transport_add_socket(self->transport, self->rtcp.local_socket->fd, self->rtcp.local_socket->type, tsk_false/* do not take ownership */, tsk_true/* only Meaningful for tls*/, tsk_null))) { + TSK_DEBUG_ERROR("Failed to add RTCP socket"); + /* do not exit */ + } + } + /* create and start RTCP session */ + if(!self->rtcp.session && ret == 0) { + self->rtcp.session = trtp_rtcp_session_create_2(self->ice_ctx, self->rtp.ssrc.local, self->rtcp.cname); + } + if(self->rtcp.session) { + ret = trtp_rtcp_session_set_callback(self->rtcp.session, self->rtcp.cb.fun, self->rtcp.cb.usrdata); + ret = trtp_rtcp_session_set_app_bw_and_jcng(self->rtcp.session, self->app_bw_max_upload, self->app_bw_max_download, self->app_jitter_cng); ret = trtp_rtcp_session_set_net_transport(self->rtcp.session, self->transport); - if((ret = trtp_rtcp_session_start(self->rtcp.session, local_rtcp_fd, (const struct sockaddr *)&self->rtcp.remote_addr))){ - TSK_DEBUG_ERROR("Failed to start RTCP session"); - goto bail; - } - } - } - - /*SRTP*/ + if((ret = trtp_rtcp_session_start(self->rtcp.session, local_rtcp_fd, (const struct sockaddr *)&self->rtcp.remote_addr))) { + TSK_DEBUG_ERROR("Failed to start RTCP session"); + goto bail; + } + } + } + + /*SRTP*/ #if HAVE_SRTP - { - // activate SRTP (nothing will be done is srtp_mode is # "optional/mandatory") - // will also start the manager if we're using SDES mode - if((ret = _trtp_manager_srtp_activate(self, self->srtp_type))){ - goto bail; - } - - /* DTLS handshaking Timer */ - if (self->timer_mgr_global && self->srtp_state == trtp_srtp_state_activated && (self->srtp_type & tmedia_srtp_type_dtls) == tmedia_srtp_type_dtls) { - ret = tsk_timer_manager_start(self->timer_mgr_global); - self->dtls.timer_hanshaking.timeout = TRTP_DTLS_HANDSHAKING_TIMEOUT; - // start handshaking timer - // never mind if net work transport not started yet: the DTLS sockets will send the handshaking data by themself - self->dtls.timer_hanshaking.id = tsk_timer_manager_schedule(self->timer_mgr_global, self->dtls.timer_hanshaking.timeout, _trtp_transport_dtls_handshaking_timer_cb, self); - } - } + { + // activate SRTP (nothing will be done is srtp_mode is # "optional/mandatory") + // will also start the manager if we're using SDES mode + if((ret = _trtp_manager_srtp_activate(self, self->srtp_type))) { + goto bail; + } + + /* DTLS handshaking Timer */ + if (self->timer_mgr_global && self->srtp_state == trtp_srtp_state_activated && (self->srtp_type & tmedia_srtp_type_dtls) == tmedia_srtp_type_dtls) { + ret = tsk_timer_manager_start(self->timer_mgr_global); + self->dtls.timer_hanshaking.timeout = TRTP_DTLS_HANDSHAKING_TIMEOUT; + // start handshaking timer + // never mind if net work transport not started yet: the DTLS sockets will send the handshaking data by themself + self->dtls.timer_hanshaking.id = tsk_timer_manager_schedule(self->timer_mgr_global, self->dtls.timer_hanshaking.timeout, _trtp_transport_dtls_handshaking_timer_cb, self); + } + } #endif /* HAVE_SRTP */ - /* start the transport if TURN is not active (otherwise TURN data will be received directly on RTP manager with channel headers) */ - if (!self->is_ice_turn_active && (ret = tnet_transport_start(self->transport))) { - TSK_DEBUG_ERROR("Failed to start the RTP/RTCP transport"); - goto bail; - } + /* start the transport if TURN is not active (otherwise TURN data will be received directly on RTP manager with channel headers) */ + if (!self->is_ice_turn_active && (ret = tnet_transport_start(self->transport))) { + TSK_DEBUG_ERROR("Failed to start the RTP/RTCP transport"); + goto bail; + } - self->is_started = tsk_true; + self->is_started = tsk_true; bail: - tsk_safeobj_unlock(self); + tsk_safeobj_unlock(self); - return ret; + return ret; } -/* Encapsulate raw data into RTP packet and send it over the network +/* Encapsulate raw data into RTP packet and send it over the network * Very IMPORTANT: For voice packets, the marker bits indicates the beginning of a talkspurt */ tsk_size_t trtp_manager_send_rtp(trtp_manager_t* self, const void* data, tsk_size_t size, uint32_t duration, tsk_bool_t marker, tsk_bool_t last_packet) { - trtp_rtp_packet_t* packet; - tsk_size_t ret; - - if(!self || !self->transport || !data || !size){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - - /* check if transport is started */ - if(!self->is_started || !self->transport->master){ - TSK_DEBUG_WARN("RTP engine not ready yet"); - return 0; - } + trtp_rtp_packet_t* packet; + tsk_size_t ret; + + if(!self || !self->transport || !data || !size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + /* check if transport is started */ + if(!self->is_started || !self->transport->master) { + TSK_DEBUG_WARN("RTP engine not ready yet"); + return 0; + } #if HAVE_SRTP - /* check that SRTP engine is ready or disabled */ - if(self->srtp_state != trtp_srtp_state_none && self->srtp_state != trtp_srtp_state_started){ - TSK_DEBUG_WARN("SRTP engine not ready yet"); - return 0; - } + /* check that SRTP engine is ready or disabled */ + if(self->srtp_state != trtp_srtp_state_none && self->srtp_state != trtp_srtp_state_started) { + TSK_DEBUG_WARN("SRTP engine not ready yet"); + return 0; + } #endif - /* create packet with header */ - if(!(packet = trtp_rtp_packet_create(self->rtp.ssrc.local, ++self->rtp.seq_num, self->rtp.timestamp, self->rtp.payload_type, marker))){ - return 0; - } - if(last_packet){ - self->rtp.timestamp += duration; - } - - /* set data */ + /* create packet with header */ + if(!(packet = trtp_rtp_packet_create(self->rtp.ssrc.local, ++self->rtp.seq_num, self->rtp.timestamp, self->rtp.payload_type, marker))) { + return 0; + } + if(last_packet) { + self->rtp.timestamp += duration; + } + + /* set data */ #if 0 - if((packet->payload.data = tsk_calloc(size, sizeof(uint8_t)))){ - memcpy(packet->payload.data, data, size); - packet->payload.size = size; - } + if((packet->payload.data = tsk_calloc(size, sizeof(uint8_t)))) { + memcpy(packet->payload.data, data, size); + packet->payload.size = size; + } #else - packet->payload.data_const = data; - packet->payload.size = size; + packet->payload.data_const = data; + packet->payload.size = size; #endif - ret = trtp_manager_send_rtp_packet(self, packet, tsk_false); - TSK_OBJECT_SAFE_FREE(packet); - return ret; + ret = trtp_manager_send_rtp_packet(self, packet, tsk_false); + TSK_OBJECT_SAFE_FREE(packet); + return ret; } // serialize, encrypt then send the data tsk_size_t trtp_manager_send_rtp_packet(trtp_manager_t* self, const struct trtp_rtp_packet_s* packet, tsk_bool_t bypass_encrypt) { - int ret = 0; - tsk_size_t rtp_buff_pad_count = 0; - tsk_size_t xsize; - - /* check validity */ - if(!self || !packet){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - - tsk_safeobj_lock(self); - + int ret = 0; + tsk_size_t rtp_buff_pad_count = 0; + tsk_size_t xsize; + + /* check validity */ + if(!self || !packet) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + tsk_safeobj_lock(self); + // reset index self->rtp.serial_buffer.index = 0; - /* check if transport is started */ - if(!self->is_started || !self->transport || !self->transport->master){ - TSK_DEBUG_WARN("RTP engine not ready yet"); - ret = 0; - goto bail; - } + /* check if transport is started */ + if(!self->is_started || !self->transport || !self->transport->master) { + TSK_DEBUG_WARN("RTP engine not ready yet"); + ret = 0; + goto bail; + } #if HAVE_SRTP - /* check that SRTP engine is ready or disabled */ - if(self->srtp_state != trtp_srtp_state_none && self->srtp_state != trtp_srtp_state_started){ - TSK_DEBUG_WARN("SRTP engine not ready yet"); - ret = 0; - goto bail; - } - if(self->srtp_ctx_neg_local && !bypass_encrypt){ - rtp_buff_pad_count = (SRTP_MAX_TRAILER_LEN + 0x04); - } + /* check that SRTP engine is ready or disabled */ + if(self->srtp_state != trtp_srtp_state_none && self->srtp_state != trtp_srtp_state_started) { + TSK_DEBUG_WARN("SRTP engine not ready yet"); + ret = 0; + goto bail; + } + if(self->srtp_ctx_neg_local && !bypass_encrypt) { + rtp_buff_pad_count = (SRTP_MAX_TRAILER_LEN + 0x04); + } #endif /* HAVE_SRTP */ - xsize = (trtp_rtp_packet_guess_serialbuff_size(packet) + rtp_buff_pad_count); - if(self->rtp.serial_buffer.size < xsize){ - if(!(self->rtp.serial_buffer.ptr = tsk_realloc(self->rtp.serial_buffer.ptr, xsize))){ - TSK_DEBUG_ERROR("Failed to allocate buffer with size = %d", (int)xsize); - self->rtp.serial_buffer.size = 0; - goto bail; - } - self->rtp.serial_buffer.size = xsize; - } - - /* serialize and send over the network */ - if ((ret = (int)trtp_rtp_packet_serialize_to(packet, self->rtp.serial_buffer.ptr, xsize))) { - void* data_ptr = self->rtp.serial_buffer.ptr; - int data_size = ret; + xsize = (trtp_rtp_packet_guess_serialbuff_size(packet) + rtp_buff_pad_count); + if(self->rtp.serial_buffer.size < xsize) { + if(!(self->rtp.serial_buffer.ptr = tsk_realloc(self->rtp.serial_buffer.ptr, xsize))) { + TSK_DEBUG_ERROR("Failed to allocate buffer with size = %d", (int)xsize); + self->rtp.serial_buffer.size = 0; + goto bail; + } + self->rtp.serial_buffer.size = xsize; + } + + /* serialize and send over the network */ + if ((ret = (int)trtp_rtp_packet_serialize_to(packet, self->rtp.serial_buffer.ptr, xsize))) { + void* data_ptr = self->rtp.serial_buffer.ptr; + int data_size = ret; #if HAVE_SRTP - err_status_t status; - if(self->srtp_ctx_neg_local && !bypass_encrypt){ - if((status = srtp_protect(self->srtp_ctx_neg_local->rtp.session, data_ptr, &data_size)) != err_status_ok){ - TSK_DEBUG_ERROR("srtp_protect() failed with error code =%d", (int)status); - goto bail; - } - } + err_status_t status; + if(self->srtp_ctx_neg_local && !bypass_encrypt) { + if((status = srtp_protect(self->srtp_ctx_neg_local->rtp.session, data_ptr, &data_size)) != err_status_ok) { + TSK_DEBUG_ERROR("srtp_protect() failed with error code =%d", (int)status); + goto bail; + } + } #endif self->rtp.serial_buffer.index = data_size; // update index - if (/* number of bytes sent */(ret = (int)trtp_manager_send_rtp_raw(self, data_ptr, data_size)) > 0) { - // forward packet to the RTCP session - if (self->rtcp.session) { - trtp_rtcp_session_process_rtp_out(self->rtcp.session, packet, data_size); - } - } - else ret = 0; - } - else{ - TSK_DEBUG_ERROR("Failed to serialize RTP packet"); - } + if (/* number of bytes sent */(ret = (int)trtp_manager_send_rtp_raw(self, data_ptr, data_size)) > 0) { + // forward packet to the RTCP session + if (self->rtcp.session) { + trtp_rtcp_session_process_rtp_out(self->rtcp.session, packet, data_size); + } + } + else { + ret = 0; + } + } + else { + TSK_DEBUG_ERROR("Failed to serialize RTP packet"); + } bail: - tsk_safeobj_unlock(self); - return ret; + tsk_safeobj_unlock(self); + return ret; } // send raw data "as is" without adding any RTP header or SRTP encryption tsk_size_t trtp_manager_send_rtp_raw(trtp_manager_t* self, const void* data, tsk_size_t size) { - tsk_size_t ret = 0; - - if(!self || !self->transport || !self->transport->master || !data || !size){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - tsk_safeobj_lock(self); - if (self->is_ice_turn_active) { - // Send UDP/TCP/TLS buffer using TURN sockets - ret = (tnet_ice_ctx_send_turn_rtp(self->ice_ctx, data, size) == 0) ? size : 0; // returns #0 if ok - } - else { + tsk_size_t ret = 0; + + if(!self || !self->transport || !self->transport->master || !data || !size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + tsk_safeobj_lock(self); + if (self->is_ice_turn_active) { + // Send UDP/TCP/TLS buffer using TURN sockets + ret = (tnet_ice_ctx_send_turn_rtp(self->ice_ctx, data, size) == 0) ? size : 0; // returns #0 if ok + } + else { #if 1 ret = tnet_transport_sendto(self->transport, self->transport->master->fd, (const struct sockaddr *)&self->rtp.remote_addr, data, size); // returns number of sent bytes #else - ret = tnet_sockfd_sendto(self->transport->master->fd, (const struct sockaddr *)&self->rtp.remote_addr, data, size); // returns number of sent bytes + ret = tnet_sockfd_sendto(self->transport->master->fd, (const struct sockaddr *)&self->rtp.remote_addr, data, size); // returns number of sent bytes #endif - } - tsk_safeobj_unlock(self); - return ret; + } + tsk_safeobj_unlock(self); + return ret; } int trtp_manager_get_bytes_count(trtp_manager_t* self, uint64_t* bytes_in, uint64_t* bytes_out) @@ -1708,125 +1717,130 @@ int trtp_manager_get_bytes_count(trtp_manager_t* self, uint64_t* bytes_in, uint6 } if (!self->is_started) { TSK_DEBUG_INFO("trtp_manager_get_bytes_count() called before starting RTP manager... returning zeros"); - if (bytes_in) *bytes_in = 0; - if (bytes_out) *bytes_out = 0; + if (bytes_in) { + *bytes_in = 0; + } + if (bytes_out) { + *bytes_out = 0; + } return 0; } - + if (self->is_ice_turn_active) { return tnet_ice_ctx_turn_get_bytes_count(self->ice_ctx, bytes_in, bytes_out); } return tnet_transport_get_bytes_count(self->transport, bytes_in, bytes_out); } -int trtp_manager_set_app_bandwidth_max(trtp_manager_t* self, int32_t bw_upload_kbps, int32_t bw_download_kbps) +int trtp_manager_set_app_bw_and_jcng(trtp_manager_t* self, int32_t bw_upload_kbps, int32_t bw_download_kbps, float q_jcng) { - if(self){ - self->app_bw_max_upload = bw_upload_kbps; - self->app_bw_max_download = bw_download_kbps; - if(self->rtcp.session){ - return trtp_rtcp_session_set_app_bandwidth_max(self->rtcp.session, bw_upload_kbps, bw_download_kbps); - } - return 0; - } - return -1; + if(self) { + self->app_bw_max_upload = bw_upload_kbps; + self->app_bw_max_download = bw_download_kbps; + self->app_jitter_cng = q_jcng; + if(self->rtcp.session) { + return trtp_rtcp_session_set_app_bw_and_jcng(self->rtcp.session, bw_upload_kbps, bw_download_kbps, q_jcng); + } + return 0; + } + return -1; } int trtp_manager_signal_pkt_loss(trtp_manager_t* self, uint32_t ssrc_media, const uint16_t* seq_nums, tsk_size_t count) { - if(self && self->rtcp.session){ - return trtp_rtcp_session_signal_pkt_loss(self->rtcp.session, ssrc_media, seq_nums, count); - } - return -1; + if(self && self->rtcp.session) { + return trtp_rtcp_session_signal_pkt_loss(self->rtcp.session, ssrc_media, seq_nums, count); + } + return -1; } int trtp_manager_signal_frame_corrupted(trtp_manager_t* self, uint32_t ssrc_media) { - if(self && self->rtcp.session){ - return trtp_rtcp_session_signal_frame_corrupted(self->rtcp.session, ssrc_media); - } - return -1; + if(self && self->rtcp.session) { + return trtp_rtcp_session_signal_frame_corrupted(self->rtcp.session, ssrc_media); + } + return -1; } int trtp_manager_signal_jb_error(trtp_manager_t* self, uint32_t ssrc_media) { - if(self && self->rtcp.session){ - return trtp_rtcp_session_signal_jb_error(self->rtcp.session, ssrc_media); - } - return -1; + if(self && self->rtcp.session) { + return trtp_rtcp_session_signal_jb_error(self->rtcp.session, ssrc_media); + } + return -1; } /** Stops the RTP/RTCP manager */ int trtp_manager_stop(trtp_manager_t* self) { - int ret = 0; + int ret = 0; - if (!self) { - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if (!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - TSK_DEBUG_INFO("trtp_manager_stop()"); + TSK_DEBUG_INFO("trtp_manager_stop()"); - tsk_safeobj_lock(self); + tsk_safeobj_lock(self); - // We haven't started the ICE context which means we must not stop it - //if(self->ice_ctx){ - // ret = tnet_ice_ctx_stop(self->ice_ctx); - //} + // We haven't started the ICE context which means we must not stop it + //if(self->ice_ctx){ + // ret = tnet_ice_ctx_stop(self->ice_ctx); + //} - // callbacks - if (self->transport) { - ret = tnet_transport_set_callback(self->transport, tsk_null, tsk_null); - } - if (self->ice_ctx) { - ret = tnet_ice_ctx_rtp_callback(self->ice_ctx, tsk_null, tsk_null); - } + // callbacks + if (self->transport) { + ret = tnet_transport_set_callback(self->transport, tsk_null, tsk_null); + } + if (self->ice_ctx) { + ret = tnet_ice_ctx_rtp_callback(self->ice_ctx, tsk_null, tsk_null); + } - // Stop the RTCP session first (will send BYE) - if(self->rtcp.session){ - ret = trtp_rtcp_session_stop(self->rtcp.session); + // Stop the RTCP session first (will send BYE) + if(self->rtcp.session) { + ret = trtp_rtcp_session_stop(self->rtcp.session); ret = trtp_rtcp_session_set_net_transport(self->rtcp.session, tsk_null); - } + } - // Free transport to force next call to start() to create new one with new sockets - if (self->transport) { - tnet_socket_t *master_copy = tsk_object_ref(self->transport->master); // "tnet_transport_shutdown" will free the master - tnet_transport_shutdown(self->transport); + // Free transport to force next call to start() to create new one with new sockets + if (self->transport) { + tnet_socket_t *master_copy = tsk_object_ref(self->transport->master); // "tnet_transport_shutdown" will free the master + tnet_transport_shutdown(self->transport); #if HAVE_SRTP - { - struct tnet_socket_s* sockets[] = { master_copy, self->rtcp.local_socket }; - // cancel DTLS handshaking timer - if (self->timer_mgr_global && self->dtls.timer_hanshaking.id != TSK_INVALID_TIMER_ID) { - tsk_timer_manager_cancel(self->timer_mgr_global, self->dtls.timer_hanshaking.id); - self->dtls.timer_hanshaking.id = TSK_INVALID_TIMER_ID; // invalidate timer id - self->dtls.timer_hanshaking.timeout = TRTP_DTLS_HANDSHAKING_TIMEOUT; // reset timeout - } - // destroy all SRTP contexts - _trtp_manager_srtp_set_enabled(self, self->srtp_type, sockets, sizeof(sockets) / sizeof(sockets[0]), tsk_false); - } + { + struct tnet_socket_s* sockets[] = { master_copy, self->rtcp.local_socket }; + // cancel DTLS handshaking timer + if (self->timer_mgr_global && self->dtls.timer_hanshaking.id != TSK_INVALID_TIMER_ID) { + tsk_timer_manager_cancel(self->timer_mgr_global, self->dtls.timer_hanshaking.id); + self->dtls.timer_hanshaking.id = TSK_INVALID_TIMER_ID; // invalidate timer id + self->dtls.timer_hanshaking.timeout = TRTP_DTLS_HANDSHAKING_TIMEOUT; // reset timeout + } + // destroy all SRTP contexts + _trtp_manager_srtp_set_enabled(self, self->srtp_type, sockets, sizeof(sockets) / sizeof(sockets[0]), tsk_false); + } #endif /* HAVE_SRTP */ - TSK_OBJECT_SAFE_FREE(master_copy); - TSK_OBJECT_SAFE_FREE(self->transport); - } - // Free RTCP info to make sure these values will be updated in next start() - TSK_OBJECT_SAFE_FREE(self->rtcp.local_socket); + TSK_OBJECT_SAFE_FREE(master_copy); + TSK_OBJECT_SAFE_FREE(self->transport); + } + // Free RTCP info to make sure these values will be updated in next start() + TSK_OBJECT_SAFE_FREE(self->rtcp.local_socket); TSK_OBJECT_SAFE_FREE(self->rtcp.session); self->rtcp.public_port = self->rtcp.remote_port = 0; TSK_FREE(self->rtcp.public_ip); TSK_FREE(self->rtcp.remote_ip); - // reset default values - self->is_symetric_rtp_checked = self->is_symetric_rtcp_checked = tsk_false; - self->is_ice_neg_ok = tsk_false; - self->is_ice_turn_active = tsk_false; - self->is_socket_disabled = tsk_false; + // reset default values + self->is_symetric_rtp_checked = self->is_symetric_rtcp_checked = tsk_false; + self->is_ice_neg_ok = tsk_false; + self->is_ice_turn_active = tsk_false; + self->is_socket_disabled = tsk_false; - self->is_started = tsk_false; + self->is_started = tsk_false; - tsk_safeobj_unlock(self); + tsk_safeobj_unlock(self); - return ret; + return ret; } @@ -1837,29 +1851,30 @@ int trtp_manager_stop(trtp_manager_t* self) // static tsk_object_t* trtp_manager_ctor(tsk_object_t * self, va_list * app) { - trtp_manager_t *manager = (trtp_manager_t*)self; - if(manager){ - manager->port_range.start = tmedia_defaults_get_rtp_port_range_start(); - manager->port_range.stop = tmedia_defaults_get_rtp_port_range_stop(); - manager->is_force_symetric_rtp = tmedia_defaults_get_rtp_symetric_enabled(); - manager->app_bw_max_upload = INT_MAX; // INT_MAX or <=0 means undefined - manager->app_bw_max_download = INT_MAX; // INT_MAX or <=0 means undefined - - /* srtp */ + trtp_manager_t *manager = (trtp_manager_t*)self; + if(manager) { + manager->port_range.start = tmedia_defaults_get_rtp_port_range_start(); + manager->port_range.stop = tmedia_defaults_get_rtp_port_range_stop(); + manager->is_force_symetric_rtp = tmedia_defaults_get_rtp_symetric_enabled(); + manager->app_bw_max_upload = INT_MAX; // INT_MAX or <=0 means undefined + manager->app_bw_max_download = INT_MAX; // INT_MAX or <=0 means undefined + manager->app_jitter_cng = 1.f; // Within [0, 1], in quality metric unit: 1 is best, 0 worst + + /* srtp */ #if HAVE_SRTP - manager->srtp_type = tmedia_defaults_get_srtp_type(); - manager->srtp_mode = tmedia_defaults_get_srtp_mode(); - manager->dtls.timer_hanshaking.id = TSK_INVALID_TIMER_ID; - manager->dtls.timer_hanshaking.timeout = TRTP_DTLS_HANDSHAKING_TIMEOUT; + manager->srtp_type = tmedia_defaults_get_srtp_type(); + manager->srtp_mode = tmedia_defaults_get_srtp_mode(); + manager->dtls.timer_hanshaking.id = TSK_INVALID_TIMER_ID; + manager->dtls.timer_hanshaking.timeout = TRTP_DTLS_HANDSHAKING_TIMEOUT; #endif /* HAVE_SRTP */ - /* rtp */ - manager->rtp.timestamp = rand()^rand(); - manager->rtp.seq_num = rand()^rand(); - manager->rtp.ssrc.local = rand()^rand()^(int)tsk_time_epoch(); + /* rtp */ + manager->rtp.timestamp = rand()^rand(); + manager->rtp.seq_num = rand()^rand(); + manager->rtp.ssrc.local = rand()^rand()^(int)tsk_time_epoch(); manager->rtp.dscp = TRTP_DSCP_RTP_DEFAULT; - /* rtcp */ + /* rtcp */ { // use MD5 string to avoid padding issues tsk_md5string_t md5 = { 0 }; @@ -1868,97 +1883,96 @@ static tsk_object_t* trtp_manager_ctor(tsk_object_t * self, va_list * app) tsk_strupdate(&manager->rtcp.cname, md5); } - /* timer */ - manager->timer_mgr_global = tsk_timer_mgr_global_ref(); + /* timer */ + manager->timer_mgr_global = tsk_timer_mgr_global_ref(); - tsk_safeobj_init(manager); - } - return self; + tsk_safeobj_init(manager); + } + return self; } static tsk_object_t* trtp_manager_dtor(tsk_object_t * self) -{ - trtp_manager_t *manager = self; - if(manager){ - /* callbacks */ - if (manager->ice_ctx) { - tnet_ice_ctx_rtp_callback(manager->ice_ctx, tsk_null, tsk_null); - } - if (manager->transport) { - - } - - /* stop */ - if (manager->is_started) { - trtp_manager_stop(manager); - } - - TSK_OBJECT_SAFE_FREE(manager->transport); - - TSK_FREE(manager->local_ip); - - /* rtp */ - TSK_FREE(manager->rtp.remote_ip); - TSK_FREE(manager->rtp.public_ip); - TSK_FREE(manager->rtp.serial_buffer.ptr); - - /* rtcp */ - TSK_OBJECT_SAFE_FREE(manager->rtcp.session); - TSK_FREE(manager->rtcp.remote_ip); - TSK_FREE(manager->rtcp.public_ip); - TSK_FREE(manager->rtcp.cname); - TSK_OBJECT_SAFE_FREE(manager->rtcp.local_socket); - - /* SRTP */ +{ + trtp_manager_t *manager = self; + if(manager) { + /* callbacks */ + if (manager->ice_ctx) { + tnet_ice_ctx_rtp_callback(manager->ice_ctx, tsk_null, tsk_null); + } + if (manager->transport) { + + } + + /* stop */ + if (manager->is_started) { + trtp_manager_stop(manager); + } + + TSK_OBJECT_SAFE_FREE(manager->transport); + + TSK_FREE(manager->local_ip); + + /* rtp */ + TSK_FREE(manager->rtp.remote_ip); + TSK_FREE(manager->rtp.public_ip); + TSK_FREE(manager->rtp.serial_buffer.ptr); + + /* rtcp */ + TSK_OBJECT_SAFE_FREE(manager->rtcp.session); + TSK_FREE(manager->rtcp.remote_ip); + TSK_FREE(manager->rtcp.public_ip); + TSK_FREE(manager->rtcp.cname); + TSK_OBJECT_SAFE_FREE(manager->rtcp.local_socket); + + /* SRTP */ #if HAVE_SRTP - { - int i; - - /* Timer */ - // cancel DTLS handshaking timer - if(manager->timer_mgr_global && manager->dtls.timer_hanshaking.id != TSK_INVALID_TIMER_ID){ - tsk_timer_manager_cancel(manager->timer_mgr_global, manager->dtls.timer_hanshaking.id); - manager->dtls.timer_hanshaking.id = TSK_INVALID_TIMER_ID; - } - - for(i = 0; i < 2; ++i){ - trtp_srtp_ctx_deinit(&manager->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][i]); - trtp_srtp_ctx_deinit(&manager->srtp_contexts[TRTP_SRTP_LINE_IDX_REMOTE][i]); - } - - /* SRTP-DTLS */ - TSK_FREE(manager->dtls.file_ca); - TSK_FREE(manager->dtls.file_pbk); - TSK_FREE(manager->dtls.file_pvk); - } + { + int i; + + /* Timer */ + // cancel DTLS handshaking timer + if(manager->timer_mgr_global && manager->dtls.timer_hanshaking.id != TSK_INVALID_TIMER_ID) { + tsk_timer_manager_cancel(manager->timer_mgr_global, manager->dtls.timer_hanshaking.id); + manager->dtls.timer_hanshaking.id = TSK_INVALID_TIMER_ID; + } + + for(i = 0; i < 2; ++i) { + trtp_srtp_ctx_deinit(&manager->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][i]); + trtp_srtp_ctx_deinit(&manager->srtp_contexts[TRTP_SRTP_LINE_IDX_REMOTE][i]); + } + + /* SRTP-DTLS */ + TSK_FREE(manager->dtls.file_ca); + TSK_FREE(manager->dtls.file_pbk); + TSK_FREE(manager->dtls.file_pvk); + } #endif /* HAVE_SRTP */ - /* Timer manager */ - if(manager->timer_mgr_global){ - tsk_timer_mgr_global_unref(&manager->timer_mgr_global); - } + /* Timer manager */ + if(manager->timer_mgr_global) { + tsk_timer_mgr_global_unref(&manager->timer_mgr_global); + } + + /* ICE */ + if (manager->ice_ctx) { + TSK_OBJECT_SAFE_FREE(manager->ice_ctx); + } - /* ICE */ - if (manager->ice_ctx) { - TSK_OBJECT_SAFE_FREE(manager->ice_ctx); - } - /* Proxy */ TSK_OBJECT_SAFE_FREE(manager->proxy.info); - tsk_safeobj_deinit(manager); + tsk_safeobj_deinit(manager); - TSK_DEBUG_INFO("*** RTP manager destroyed ***"); - } + TSK_DEBUG_INFO("*** RTP manager destroyed ***"); + } - return self; + return self; } -static const tsk_object_def_t trtp_manager_def_s = -{ - sizeof(trtp_manager_t), - trtp_manager_ctor, - trtp_manager_dtor, - tsk_null, +static const tsk_object_def_t trtp_manager_def_s = { + sizeof(trtp_manager_t), + trtp_manager_ctor, + trtp_manager_dtor, + tsk_null, }; const tsk_object_def_t *trtp_manager_def_t = &trtp_manager_def_s; diff --git a/tinyRTP/src/trtp_srtp.c b/tinyRTP/src/trtp_srtp.c index 5e2d033..e754a59 100755 --- a/tinyRTP/src/trtp_srtp.c +++ b/tinyRTP/src/trtp_srtp.c @@ -33,16 +33,16 @@ int trtp_srtp_ctx_internal_init(struct trtp_srtp_ctx_internal_xs* ctx, int32_t t char* key_str = ctx->key_str; err_status_t srtp_err; tsk_size_t size; - + if (!ctx) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - + if (ctx->initialized) { trtp_srtp_ctx_internal_deinit(ctx); } - + ctx->tag = tag; ctx->crypto_type = type; if (!ctx->have_valid_key) { // use same key to avoid unseless SRTP re-negs (also fix interop-issues against buggy clients -reINVITEs-) @@ -54,23 +54,21 @@ int trtp_srtp_ctx_internal_init(struct trtp_srtp_ctx_internal_xs* ctx, int32_t t key_str[size] = '\0'; ctx->have_valid_key = tsk_true; } - - switch(ctx->crypto_type){ - case HMAC_SHA1_80: - { - crypto_policy_set_aes_cm_128_hmac_sha1_80(&ctx->policy.rtp); - crypto_policy_set_aes_cm_128_hmac_sha1_80(&ctx->policy.rtcp); - break; - } - case HMAC_SHA1_32: - default: - { - crypto_policy_set_aes_cm_128_hmac_sha1_32(&ctx->policy.rtp); - crypto_policy_set_aes_cm_128_hmac_sha1_80(&ctx->policy.rtcp); // RTCP always 80 - break; - } + + switch(ctx->crypto_type) { + case HMAC_SHA1_80: { + crypto_policy_set_aes_cm_128_hmac_sha1_80(&ctx->policy.rtp); + crypto_policy_set_aes_cm_128_hmac_sha1_80(&ctx->policy.rtcp); + break; + } + case HMAC_SHA1_32: + default: { + crypto_policy_set_aes_cm_128_hmac_sha1_32(&ctx->policy.rtp); + crypto_policy_set_aes_cm_128_hmac_sha1_80(&ctx->policy.rtcp); // RTCP always 80 + break; } - + } + ctx->policy.key = (unsigned char*)ctx->key_bin; ctx->policy.ssrc.type = ssrc_any_outbound; ctx->policy.ssrc.value = ssrc; @@ -86,11 +84,11 @@ int trtp_srtp_ctx_internal_init(struct trtp_srtp_ctx_internal_xs* ctx, int32_t t int trtp_srtp_ctx_internal_deinit(struct trtp_srtp_ctx_internal_xs* ctx) { - if(!ctx){ + if(!ctx) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - if(ctx->initialized){ + if(ctx->initialized) { /*err_status_t srtp_err =*/ srtp_dealloc(ctx->session); memset(&ctx->policy, 0, sizeof(ctx->policy)); ctx->initialized = tsk_false; @@ -101,11 +99,11 @@ int trtp_srtp_ctx_internal_deinit(struct trtp_srtp_ctx_internal_xs* ctx) int trtp_srtp_ctx_init(trtp_srtp_ctx_xt* ctx, int32_t tag, trtp_srtp_crypto_type_t type, uint32_t ssrc) { int ret; - if(!ctx){ + if(!ctx) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - if((ret = trtp_srtp_ctx_internal_init(&ctx->rtp, tag, type, ssrc))){ + if((ret = trtp_srtp_ctx_internal_init(&ctx->rtp, tag, type, ssrc))) { return ret; } return trtp_srtp_ctx_internal_init(&ctx->rtcp, tag, type, ssrc); @@ -114,11 +112,11 @@ int trtp_srtp_ctx_init(trtp_srtp_ctx_xt* ctx, int32_t tag, trtp_srtp_crypto_type int trtp_srtp_ctx_deinit(trtp_srtp_ctx_xt* ctx) { int ret; - if(!ctx){ + if(!ctx) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - if((ret = trtp_srtp_ctx_internal_deinit(&ctx->rtp))){ + if((ret = trtp_srtp_ctx_internal_deinit(&ctx->rtp))) { return ret; } return trtp_srtp_ctx_internal_deinit(&ctx->rtcp); @@ -131,47 +129,46 @@ int trtp_srtp_match_line(const char* crypto_line, int32_t* tag, int32_t* crypto_ char* v = tsk_strtok_r(copyptr, " :|;", &saveptr); int32_t k = 0; int ret = -0xF0; - while(v){ - switch(k){ - case 0: - { - if(tag){ - *tag = atoi(v); - } - break; + while(v) { + switch(k) { + case 0: { + if(tag) { + *tag = atoi(v); } - case 1: - { - if(tsk_striequals(v, TRTP_SRTP_AES_CM_128_HMAC_SHA1_80)){ - if(crypto_type){ - *crypto_type = HMAC_SHA1_80; - } - } - else if(tsk_striequals(v, TRTP_SRTP_AES_CM_128_HMAC_SHA1_32)){ - if(crypto_type){ - *crypto_type = HMAC_SHA1_32; - } - } - else { - ret = -0xFF; goto bail; + break; + } + case 1: { + if(tsk_striequals(v, TRTP_SRTP_AES_CM_128_HMAC_SHA1_80)) { + if(crypto_type) { + *crypto_type = HMAC_SHA1_80; } - break; } - case 2: - { - if(!tsk_striequals(v, "inline")){ - ret = -0xFF; goto bail; + else if(tsk_striequals(v, TRTP_SRTP_AES_CM_128_HMAC_SHA1_32)) { + if(crypto_type) { + *crypto_type = HMAC_SHA1_32; } - break; } - case 3: - { - if(key && key_size){ - memset(key, 0, key_size); - memcpy(key, v, TSK_MIN(key_size, tsk_strlen(v))); - } - ret = 0; goto bail; + else { + ret = -0xFF; + goto bail; + } + break; + } + case 2: { + if(!tsk_striequals(v, "inline")) { + ret = -0xFF; + goto bail; + } + break; + } + case 3: { + if(key && key_size) { + memset(key, 0, key_size); + memcpy(key, v, TSK_MIN(key_size, tsk_strlen(v))); } + ret = 0; + goto bail; + } } ++k; v = tsk_strtok_r(tsk_null, " :|;", &saveptr); @@ -184,11 +181,11 @@ bail: tsk_size_t trtp_srtp_get_local_contexts(trtp_manager_t* rtp_mgr, const struct trtp_srtp_ctx_xs ** contexts, tsk_size_t contexts_count) { tsk_size_t ret = 0; - if(!rtp_mgr || !contexts){ + if(!rtp_mgr || !contexts) { TSK_DEBUG_ERROR("Invalid parameter"); return 0; } - + if (contexts_count > ret && rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80].rtp.initialized) { contexts[ret++] = &rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80]; } @@ -207,46 +204,45 @@ int trtp_srtp_set_crypto(struct trtp_manager_s* rtp_mgr, const char* crypto_line err_status_t srtp_err; int32_t tag, crypto_type; char key_str[SRTP_MAX_KEY_LEN + 1]; - + memset(key_str, 0, sizeof(key_str)); - + if ((ret = trtp_srtp_match_line(crypto_line, &tag, &crypto_type, key_str, sizeof(key_str) - 1))) { return ret; } - + srtp_ctx = &rtp_mgr->srtp_contexts[idx][crypto_type]; ret = trtp_srtp_ctx_deinit(srtp_ctx); - + srtp_ctx->rtp.tag = tag; srtp_ctx->rtp.crypto_type = (trtp_srtp_crypto_type_t)crypto_type; memcpy(srtp_ctx->rtp.key_str, key_str, sizeof(srtp_ctx->rtp.key_str)); - - switch(srtp_ctx->rtp.crypto_type){ - case HMAC_SHA1_80: - { - crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->rtp.policy.rtp); - crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->rtp.policy.rtcp); - if (idx == TRTP_SRTP_LINE_IDX_REMOTE) { - trtp_srtp_ctx_deinit(&rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32]); - rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80].rtp.tag = + + switch(srtp_ctx->rtp.crypto_type) { + case HMAC_SHA1_80: { + crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->rtp.policy.rtp); + crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->rtp.policy.rtcp); + if (idx == TRTP_SRTP_LINE_IDX_REMOTE) { + trtp_srtp_ctx_deinit(&rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32]); + rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80].rtp.tag = rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80].rtcp.tag = srtp_ctx->rtp.tag; - } - break; } - case HMAC_SHA1_32: - { - crypto_policy_set_aes_cm_128_hmac_sha1_32(&srtp_ctx->rtp.policy.rtp); - crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->rtp.policy.rtcp); // RTCP always 80 - if (idx == TRTP_SRTP_LINE_IDX_REMOTE) { - trtp_srtp_ctx_deinit(&rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80]); - rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32].rtp.tag = + break; + } + case HMAC_SHA1_32: { + crypto_policy_set_aes_cm_128_hmac_sha1_32(&srtp_ctx->rtp.policy.rtp); + crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->rtp.policy.rtcp); // RTCP always 80 + if (idx == TRTP_SRTP_LINE_IDX_REMOTE) { + trtp_srtp_ctx_deinit(&rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_80]); + rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32].rtp.tag = rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32].rtcp.tag = srtp_ctx->rtp.tag; - } - break; } - default: break; + break; + } + default: + break; } - + key_bin = (unsigned char*)srtp_ctx->rtp.key_bin; tsk_base64_decode((const uint8_t*)srtp_ctx->rtp.key_str, (tsk_size_t)tsk_strlen(srtp_ctx->rtp.key_str), (char**)&key_bin); srtp_ctx->rtp.policy.key = key_bin; @@ -270,40 +266,38 @@ int trtp_srtp_set_key_and_salt(trtp_manager_t* rtp_mgr, trtp_srtp_crypto_type_t TSK_DEBUG_ERROR("Invalid parameter"); return -1; } - + srtp_ctx = is_rtp ? &rtp_mgr->srtp_contexts[idx][crypto_type].rtp : &rtp_mgr->srtp_contexts[idx][crypto_type].rtcp; if ((ret = trtp_srtp_ctx_internal_deinit(srtp_ctx))) { return ret; } - + switch ((srtp_ctx->crypto_type = crypto_type)) { - case HMAC_SHA1_80: - default: - { - crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtp); - crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtcp); - break; - } - case HMAC_SHA1_32: - { - crypto_policy_set_aes_cm_128_hmac_sha1_32(&srtp_ctx->policy.rtp); - crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtcp); // always 80 - break; - } + case HMAC_SHA1_80: + default: { + crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtp); + crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtcp); + break; + } + case HMAC_SHA1_32: { + crypto_policy_set_aes_cm_128_hmac_sha1_32(&srtp_ctx->policy.rtp); + crypto_policy_set_aes_cm_128_hmac_sha1_80(&srtp_ctx->policy.rtcp); // always 80 + break; + } } - + memcpy(srtp_ctx->key_bin, key, key_size); #if HAVE_APPEND_SALT_TO_KEY append_salt_to_key(srtp_ctx->key_bin, key_size, (void*)salt, salt_size); #else memcpy(&srtp_ctx->key_bin[key_size], salt, salt_size); #endif - + srtp_ctx->policy.key = (unsigned char *)srtp_ctx->key_bin; srtp_ctx->policy.ssrc.type = idx == TRTP_SRTP_LINE_IDX_REMOTE ? ssrc_any_inbound : ssrc_any_outbound; srtp_ctx->policy.window_size = 2048; srtp_ctx->policy.allow_repeat_tx = 1; - if((srtp_err = srtp_create(&srtp_ctx->session, &srtp_ctx->policy)) != err_status_ok){ + if((srtp_err = srtp_create(&srtp_ctx->session, &srtp_ctx->policy)) != err_status_ok) { TSK_DEBUG_ERROR("srtp_create() failed: %d", srtp_err); return -3; } @@ -316,7 +310,7 @@ tsk_bool_t trtp_srtp_is_initialized(trtp_manager_t* rtp_mgr) if (!rtp_mgr) { return tsk_false; } - return ((rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][0].rtp.initialized || rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][1].rtp.initialized) + return ((rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][0].rtp.initialized || rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][1].rtp.initialized) && rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_REMOTE][0].rtp.initialized); } |