From 1ebf5a5fcda0c9154e22ed02404fd46525a7fd9f Mon Sep 17 00:00:00 2001 From: bossiel Date: Wed, 10 Aug 2011 22:59:15 +0000 Subject: Move deprecated v1.0 from trunk to branches --- tinyRTP/src/rtcp/trtp_rtcp_session.c | 29 ++ tinyRTP/src/rtp/trtp_rtp_header.c | 224 +++++++++++++++ tinyRTP/src/rtp/trtp_rtp_packet.c | 194 +++++++++++++ tinyRTP/src/rtp/trtp_rtp_session.c | 29 ++ tinyRTP/src/trtp.c | 30 ++ tinyRTP/src/trtp_manager.c | 518 +++++++++++++++++++++++++++++++++++ 6 files changed, 1024 insertions(+) create mode 100644 tinyRTP/src/rtcp/trtp_rtcp_session.c create mode 100644 tinyRTP/src/rtp/trtp_rtp_header.c create mode 100644 tinyRTP/src/rtp/trtp_rtp_packet.c create mode 100644 tinyRTP/src/rtp/trtp_rtp_session.c create mode 100644 tinyRTP/src/trtp.c create mode 100644 tinyRTP/src/trtp_manager.c (limited to 'tinyRTP/src') diff --git a/tinyRTP/src/rtcp/trtp_rtcp_session.c b/tinyRTP/src/rtcp/trtp_rtcp_session.c new file mode 100644 index 0000000..5d97083 --- /dev/null +++ b/tinyRTP/src/rtcp/trtp_rtcp_session.c @@ -0,0 +1,29 @@ +/* +* Copyright (C) 2009-2010 Mamadou Diop. +* +* Contact: Mamadou Diop +* +* 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. +* +*/ +/**@file trtp_rtcp_session.c + * @brief RTCP session. + * + * @author Mamadou Diop + * + * @date Created: Sat Nov 8 16:54:58 2009 mdiop + */ +#include "tinyrtp/rtcp/trtp_rtcp_session.h" diff --git a/tinyRTP/src/rtp/trtp_rtp_header.c b/tinyRTP/src/rtp/trtp_rtp_header.c new file mode 100644 index 0000000..65fffe3 --- /dev/null +++ b/tinyRTP/src/rtp/trtp_rtp_header.c @@ -0,0 +1,224 @@ +/* +* Copyright (C) 2009-2010 Mamadou Diop. +* +* Contact: Mamadou Diop +* +* 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. +* +*/ +/**@file trtp_rtp_header.c + * @brief RTP header. + * + * @author Mamadou Diop + * + * @date Created: Sat Nov 8 16:54:58 2009 mdiop + */ +#include "tinyrtp/rtp/trtp_rtp_header.h" + +#include "tnet_endianness.h" + +#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 | + | .... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +/* Create new RTP header */ +trtp_rtp_header_t* trtp_rtp_header_create_null() +{ + 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 = tsk_object_new(trtp_rtp_header_def_t))){ + 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; +} + +/** Serialize rtp header object into binary buffer */ +tsk_buffer_t* trtp_rtp_header_serialize(const trtp_rtp_header_t *self) +{ + tsk_buffer_t* buffer; + uint8_t* data; + tsk_size_t i; + + if(!self){ + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + if(!(data = tsk_calloc(TRTP_RTP_HEADER_MIN_SIZE + (4 * self->csrc_count), 1))){ + TSK_DEBUG_ERROR("Failed to allocate buffer"); + return tsk_null; + } + + /* Octet-0: version(2), Padding(1), Extension(1), CSRC Count(4) */ + data[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) */ + data[1] = (((uint8_t)self->marker)<< 7) | + ((uint8_t)self->payload_type); + /* Octet-2-3: Sequence number (16) */ + *((uint16_t*)&data[2]) = tnet_htons(self->seq_num); + /* Octet-4-5-6-7: timestamp (32) */ + *((uint32_t*)&data[4]) = tnet_htonl(self->timestamp); + /* Octet-8-9-10-11: SSRC (32) */ + *((uint32_t*)&data[8]) = tnet_htonl(self->ssrc); + + /* Octet-12-13-14-15-****: CSRC */ + for(i=0; icsrc_count; i++){ + *((uint32_t*)&data[12+i]) = tnet_htonl(self->csrc[i]); + } + + if(!(buffer = tsk_buffer_create_null())){ + TSK_DEBUG_ERROR("Failed to create new buffer"); + TSK_FREE(data); + return tsk_null; + } + else{ + tsk_buffer_takeownership(buffer, (void**)&data, TRTP_RTP_HEADER_MIN_SIZE + (4 * self->csrc_count)); + } + + 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 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 = tnet_ntohs(*((uint16_t*)pdata)); + // skip octets + pdata += 2; + + /* timestamp (32bits) */ + header->timestamp = tnet_ntohl(*((uint32_t*)pdata)); + // skip octets + pdata += 4; + + /* synchronization source (SSRC) identifier (32bits) */ + header->ssrc = tnet_ntohl(*((uint32_t*)pdata)); + // skip octets + pdata += 4; + + /* contributing source (CSRC) identifiers */ + for(i=0; icsrc[i] = tnet_ntohl(*((uint32_t*)pdata)); + } + + return header; +} + + + + + + +//================================================================================================= +// RTP header object definition +// +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; +} + +static tsk_object_t* trtp_rtp_header_dtor(tsk_object_t * self) +{ + trtp_rtp_header_t *header = self; + if(header){ + } + + 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, +}; +const tsk_object_def_t *trtp_rtp_header_def_t = &trtp_rtp_header_def_s; \ No newline at end of file diff --git a/tinyRTP/src/rtp/trtp_rtp_packet.c b/tinyRTP/src/rtp/trtp_rtp_packet.c new file mode 100644 index 0000000..2f2fcb4 --- /dev/null +++ b/tinyRTP/src/rtp/trtp_rtp_packet.c @@ -0,0 +1,194 @@ +/* +* Copyright (C) 2009-2010 Mamadou Diop. +* +* Contact: Mamadou Diop +* +* 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. +* +*/ +/**@file trtp_rtp_packet.c + * @brief RTP packet. + * + * @author Mamadou Diop + * + * @date Created: Sat Nov 8 16:54:58 2009 mdiop + */ +#include "tinyrtp/rtp/trtp_rtp_packet.h" + +#include "tnet_endianness.h" + +#include "tsk_memory.h" +#include "tsk_debug.h" + +#include /* memcpy() */ + +/** Create new RTP packet */ +trtp_rtp_packet_t* trtp_rtp_packet_create_null() +{ + 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; +} + +/** Serialize rtp packet object into binary buffer */ +tsk_buffer_t* trtp_rtp_packet_serialize(const trtp_rtp_packet_t *self) +{ + tsk_buffer_t* buffer = tsk_null; + + if(!self || !self->header){ + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + + if(!(buffer = trtp_rtp_header_serialize(self->header))){ + TSK_DEBUG_ERROR("Failed to serialize the RTP header"); + return tsk_null; + } + else{ + /* extension */ + if(self->extension.data && self->extension.size && self->header->extension){ + tsk_buffer_append(buffer, self->extension.data, self->extension.size); + } + /* append payload */ + tsk_buffer_append(buffer, self->payload.data_const ? self->payload.data_const : self->payload.data, self->payload.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 * 4)); + 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 */){ + pdata += 2; /* skip "defined by profile" field */ + packet->extension.size = 4 /* first two 16-bit fields */ + (tnet_ntohs(*((uint16_t*)pdata)) * 4/*words(32-bit)*/); + pdata += 2; /* skip "length" field */ + if((packet->extension.data = tsk_calloc(packet->extension.size, sizeof(uint8_t)))){ + memcpy(packet->extension.data, (pdata - 4), 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->payload.size); + } + else{ + TSK_DEBUG_ERROR("Failed to allocate new buffer"); + packet->payload.size = 0; + } + } + + return packet; +} + + + + + + + + + +//================================================================================================= +// RTP packet object definition +// +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; +} + +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; +} + +static const tsk_object_def_t trtp_rtp_packet_def_s = +{ + sizeof(trtp_rtp_packet_t), + trtp_rtp_packet_ctor, + trtp_rtp_packet_dtor, + tsk_null, +}; +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 new file mode 100644 index 0000000..73e4bab --- /dev/null +++ b/tinyRTP/src/rtp/trtp_rtp_session.c @@ -0,0 +1,29 @@ +/* +* Copyright (C) 2009-2010 Mamadou Diop. +* +* Contact: Mamadou Diop +* +* 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. +* +*/ +/**@file trtp_rtp_session.c + * @brief RTP session. + * + * @author Mamadou Diop + * + * @date Created: Sat Nov 8 16:54:58 2009 mdiop + */ +#include "tinyrtp/rtp/trtp_rtp_session.h" \ No newline at end of file diff --git a/tinyRTP/src/trtp.c b/tinyRTP/src/trtp.c new file mode 100644 index 0000000..cf87148 --- /dev/null +++ b/tinyRTP/src/trtp.c @@ -0,0 +1,30 @@ +/* +* Copyright (C) 2009-2010 Mamadou Diop. +* +* Contact: Mamadou Diop +* +* 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. +* +*/ +/**@file trtp.h + * @brief tinyRTP (Real-time Transport Protocol) as per RFC 3550. + * + * @author Mamadou Diop + * + * @date Created: Sat Nov 8 16:54:58 2009 mdiop + */ +#include "tinyrtp/trtp.h" + diff --git a/tinyRTP/src/trtp_manager.c b/tinyRTP/src/trtp_manager.c new file mode 100644 index 0000000..9b5d6c8 --- /dev/null +++ b/tinyRTP/src/trtp_manager.c @@ -0,0 +1,518 @@ +/* +* Copyright (C) 2009-2010 Mamadou Diop. +* +* Contact: Mamadou Diop +* +* 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. +* +*/ +/**@file trtp_manager.c + * @brief RTP/RTCP manager. + * + * @author Mamadou Diop + * + * @date Created: Sat Nov 8 16:54:58 2009 mdiop + */ +#include "tinyrtp/trtp_manager.h" + +#include "tinyrtp/rtp/trtp_rtp_packet.h" + +#include "tsk_string.h" +#include "tsk_memory.h" +#include "tsk_debug.h" + +#define TINY_RCVBUF (256/2/*Will be doubled and min on linux is 256*/) /* tiny buffer used to disable receiving */ +#define BIG_RCVBUF 64000 +#define BIG_SNDBUF 64000 + +// TODO: Add support for outbound DTMF (http://www.ietf.org/rfc/rfc2833.txt) + +/* ======================= Transport callback ========================== */ +static int trtp_transport_layer_cb(const tnet_transport_event_t* e) +{ + int ret = -1; + const trtp_manager_t *manager = e->callback_data; + trtp_rtp_packet_t* packet = tsk_null; + + switch(e->type){ + case event_data: { + break; + } + case event_closed: + case event_connected: + default:{ + return 0; + } + } + + // + // RTCP + // + if(manager->rtcp.local_socket && manager->rtcp.local_socket->fd == e->local_fd){ + TSK_DEBUG_INFO("RTCP packet"); + } + // + // RTP + // + else if(manager->transport->master && (manager->transport->master->fd == e->local_fd)){ + if(manager->rtp.callback){ + if((packet = trtp_rtp_packet_deserialize(e->data, e->size))){ + manager->rtp.callback(manager->rtp.callback_data, packet); + TSK_OBJECT_SAFE_FREE(packet); + } + else{ + TSK_DEBUG_ERROR("RTP packet === NOK"); + goto bail; + } + } + } + // + // UNKNOWN + // + else{ + TSK_DEBUG_INFO("XXXX packet"); + goto bail; + } + +bail: + + return ret; +} + + + +/** Create RTP/RTCP manager */ +trtp_manager_t* trtp_manager_create(tsk_bool_t enable_rtcp, const char* local_ip, tsk_bool_t ipv6) +{ + trtp_manager_t* manager; + if((manager = tsk_object_new(trtp_manager_def_t))){ + manager->enable_rtcp = enable_rtcp; + manager->local_ip = tsk_strdup(local_ip); + manager->ipv6 = ipv6; + manager->rtp.payload_type = 127; + } + return manager; +} + +/** Prepares the RTP/RTCP manager */ +int trtp_manager_prepare(trtp_manager_t* self) +{ + uint8_t retry_count = 7; + tnet_socket_type_t socket_type; + + if(!self){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(self->transport){ + TSK_DEBUG_ERROR("RTP/RTCP manager already prepared"); + return -2; + } + + socket_type = self->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 */ +#if 0 + tnet_port_t local_port = 6060; +#else + tnet_port_t local_port = ((rand() % 64510) + 1025); +#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, "RTP/RTCP Manager"))){ + /* set callback function */ + tnet_transport_set_callback(self->transport, trtp_transport_layer_cb, self); + tsk_strupdate(&self->rtp.public_ip, self->transport->master->ip); + self->rtp.public_port = local_port; + /* Disable receiving until we start the transport (To avoid buffering) */ + { + int err, optval = 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); + } + } + } + else { + TSK_DEBUG_ERROR("Failed to create RTP/RTCP Transport"); + return -3; + } + + /* RTCP */ + if(self->enable_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; + } + else{ + tsk_strupdate(&self->rtcp.public_ip, self->rtcp.local_socket->ip); + self->rtcp.public_port = local_port + 1; + } + } + + TSK_DEBUG_INFO("RTP/RTCP manager[End]: Trying to bind to random ports"); + break; + } + + return 0; +} + +/** Indicates whether the manager is already prepared or not */ +tsk_bool_t trtp_manager_is_prepared(trtp_manager_t* self) +{ + if(!self){ + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_false; + } + return self->transport == tsk_null ? tsk_false : tsk_true; +} + +/** Sets NAT Traversal context */ +int trtp_manager_set_natt_ctx(trtp_manager_t* self, tnet_nat_context_handle_t* natt_ctx) +{ + int ret; + + if(!self || !self->transport){ + 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; + } + } + return ret; +} + +/** Sets RTP callback */ +int trtp_manager_set_rtp_callback(trtp_manager_t* self, trtp_manager_rtp_cb_f callback, const void* callback_data) +{ + if(!self){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + self->rtp.callback = callback; + self->rtp.callback_data = callback_data; + + 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; +} + +/** 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; + } + 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; + } + tsk_strupdate(&self->rtcp.remote_ip, remote_ip); + self->rtcp.remote_port = remote_port; + return 0; +} + +/** Starts the RTP/RTCP manager */ +int trtp_manager_start(trtp_manager_t* self) +{ + int ret = 0; + + if(!self){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(self->started){ + TSK_DEBUG_WARN("RTP/RTCP manager already started"); + return 0; + } + + if(!self->transport || !self->transport->master){ + TSK_DEBUG_ERROR("RTP/RTCP manager not prepared"); + return -2; + } + + /* Change RCV and SND buffer sizes */ + { + char buff[1024]; + int rcv_buf = BIG_RCVBUF, snd_buf = BIG_SNDBUF; + 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 = recv(self->transport->master->fd, buff, sizeof(buff), 0)) > 0){ + TSK_DEBUG_INFO("Flushing RTP Buffer %d", ret); + } + TSK_DEBUG_INFO("End flushing RTP socket"); + 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; + } + } + + /* start the transport */ + if((ret = tnet_transport_start(self->transport))){ + TSK_DEBUG_ERROR("Failed to start the RTP/RTCP transport"); + return ret; + } + + /* RTP */ + 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_DEBUG_ERROR("Invalid RTP host:port [%s:%u]", self->rtp.remote_ip, self->rtp.remote_port); + return ret; + } + + /* RTCP */ + if(self->enable_rtcp){ + if(!self->rtcp.remote_ip){ + self->rtcp.remote_ip = tsk_strdup(self->rtp.remote_ip); + } + if(!self->rtcp.remote_port){ + self->rtcp.remote_port = self->rtp.remote_port; + } + } + if(self->enable_rtcp && (ret = tnet_sockaddr_init(self->rtcp.remote_ip, self->rtcp.remote_port, self->rtcp.local_socket->type, &self->rtp.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->enable_rtcp && (ret = tnet_transport_add_socket(self->transport, self->rtcp.local_socket->fd, self->rtcp.local_socket->type, tsk_false, tsk_true/* only Meaningful for tls*/))){ + TSK_DEBUG_ERROR("Failed to add RTCP socket"); + /* do not exit */ + } + + +#if 0 + { + int flags; + if((flags = fcntl(self->transport->master->fd, F_GETFL, 0)) < 0) { + TNET_PRINT_LAST_ERROR("fcntl(F_GETFL) have failed."); + } + else{ + if(fcntl(self->transport->master->fd, F_SETFL, flags | O_DIRECT) < 0){ + TNET_PRINT_LAST_ERROR("fcntl(O_DIRECT) have failed."); + } + } + } +#endif + self->started = tsk_true; + + return 0; +} + +/* 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 */ +int 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_buffer_t* buffer; + int ret = -1; + + if(!self || !data || !size){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(!self->started){ + //--TSK_DEBUG_ERROR("RTP/RTCP manager should be started before trying to send data"); + return -2; + } + + /* create packet with header */ + if(!(packet = trtp_rtp_packet_create(self->rtp.ssrc, self->rtp.seq_num++, self->rtp.timestamp, self->rtp.payload_type, marker))){ + return -3; + } + 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; + } +#else + packet->payload.data_const = data; + packet->payload.size = size; +#endif + + /* serialize and send over the network */ + if((buffer = trtp_rtp_packet_serialize(packet))){ + if(/* number of bytes sent */tnet_sockfd_sendto(self->transport->master->fd, (const struct sockaddr *)&self->rtp.remote_addr, buffer->data, buffer->size)){ + ret = 0; + } + TSK_OBJECT_SAFE_FREE(buffer); + } + else{ + TSK_DEBUG_ERROR("Failed to serialize RTP packet"); + ret = -5; + goto bail; + } + +bail: + TSK_OBJECT_SAFE_FREE(packet); + return ret; +} + +int trtp_manager_send_rtp_2(trtp_manager_t* self, const struct trtp_rtp_packet_s* packet) +{ + tsk_buffer_t* buffer; + int ret; + + if(!self || !packet){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + /* serialize and send over the network */ + if((buffer = trtp_rtp_packet_serialize(packet))){ + if(/* number of bytes sent */tnet_sockfd_sendto(self->transport->master->fd, (const struct sockaddr *)&self->rtp.remote_addr, buffer->data, buffer->size)){ + ret = 0; + } + TSK_OBJECT_SAFE_FREE(buffer); + } + else{ + TSK_DEBUG_ERROR("Failed to serialize RTP packet"); + ret = -5; + } + return ret; +} + +/** Stops the RTP/RTCP manager */ +int trtp_manager_stop(trtp_manager_t* self) +{ + int ret; + + if(!self){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(!self->started){ + TSK_DEBUG_WARN("RTP/RTCP manager not started"); + return 0; + } + + if(!self->transport){ + TSK_DEBUG_ERROR("RTP/RTCP manager not prepared"); + return -2; + } + + if(!(ret = tnet_transport_shutdown(self->transport))){ + self->started = tsk_false; + } + + return ret; +} + + + + +//================================================================================================= +// RTP manager object definition +// +static tsk_object_t* trtp_manager_ctor(tsk_object_t * self, va_list * app) +{ + trtp_manager_t *manager = self; + if(manager){ + /* rtp */ + manager->rtp.timestamp = rand()^rand(); + manager->rtp.seq_num = rand()^rand(); + manager->rtp.ssrc = rand()^rand(); + + /* rtcp */ + } + return self; +} + +static tsk_object_t* trtp_manager_dtor(tsk_object_t * self) +{ + trtp_manager_t *manager = self; + if(manager){ + /* stop */ + if(manager->started){ + trtp_manager_stop(manager); + } + + /* rtp */ + TSK_FREE(manager->rtp.remote_ip); + TSK_FREE(manager->rtp.public_ip); + + /* rtcp */ + TSK_FREE(manager->rtcp.remote_ip); + TSK_FREE(manager->rtcp.public_ip); + TSK_OBJECT_SAFE_FREE(manager->rtcp.local_socket); + + TSK_FREE(manager->local_ip); + TSK_OBJECT_SAFE_FREE(manager->transport); + } + + return self; +} + +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; -- cgit v1.1