summaryrefslogtreecommitdiffstats
path: root/tinyRTP
diff options
context:
space:
mode:
Diffstat (limited to 'tinyRTP')
-rw-r--r--tinyRTP/Makefile.am49
-rw-r--r--tinyRTP/droid-makefile59
-rw-r--r--tinyRTP/include/tinyrtp.h43
-rw-r--r--tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_header.h62
-rw-r--r--tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_packet.h74
-rw-r--r--tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_rblock.h59
-rw-r--r--tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report.h32
-rw-r--r--tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_bye.h45
-rw-r--r--tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_fb.h152
-rw-r--r--tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_rr.h54
-rw-r--r--tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_sdes.h53
-rw-r--r--tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_sr.h62
-rw-r--r--tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_xr.h32
-rw-r--r--tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_sdes_chunck.h56
-rw-r--r--tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_sdes_item.h71
-rw-r--r--tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_session.h70
-rw-r--r--tinyRTP/include/tinyrtp/rtp/trtp_rtp_header.h85
-rw-r--r--tinyRTP/include/tinyrtp/rtp/trtp_rtp_packet.h74
-rw-r--r--tinyRTP/include/tinyrtp/rtp/trtp_rtp_session.h42
-rw-r--r--tinyRTP/include/tinyrtp/trtp.h38
-rw-r--r--tinyRTP/include/tinyrtp/trtp_manager.h227
-rw-r--r--tinyRTP/include/tinyrtp/trtp_srtp.h131
-rw-r--r--tinyRTP/include/tinyrtp_config.h92
-rw-r--r--tinyRTP/src/rtcp/trtp_rtcp_header.c134
-rw-r--r--tinyRTP/src/rtcp/trtp_rtcp_packet.c255
-rw-r--r--tinyRTP/src/rtcp/trtp_rtcp_rblock.c153
-rw-r--r--tinyRTP/src/rtcp/trtp_rtcp_report.c21
-rw-r--r--tinyRTP/src/rtcp/trtp_rtcp_report_bye.c225
-rw-r--r--tinyRTP/src/rtcp/trtp_rtcp_report_fb.c651
-rw-r--r--tinyRTP/src/rtcp/trtp_rtcp_report_rr.c232
-rw-r--r--tinyRTP/src/rtcp/trtp_rtcp_report_sdes.c214
-rw-r--r--tinyRTP/src/rtcp/trtp_rtcp_report_sr.c270
-rw-r--r--tinyRTP/src/rtcp/trtp_rtcp_report_xr.c21
-rw-r--r--tinyRTP/src/rtcp/trtp_rtcp_sdes_chunck.c190
-rw-r--r--tinyRTP/src/rtcp/trtp_rtcp_sdes_item.c148
-rw-r--r--tinyRTP/src/rtcp/trtp_rtcp_session.c1584
-rw-r--r--tinyRTP/src/rtp/trtp_rtp_header.c259
-rw-r--r--tinyRTP/src/rtp/trtp_rtp_packet.c260
-rw-r--r--tinyRTP/src/rtp/trtp_rtp_session.c29
-rw-r--r--tinyRTP/src/trtp.c30
-rw-r--r--tinyRTP/src/trtp_manager.c1960
-rw-r--r--tinyRTP/src/trtp_srtp.c332
-rw-r--r--tinyRTP/test/test.c65
-rw-r--r--tinyRTP/test/test.vcproj200
-rw-r--r--tinyRTP/test/test_manager.h69
-rw-r--r--tinyRTP/test/test_parser.h331
-rw-r--r--tinyRTP/tinyRTP.pc.in14
-rw-r--r--tinyRTP/tinyRTP.sln92
-rw-r--r--tinyRTP/tinyRTP.vcproj384
-rw-r--r--tinyRTP/version.rc102
50 files changed, 9887 insertions, 0 deletions
diff --git a/tinyRTP/Makefile.am b/tinyRTP/Makefile.am
new file mode 100644
index 0000000..02fc587
--- /dev/null
+++ b/tinyRTP/Makefile.am
@@ -0,0 +1,49 @@
+lib_LTLIBRARIES = libtinyRTP.la
+libtinyRTP_la_LIBADD = ../tinySAK/libtinySAK.la ../tinyNET/libtinyNET.la ../tinyMEDIA/libtinyMEDIA.la
+libtinyRTP_la_CPPFLAGS = -I../tinySAK/src -I../tinyNET/src -I../tinyMEDIA/include -Iinclude
+
+if USE_SRTP
+libtinyRTP_la_LIBADD += ${LIBSRTP_LIBADD}
+libtinyRTP_la_CPPFLAGS += -DHAVE_SRTP=1
+endif
+
+libtinyRTP_la_SOURCES = \
+ src/trtp.c \
+ src/trtp_manager.c \
+ src/trtp_srtp.c
+
+libtinyRTP_la_SOURCES += src/rtcp/trtp_rtcp_header.c \
+ src/rtcp/trtp_rtcp_packet.c \
+ src/rtcp/trtp_rtcp_rblock.c \
+ src/rtcp/trtp_rtcp_report.c \
+ src/rtcp/trtp_rtcp_report_bye.c \
+ src/rtcp/trtp_rtcp_report_fb.c \
+ src/rtcp/trtp_rtcp_report_rr.c \
+ src/rtcp/trtp_rtcp_report_sdes.c \
+ src/rtcp/trtp_rtcp_report_sr.c \
+ src/rtcp/trtp_rtcp_report_xr.c \
+ src/rtcp/trtp_rtcp_sdes_chunck.c \
+ src/rtcp/trtp_rtcp_sdes_item.c \
+ src/rtcp/trtp_rtcp_session.c
+
+libtinyRTP_la_SOURCES += src/rtp/trtp_rtp_header.c \
+ src/rtp/trtp_rtp_packet.c \
+ src/rtp/trtp_rtp_session.c
+
+
+libtinyRTP_la_LDFLAGS = $LDFLAGS -no-undefined
+if TARGET_OS_IS_ANDROID
+libtinyRTP_la_LDFLAGS += -static
+endif
+
+_includedir = $(includedir)/tinyrtp
+_include_HEADERS = include/*.h
+__includedir = $(includedir)/tinyrtp/tinyrtp
+__include_HEADERS = include/tinyrtp/*.h
+rtcp_includedir = $(includedir)/tinyrtp/tinyrtp/rtcp
+rtcp_include_HEADERS = include/tinyrtp/rtcp/*.h
+rtp_includedir = $(includedir)/tinyrtp/tinyrtp/rtp
+rtp_include_HEADERS = include/tinyrtp/rtp/*.h
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = tinyRTP.pc \ No newline at end of file
diff --git a/tinyRTP/droid-makefile b/tinyRTP/droid-makefile
new file mode 100644
index 0000000..a56b89f
--- /dev/null
+++ b/tinyRTP/droid-makefile
@@ -0,0 +1,59 @@
+APP := lib$(PROJECT)_$(MARCH).$(EXT)
+
+# SRTP (Default: enabled)
+ifeq ($(SRTP),no)
+ LIBSRTP_CFLAGS := -DHAVE_SRTP=0
+else
+ LIBSRTP_CFLAGS := -DHAVE_SRTP=1
+ LIBSRTP_LDFLAGS := -lsrtp
+endif
+
+THIRDPARTIES_INC := ../thirdparties/android/include
+CFLAGS := $(CFLAGS_LIB) -I$(THIRDPARTIES_INC) $(LIBSRTP_CFLAGS) -I../tinySAK/src -I../tinyNET/src -I./include -I../tinyMEDIA/include
+LDFLAGS := $(LDFLAGS_LIB) $(LIBSRTP_LDFLAGS) -ltinySAK_$(MARCH) -ltinyNET_$(MARCH) -ltinyMEDIA_$(MARCH)
+
+all: $(APP)
+
+OBJS = \
+ src/trtp.o \
+ src/trtp_manager.o \
+ src/trtp_srtp.o
+
+## RTCP
+OBJS += src/rtcp/trtp_rtcp_header.o \
+ src/rtcp/trtp_rtcp_packet.o \
+ src/rtcp/trtp_rtcp_rblock.o \
+ src/rtcp/trtp_rtcp_report.o \
+ src/rtcp/trtp_rtcp_report_bye.o \
+ src/rtcp/trtp_rtcp_report_fb.o \
+ src/rtcp/trtp_rtcp_report_rr.o \
+ src/rtcp/trtp_rtcp_report_sdes.o \
+ src/rtcp/trtp_rtcp_report_sr.o \
+ src/rtcp/trtp_rtcp_report_xr.o \
+ src/rtcp/trtp_rtcp_sdes_chunck.o \
+ src/rtcp/trtp_rtcp_sdes_item.o \
+ src/rtcp/trtp_rtcp_session.o
+
+## RTP
+OBJS += src/rtp/trtp_rtp_header.o \
+ src/rtp/trtp_rtp_packet.o \
+ src/rtp/trtp_rtp_session.o
+
+
+$(APP): $(OBJS)
+ifeq ($(EXT), a)
+ $(AR) rcs $@ $^
+else
+ $(CC) $(LDFLAGS) -o $@ $^
+endif
+
+%.o: %.c
+ $(CC) -c $(INCLUDE) $(CFLAGS) $< -o $@
+
+install: $(APP)
+ $(ANDROID_SDK_ROOT)/tools/adb remount
+ $(ANDROID_SDK_ROOT)/tools/adb push $(APP) $(LIB_DIR)/$(APP)
+ $(ANDROID_SDK_ROOT)/tools/adb shell chmod 777 $(LIB_DIR)/$(APP)
+
+clean:
+ @rm -f $(OBJS) $(APP) \ No newline at end of file
diff --git a/tinyRTP/include/tinyrtp.h b/tinyRTP/include/tinyrtp.h
new file mode 100644
index 0000000..8707f81
--- /dev/null
+++ b/tinyRTP/include/tinyrtp.h
@@ -0,0 +1,43 @@
+/*
+* 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.
+*
+*/
+
+/**@file tinyrtp.h
+ * @brief tinyRTP (Real-time Transport Protocol) API.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+
+ */
+#ifndef TINYRTP_TINYRTP_H
+#define TINYRTP_TINYRTP_H
+
+/* === tinyNET (tinyNET/src) === */
+#include "tnet.h"
+
+/* === tinySAK (tinySAK/src)=== */
+#include "tsk.h"
+
+#include "tinyrtp/rtp/trtp_rtp_header.h"
+#include "tinyrtp/rtp/trtp_rtp_packet.h"
+#include "tinyrtp/trtp_manager.h"
+
+#endif /* TINYRTP_TINYRTP_H */
diff --git a/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_header.h b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_header.h
new file mode 100644
index 0000000..9cf6a1a
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_header.h
@@ -0,0 +1,62 @@
+/*
+* 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.
+*
+*/
+#ifndef TINYRTP_RTCP_HEADER_H
+#define TINYRTP_RTCP_HEADER_H
+
+#include "tinyrtp_config.h"
+#include "tinyrtp/rtcp/trtp_rtcp_packet.h"
+
+#include "tsk_buffer.h"
+#include "tsk_list.h"
+
+#define TRTP_RTCP_HEADER_SIZE 4
+#define TRTP_RTCP_HEADER_VERSION_DEFAULT 2
+
+TRTP_BEGIN_DECLS
+
+typedef struct trtp_rtcp_header_s
+{
+ TSK_DECLARE_OBJECT;
+
+ unsigned version:2;
+ unsigned padding:1;
+ unsigned rc:5;
+ trtp_rtcp_packet_type_t type; /**< Packet Type on 8bits */
+ uint16_t length_in_words_minus1; /**< The length of this RTCP packet in 32-bit words minus one */
+ uint32_t length_in_bytes;
+}
+trtp_rtcp_header_t;
+
+#define TRTP_DECLARE_RTCP_HEADER trtp_rtcp_header_t __header__
+typedef tsk_list_t trtp_rtcp_headers_L_t; /**< List of @ref trtp_rtcp_header_t elements */
+
+TINYRTP_API trtp_rtcp_header_t* trtp_rtcp_header_create_null();
+TINYRTP_API 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);
+TINYRTP_API int trtp_rtcp_header_serialize_to(const trtp_rtcp_header_t *self, void* data, tsk_size_t size);
+TINYRTP_API trtp_rtcp_header_t* trtp_rtcp_header_deserialize(const void *data, tsk_size_t size);
+TINYRTP_API int trtp_rtcp_header_deserialize_to(trtp_rtcp_header_t** self, const void *data, tsk_size_t size);
+
+TINYRTP_GEXTERN const tsk_object_def_t *trtp_rtcp_header_def_t;
+
+TRTP_END_DECLS
+
+#endif /* TINYRTP_RTCP_HEADER_H */
diff --git a/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_packet.h b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_packet.h
new file mode 100644
index 0000000..9045be7
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_packet.h
@@ -0,0 +1,74 @@
+/*
+* 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.
+*
+*/
+#ifndef TINYRTP_RTCP_PACKET_H
+#define TINYRTP_RTCP_PACKET_H
+
+#include "tinyrtp_config.h"
+
+#include "tsk_buffer.h"
+#include "tsk_list.h"
+
+TRTP_BEGIN_DECLS
+
+#define TRTP_RTCP_PACKET(self) ((trtp_rtcp_packet_t*)(self))
+#define TRTP_DECLARE_RTCP_PACKET trtp_rtcp_packet_t __packet__
+
+// RFC 3550 12.1 RTCP Packet Types
+// RFC 4585
+// RFC 5104 (FIXME: not supported yet!)
+typedef enum trtp_rtcp_packet_type_e
+{
+ trtp_rtcp_packet_type_sr = 200,
+ trtp_rtcp_packet_type_rr = 201,
+ trtp_rtcp_packet_type_sdes = 202,
+ trtp_rtcp_packet_type_bye = 203,
+ trtp_rtcp_packet_type_app = 204,
+ trtp_rtcp_packet_type_rtpfb = 205,
+ trtp_rtcp_packet_type_psfb = 206
+}
+trtp_rtcp_packet_type_t;
+
+typedef struct trtp_rtcp_packet_s
+{
+ TSK_DECLARE_OBJECT;
+
+ struct trtp_rtcp_header_s *header;
+}
+trtp_rtcp_packet_t;
+
+typedef tsk_list_t trtp_rtcp_packets_L_t; /**< List of @ref trtp_rtcp_packet_t elements */
+
+trtp_rtcp_packet_t* trtp_rtcp_packet_create(struct trtp_rtcp_header_s* header);
+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);
+trtp_rtcp_packet_t* trtp_rtcp_packet_deserialize(const void* data, tsk_size_t size);
+int trtp_rtcp_packet_serialize_to(const trtp_rtcp_packet_t* self, void* data, tsk_size_t size);
+tsk_buffer_t* trtp_rtcp_packet_serialize(const trtp_rtcp_packet_t* self, tsk_size_t num_bytes_pad);
+int trtp_rtcp_packet_add_packet(trtp_rtcp_packet_t* self, trtp_rtcp_packet_t* packet, tsk_bool_t front);
+TINYRTP_API 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);
+TINYRTP_API const trtp_rtcp_packet_t* trtp_rtcp_packet_get(const trtp_rtcp_packet_t* self, trtp_rtcp_packet_type_t type);
+tsk_size_t trtp_rtcp_packet_get_size(const trtp_rtcp_packet_t* self);
+
+int trtp_rtcp_packet_deinit(trtp_rtcp_packet_t* self);
+
+TRTP_END_DECLS
+
+#endif /* TINYRTP_RTCP_PACKET_H */
diff --git a/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_rblock.h b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_rblock.h
new file mode 100644
index 0000000..5ea54e6
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_rblock.h
@@ -0,0 +1,59 @@
+/*
+* 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.
+*
+*/
+#ifndef TINYRTP_RTCP_REPORT_RB_H
+#define TINYRTP_RTCP_REPORT_RB_H
+
+#include "tinyrtp_config.h"
+
+#include "tsk_list.h"
+
+TRTP_BEGIN_DECLS
+
+#define TRTP_RTCP_RBLOCK_SIZE 24
+
+#define TRTP_RTCP_RBLOCK(self) ((trtp_rtcp_rblock_t*)(self))
+
+// RFC 3550 6.4.1 SR: Sender Report RTCP Packet => Report block part
+typedef struct trtp_rtcp_rblock_s
+{
+ TSK_DECLARE_OBJECT;
+
+ uint32_t ssrc; /* data source being reported */
+ unsigned int fraction:8; /* fraction lost since last SR/RR */
+ int cumulative_no_lost:24; /* cumul. no. pkts lost (signed!) */
+ uint32_t last_seq; /* extended last seq. no. received */
+ uint32_t jitter; /* interarrival jitter */
+ uint32_t lsr; /* last SR packet from this source */
+ uint32_t dlsr; /* delay since last SR packet */
+}
+trtp_rtcp_rblock_t;
+
+typedef tsk_list_t trtp_rtcp_rblocks_L_t; /**< List of @ref trtp_rtcp_rblock_t elements */
+
+trtp_rtcp_rblock_t* trtp_rtcp_rblock_create_null();
+trtp_rtcp_rblock_t* trtp_rtcp_rblock_deserialize(const void* data, tsk_size_t size);
+int trtp_rtcp_rblock_deserialize_list(const void* data, tsk_size_t size, trtp_rtcp_rblocks_L_t* dest_list);
+int trtp_rtcp_rblock_serialize_to(const trtp_rtcp_rblock_t* self, void* data, tsk_size_t size);
+
+TRTP_END_DECLS
+
+#endif /* TINYRTP_RTCP_REPORT_RB_H */
diff --git a/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report.h b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report.h
new file mode 100644
index 0000000..c30351f
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report.h
@@ -0,0 +1,32 @@
+/*
+* 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.
+*
+*/
+#ifndef TINYRTP_RTCP_REPORT_H
+#define TINYRTP_RTCP_REPORT_H
+
+#include "tinyrtp_config.h"
+
+TRTP_BEGIN_DECLS
+
+
+TRTP_END_DECLS
+
+#endif /* TINYRTP_RTCP_REPORT_H */
diff --git a/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_bye.h b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_bye.h
new file mode 100644
index 0000000..796e9fc
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_bye.h
@@ -0,0 +1,45 @@
+/*
+* 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.
+*
+*/
+#ifndef TINYRTP_RTCP_REPORT_BYE_H
+#define TINYRTP_RTCP_REPORT_BYE_H
+
+#include "tinyrtp_config.h"
+
+#include "tinyrtp/rtcp/trtp_rtcp_packet.h"
+
+typedef struct trtp_rtcp_report_bye_s
+{
+ TRTP_DECLARE_RTCP_PACKET;
+
+ uint32_t *ssrc_list;
+ trtp_rtcp_packets_L_t* packets;
+}
+trtp_rtcp_report_bye_t;
+
+trtp_rtcp_report_bye_t* trtp_rtcp_report_bye_create_null();
+trtp_rtcp_report_bye_t* trtp_rtcp_report_bye_create(struct trtp_rtcp_header_s* header);
+trtp_rtcp_report_bye_t* trtp_rtcp_report_bye_create_2(uint32_t ssrc);
+trtp_rtcp_report_bye_t* trtp_rtcp_report_bye_deserialize(const void* data, tsk_size_t size);
+int trtp_rtcp_report_bye_serialize_to(const trtp_rtcp_report_bye_t* self, void* data, tsk_size_t size);
+tsk_size_t trtp_rtcp_report_bye_get_size(const trtp_rtcp_report_bye_t* self);
+
+#endif /* TINYRTP_RTCP_REPORT_BYE_H */
diff --git a/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_fb.h b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_fb.h
new file mode 100644
index 0000000..1ad30b4
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_fb.h
@@ -0,0 +1,152 @@
+/*
+* 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.
+*
+*/
+#ifndef TINYRTP_RTCP_REPORT_FB_H
+#define TINYRTP_RTCP_REPORT_FB_H
+
+#include "tinyrtp_config.h"
+
+#include "tinyrtp/rtcp/trtp_rtcp_packet.h"
+
+#define TRTP_RTCP_REPORT_FB(self) ((trtp_rtcp_report_fb_t*)(self))
+#define TRTP_DECLARE_RTCP_FB_PACKET trtp_rtcp_report_fb_t __packet_fb__
+
+// RFC 4585 6.1. Common Packet Format for Feedback Messages
+typedef struct trtp_rtcp_report_fb_s
+{
+ TRTP_DECLARE_RTCP_PACKET;
+
+ uint32_t ssrc_sender; /* SSRC of packet sender */
+ uint32_t ssrc_media; /* SSRC of media source */
+}
+trtp_rtcp_report_fb_t;
+
+typedef enum trtp_rtcp_rtpfb_fci_type_e
+{
+ trtp_rtcp_rtpfb_fci_type_nack = 1, // RFC 4585
+ trtp_rtcp_rtpfb_fci_type_tmmbn = 4, // RFC 5104
+}
+trtp_rtcp_rtpfb_fci_type_t;
+
+// Transport layer FB message
+typedef struct trtp_rtcp_report_rtpfb_s
+{
+ TRTP_DECLARE_RTCP_FB_PACKET;
+
+ trtp_rtcp_rtpfb_fci_type_t fci_type;
+ union{
+ struct{
+ tsk_size_t count; // not part of the specification
+ uint16_t* pid; // 16 bits
+ uint16_t* blp; // 16 bits
+ }nack;
+ struct{
+ tsk_size_t count; // not part of the specification
+ uint32_t* ssrc; // 32 bits
+ uint8_t* MxTBR_Exp; // 6 bits
+ uint32_t* MxTBR_Mantissa; // 17 bits
+ uint16_t* MeasuredOverhead; // 9 bits
+ }tmmbn;
+ };
+}
+trtp_rtcp_report_rtpfb_t;
+
+trtp_rtcp_report_rtpfb_t* trtp_rtcp_report_rtpfb_create_null();
+trtp_rtcp_report_rtpfb_t* trtp_rtcp_report_rtpfb_create(struct trtp_rtcp_header_s* header);
+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* 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* trtp_rtcp_report_rtpfb_deserialize(const void* data, tsk_size_t size);
+int trtp_rtcp_report_rtpfb_serialize_to(const trtp_rtcp_report_rtpfb_t* self, void* data, tsk_size_t size);
+tsk_size_t trtp_rtcp_report_rtpfb_get_size(const trtp_rtcp_report_rtpfb_t* self);
+
+
+typedef enum trtp_rtcp_psfb_fci_type_e
+{
+ trtp_rtcp_psfb_fci_type_pli = 1, /* rfc 4585: Picture Loss Indication (PLI) */
+ trtp_rtcp_psfb_fci_type_sli = 2, /* rfc 4585: Slice Loss Indication (SLI) */
+ trtp_rtcp_psfb_fci_type_rpsi = 3, /* rfc 4585: Reference Picture Selection Indication (RPSI) */
+ trtp_rtcp_psfb_fci_type_fir = 4, /* rfc 5104: Full Intra Request (FIR) Command*/
+ trtp_rtcp_psfb_fci_type_afb = 15, /* rfc 4585: Application layer FB (AFB) message */
+}
+trtp_rtcp_psfb_fci_type_t;
+
+/* rfc 4585: Application layer FB (AFB) message */
+typedef enum trtp_rtcp_psfb_afb_type_e
+{
+ trtp_rtcp_psfb_afb_type_none,
+ trtp_rtcp_psfb_afb_type_remb // draft-alvestrand-rmcat-remb-02
+}
+trtp_rtcp_psfb_afb_type_t;
+
+// Payload-specific FB message
+typedef struct trtp_rtcp_report_psfb_s
+{
+ TRTP_DECLARE_RTCP_FB_PACKET;
+
+ trtp_rtcp_psfb_fci_type_t fci_type;
+ union{
+ // struct{ //rfc 4585: 6.3.1.2
+ // } pli;
+ struct{ // rfc 4585: 6.3.2.2
+ uint16_t* first;
+ uint16_t* number;
+ uint8_t* pic_id;
+ } sli;
+ struct{ // rfc 4585: 6.3.3.2
+ unsigned pb:8;
+ unsigned pt:7;
+ uint8_t* bytes;
+ } rpsi;
+ struct{// rfc 5104: 4.3.1.1
+ tsk_size_t count;
+ uint32_t* ssrc; // 32 bits
+ uint8_t* seq_num; // 8 bits
+ }fir;
+ struct{ // rfc 4585: 6.4
+ trtp_rtcp_psfb_afb_type_t type;
+ union{
+ struct{ // draft-alvestrand-rmcat-remb-02: 2.2
+ // MxTBR = mantissa * 2^exp = (mantissa << exp) bps
+ uint8_t num_ssrc;
+ uint8_t exp; // 6bits
+ uint32_t mantissa; // 18bits
+ uint32_t* ssrc_feedbacks; // 'num_ssrc'nth SSRC entries
+ }remb;
+ struct{
+ uint8_t* bytes; // store bytes to allow reconstruction
+ }none; // unknown type
+ };
+ }afb;
+ };
+}
+trtp_rtcp_report_psfb_t;
+
+trtp_rtcp_report_psfb_t* trtp_rtcp_report_psfb_create_null();
+trtp_rtcp_report_psfb_t* trtp_rtcp_report_psfb_create(struct trtp_rtcp_header_s* header);
+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* trtp_rtcp_report_psfb_create_pli(uint32_t ssrc_sender, uint32_t 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* 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* trtp_rtcp_report_psfb_deserialize(const void* data, tsk_size_t size);
+int trtp_rtcp_report_psfb_serialize_to(const trtp_rtcp_report_psfb_t* self, void* data, tsk_size_t size);
+tsk_size_t trtp_rtcp_report_psfb_get_size(const trtp_rtcp_report_psfb_t* self);
+
+#endif /* TINYRTP_RTCP_REPORT_FB_H */
diff --git a/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_rr.h b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_rr.h
new file mode 100644
index 0000000..2f25779
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_rr.h
@@ -0,0 +1,54 @@
+/*
+* 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.
+*
+*/
+#ifndef TINYRTP_RTCP_REPORT_RR_H
+#define TINYRTP_RTCP_REPORT_RR_H
+
+#include "tinyrtp_config.h"
+
+#include "tinyrtp/rtcp/trtp_rtcp_packet.h"
+#include "tinyrtp/rtcp/trtp_rtcp_rblock.h"
+
+TRTP_BEGIN_DECLS
+
+#define TRTP_RTCP_REPORT_RR(self) ((trtp_rtcp_report_rr_t*)(self))
+
+// RFC 3550 6.4.2 RR: Receiver Report RTCP Packet
+typedef struct trtp_rtcp_report_rr_s
+{
+ TRTP_DECLARE_RTCP_PACKET;
+
+ uint32_t ssrc;
+ trtp_rtcp_rblocks_L_t* blocks;
+ trtp_rtcp_packets_L_t* packets;
+}
+trtp_rtcp_report_rr_t;
+
+trtp_rtcp_report_rr_t* trtp_rtcp_report_rr_create_null();
+trtp_rtcp_report_rr_t* trtp_rtcp_report_rr_create(struct trtp_rtcp_header_s* header);
+trtp_rtcp_report_rr_t* trtp_rtcp_report_rr_create_2(uint32_t ssrc);
+trtp_rtcp_report_rr_t* trtp_rtcp_report_rr_deserialize(const void* data, tsk_size_t size);
+int trtp_rtcp_report_rr_serialize_to(const trtp_rtcp_report_rr_t* self, void* data, tsk_size_t size);
+tsk_size_t trtp_rtcp_report_rr_get_size(const trtp_rtcp_report_rr_t* self);
+
+TRTP_END_DECLS
+
+#endif /* TINYRTP_RTCP_REPORT_RR_H */
diff --git a/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_sdes.h b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_sdes.h
new file mode 100644
index 0000000..04efb5c
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_sdes.h
@@ -0,0 +1,53 @@
+/*
+* 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.
+*
+*/
+#ifndef TINYRTP_RTCP_REPORT_SDES_H
+#define TINYRTP_RTCP_REPORT_SDES_H
+
+#include "tinyrtp_config.h"
+
+#include "tinyrtp/rtcp/trtp_rtcp_packet.h"
+#include "tinyrtp/rtcp/trtp_rtcp_sdes_chunck.h"
+
+TRTP_BEGIN_DECLS
+
+#define TRTP_RTCP_REPORT_SDES(self) ((trtp_rtcp_report_sdes_t*)(self))
+
+/* RFC 3550 6.5 SDES: Source Description RTCP Packet */
+typedef struct trtp_rtcp_report_sdes_s
+{
+ TRTP_DECLARE_RTCP_PACKET;
+ trtp_rtcp_sdes_chuncks_L_t* chuncks;
+}
+trtp_rtcp_report_sdes_t;
+
+typedef tsk_list_t trtp_rtcp_report_sdess_L_t; /**< List of @ref trtp_rtcp_report_sdes_t elements */
+
+trtp_rtcp_report_sdes_t* trtp_rtcp_report_sdes_create_null();
+trtp_rtcp_report_sdes_t* trtp_rtcp_report_sdes_create(struct trtp_rtcp_header_s* header);
+trtp_rtcp_report_sdes_t* trtp_rtcp_report_sdes_deserialize(const void* data, tsk_size_t size);
+int trtp_rtcp_report_sdes_serialize_to(const trtp_rtcp_report_sdes_t* self, void* data, tsk_size_t size);
+int trtp_rtcp_report_sdes_add_chunck(trtp_rtcp_report_sdes_t* self, trtp_rtcp_sdes_chunck_t* chunck);
+tsk_size_t trtp_rtcp_report_sdes_get_size(const trtp_rtcp_report_sdes_t* self);
+
+TRTP_END_DECLS
+
+#endif /* TINYRTP_RTCP_REPORT_SDES_H */
diff --git a/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_sr.h b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_sr.h
new file mode 100644
index 0000000..09d442f
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_sr.h
@@ -0,0 +1,62 @@
+/*
+* 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.
+*
+*/
+#ifndef TINYRTP_RTCP_REPORT_SR_H
+#define TINYRTP_RTCP_REPORT_SR_H
+
+#include "tinyrtp_config.h"
+
+#include "tinyrtp/rtcp/trtp_rtcp_packet.h"
+#include "tinyrtp/rtcp/trtp_rtcp_rblock.h"
+
+TRTP_BEGIN_DECLS
+
+#define TRTP_RTCP_REPORT_SR(self) ((trtp_rtcp_report_sr_t*)(self))
+
+// RFC 3550 6.4.1 SR: Sender Report RTCP Packet
+typedef struct trtp_rtcp_report_sr_s
+{
+ TRTP_DECLARE_RTCP_PACKET;
+
+ uint32_t ssrc;
+ struct{
+ uint32_t ntp_msw; /**< NTP timestamp, most significant word */
+ uint32_t ntp_lsw; /**< NTP timestamp, least significant word */
+ uint32_t rtp_timestamp;/**< RTP timestamp */
+ uint32_t sender_pcount; /**< sender's packet count */
+ uint32_t sender_ocount; /**< sender's octet count */
+ } sender_info;
+
+ trtp_rtcp_rblocks_L_t* blocks;
+ trtp_rtcp_packets_L_t* packets;
+}
+trtp_rtcp_report_sr_t;
+
+trtp_rtcp_report_sr_t* trtp_rtcp_report_sr_create_null();
+trtp_rtcp_report_sr_t* trtp_rtcp_report_sr_create(struct trtp_rtcp_header_s* header);
+trtp_rtcp_report_sr_t* trtp_rtcp_report_sr_deserialize(const void* data, tsk_size_t size);
+int trtp_rtcp_report_sr_serialize_to(const trtp_rtcp_report_sr_t* self, void* data, tsk_size_t size);
+int trtp_rtcp_report_sr_add_block(trtp_rtcp_report_sr_t* self, trtp_rtcp_rblock_t* rblock);
+tsk_size_t trtp_rtcp_report_sr_get_size(const trtp_rtcp_report_sr_t* self);
+
+TRTP_END_DECLS
+
+#endif /* TINYRTP_RTCP_REPORT_SR_H */
diff --git a/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_xr.h b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_xr.h
new file mode 100644
index 0000000..b08e096
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_report_xr.h
@@ -0,0 +1,32 @@
+/*
+* 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.
+*
+*/
+#ifndef TINYRTP_RTCP_REPORT_XR_H
+#define TINYRTP_RTCP_REPORT_XR_H
+
+#include "tinyrtp_config.h"
+
+TRTP_BEGIN_DECLS
+
+
+TRTP_END_DECLS
+
+#endif /* TINYRTP_RTCP_REPORT_XR_H */
diff --git a/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_sdes_chunck.h b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_sdes_chunck.h
new file mode 100644
index 0000000..ec3a8d8
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_sdes_chunck.h
@@ -0,0 +1,56 @@
+/*
+* 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.
+*
+*/
+#ifndef TINYRTP_RTCP_SDES_CHUNCK_H
+#define TINYRTP_RTCP_SDES_CHUNCK_H
+
+#include "tinyrtp_config.h"
+
+#include "tinyrtp/rtcp/trtp_rtcp_sdes_item.h"
+
+#define TRTP_RTCP_SDES_CHUNCK_MIN_SIZE 4
+#define TRTP_RTCP_SDES_CHUNCK_SSRC_OR_CSRC_SIZE 4
+
+#define TRTP_RTCP_SDES_CHUNCK(self) ((trtp_rtcp_sdes_chunck_t*)(self))
+
+TRTP_BEGIN_DECLS
+
+typedef struct trtp_rtcp_sdes_chunck_s
+{
+ TSK_DECLARE_OBJECT;
+
+ uint32_t ssrc;
+ trtp_rtcp_sdes_items_L_t* items;
+}
+trtp_rtcp_sdes_chunck_t;
+
+typedef tsk_list_t trtp_rtcp_sdes_chuncks_L_t; /**< List of @ref trtp_rtcp_sdes_item_t elements */
+
+trtp_rtcp_sdes_chunck_t* trtp_rtcp_sdes_chunck_create_null();
+trtp_rtcp_sdes_chunck_t* trtp_rtcp_sdes_chunck_create(uint32_t ssrc);
+trtp_rtcp_sdes_chunck_t* trtp_rtcp_sdes_chunck_deserialize(const void* data, tsk_size_t size);
+int trtp_rtcp_sdes_chunck_serialize_to(const trtp_rtcp_sdes_chunck_t* self, void* data, tsk_size_t size);
+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);
+tsk_size_t trtp_rtcp_sdes_chunck_get_size(const trtp_rtcp_sdes_chunck_t* self);
+
+TRTP_END_DECLS
+
+#endif /*TINYRTP_RTCP_SDES_CHUNCK_H*/
diff --git a/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_sdes_item.h b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_sdes_item.h
new file mode 100644
index 0000000..8356a74
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_sdes_item.h
@@ -0,0 +1,71 @@
+/*
+* 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.
+*
+*/
+#ifndef TINYRTP_RTCP_SDES_ITEM_H
+#define TINYRTP_RTCP_SDES_ITEM_H
+
+#include "tinyrtp_config.h"
+
+#include "tsk_list.h"
+#include "tsk_buffer.h"
+
+#define TRTP_RTCP_SDES_ITEM_MIN_SIZE 2 /* Type + Length */
+
+#define TRTP_RTCP_SDES_ITEM(self) ((trtp_rtcp_sdes_item_t*)(self))
+
+TRTP_BEGIN_DECLS
+
+// RFC 3550 12.2 SDES Types
+typedef enum trtp_rtcp_sdes_item_type_e
+{
+ trtp_rtcp_sdes_item_type_end = 0, /**< end of SDES list */
+ trtp_rtcp_sdes_item_type_cname = 1, /**< canonical name*/
+ trtp_rtcp_sdes_item_type_name = 2, /**< user name */
+ trtp_rtcp_sdes_item_type_email = 3, /**< user's electronic mail address*/
+ trtp_rtcp_sdes_item_type_phone = 4, /**< user's phone number */
+ trtp_rtcp_sdes_item_type_loc = 5, /**< geographic user location*/
+ trtp_rtcp_sdes_item_type_tool = 6, /**< name of application or tool*/
+ trtp_rtcp_sdes_item_type_note = 7, /**< notice about the source*/
+ trtp_rtcp_sdes_item_type_priv = 8, /**< private extensions*/
+}
+trtp_rtcp_sdes_item_type_t;
+
+typedef struct trtp_rtcp_sdes_item_s
+{
+ TSK_DECLARE_OBJECT;
+
+ trtp_rtcp_sdes_item_type_t type;
+ tsk_buffer_t *data;
+}
+trtp_rtcp_sdes_item_t;
+
+
+typedef tsk_list_t trtp_rtcp_sdes_items_L_t; /**< List of @ref trtp_rtcp_sdes_item_t elements */
+
+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* trtp_rtcp_sdes_item_deserialize(const void* data, tsk_size_t size);
+tsk_buffer_t* trtp_rtcp_sdes_item_serialize(const trtp_rtcp_sdes_item_t* self);
+int trtp_rtcp_sdes_item_serialize_to(const trtp_rtcp_sdes_item_t* self, void* data, tsk_size_t size);
+tsk_size_t trtp_rtcp_sdes_item_get_size(const trtp_rtcp_sdes_item_t* self);
+
+TRTP_END_DECLS
+
+#endif /* TINYRTP_RTCP_SDES_ITEM_H */
diff --git a/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_session.h b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_session.h
new file mode 100644
index 0000000..34ddbbc
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtcp/trtp_rtcp_session.h
@@ -0,0 +1,70 @@
+/*
+* 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.
+*
+*/
+/**@file trtp_rtcp_session.h
+ * @brief RTCP session.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+
+ */
+#ifndef TINYMEDIA_RTCP_SESSION_H
+#define TINYMEDIA_RTCP_SESSION_H
+
+#include "tinyrtp_config.h"
+#include "tinyrtp/trtp_srtp.h"
+
+#include "tnet_types.h"
+
+#include "tsk_common.h"
+
+TRTP_BEGIN_DECLS
+
+struct trtp_rtcp_packet_s;
+struct trtp_rtp_packet_s;
+struct tnet_ice_ctx_s;
+struct tnet_transport_s;
+
+typedef int (*trtp_rtcp_cb_f)(const void* callback_data, const struct trtp_rtcp_packet_s* packet);
+
+struct trtp_rtcp_session_s* trtp_rtcp_session_create(uint32_t ssrc, const char* cname);
+struct trtp_rtcp_session_s* trtp_rtcp_session_create_2(struct tnet_ice_ctx_s* ice_ctx, uint32_t ssrc, const char* cname);
+int trtp_rtcp_session_set_callback(struct trtp_rtcp_session_s* self, trtp_rtcp_cb_f callback, const void* callback_data);
+#if HAVE_SRTP
+int trtp_rtcp_session_set_srtp_sess(struct trtp_rtcp_session_s* self, const srtp_t* session);
+#endif
+int trtp_rtcp_session_set_app_bandwidth_max(struct trtp_rtcp_session_s* self, int32_t bw_upload_kbps, int32_t bw_download_kbps);
+int trtp_rtcp_session_start(struct trtp_rtcp_session_s* self, tnet_fd_t local_fd, const struct sockaddr* remote_addr);
+int trtp_rtcp_session_stop(struct trtp_rtcp_session_s* self);
+int trtp_rtcp_session_process_rtp_out(struct trtp_rtcp_session_s* self, const struct trtp_rtp_packet_s* packet_rtp, tsk_size_t size);
+int trtp_rtcp_session_process_rtp_in(struct trtp_rtcp_session_s* self, const struct trtp_rtp_packet_s* packet_rtp, tsk_size_t size);
+int trtp_rtcp_session_process_rtcp_in(struct trtp_rtcp_session_s* self, const void* buffer, tsk_size_t size);
+int trtp_rtcp_session_signal_pkt_loss(struct trtp_rtcp_session_s* self, uint32_t ssrc_media, const uint16_t* seq_nums, tsk_size_t count);
+int trtp_rtcp_session_signal_frame_corrupted(struct trtp_rtcp_session_s* self, uint32_t ssrc_media);
+int trtp_rtcp_session_signal_jb_error(struct trtp_rtcp_session_s* self, uint32_t ssrc_media);
+
+tnet_fd_t trtp_rtcp_session_get_local_fd(const struct trtp_rtcp_session_s* self);
+int trtp_rtcp_session_set_local_fd(struct trtp_rtcp_session_s* self, tnet_fd_t local_fd);
+int trtp_rtcp_session_set_net_transport(struct trtp_rtcp_session_s* self, struct tnet_transport_s* transport);
+
+TRTP_END_DECLS
+
+#endif /* TINYMEDIA_RTCP_SESSION_H */
diff --git a/tinyRTP/include/tinyrtp/rtp/trtp_rtp_header.h b/tinyRTP/include/tinyrtp/rtp/trtp_rtp_header.h
new file mode 100644
index 0000000..15d177c
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtp/trtp_rtp_header.h
@@ -0,0 +1,85 @@
+/*
+* 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.
+*
+*/
+/**@file trtp_rtp_header.h
+ * @brief RTP header.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ */
+#ifndef TINYRTP_RTP_HEADER_H
+#define TINYRTP_RTP_HEADER_H
+
+#include "tinyrtp_config.h"
+#include "tinymedia/tmedia_codec.h"
+#include "tsk_buffer.h"
+
+TRTP_BEGIN_DECLS
+
+#define TRTP_RTP_HEADER_MIN_SIZE 12
+#define TRTP_RTP_HEADER(self) ((trtp_rtp_header_t*)(self))
+
+typedef struct trtp_rtp_header_s
+{
+ TSK_DECLARE_OBJECT;
+ /* 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 |
+ | .... |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ unsigned version:2;
+ unsigned padding:1;
+ unsigned extension:1;
+ unsigned csrc_count:4;
+ unsigned marker:1;
+ unsigned payload_type:7;
+ uint16_t seq_num;
+ uint32_t timestamp;
+ uint32_t ssrc;
+ uint32_t csrc[15];
+
+ // for internal use
+ enum tmedia_codec_id_e codec_id;
+}
+trtp_rtp_header_t;
+
+TINYRTP_API trtp_rtp_header_t* trtp_rtp_header_create_null();
+TINYRTP_API 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);
+TINYRTP_API tsk_size_t trtp_rtp_header_guess_serialbuff_size(const trtp_rtp_header_t *self);
+TINYRTP_API tsk_size_t trtp_rtp_header_serialize_to(const trtp_rtp_header_t *self, void *buffer, tsk_size_t size);
+TINYRTP_API tsk_buffer_t* trtp_rtp_header_serialize(const trtp_rtp_header_t *self);
+TINYRTP_API trtp_rtp_header_t* trtp_rtp_header_deserialize(const void *data, tsk_size_t size);
+
+
+TINYRTP_GEXTERN const tsk_object_def_t *trtp_rtp_header_def_t;
+
+TRTP_END_DECLS
+
+#endif /* TINYRTP_RTP_HEADER_H */
diff --git a/tinyRTP/include/tinyrtp/rtp/trtp_rtp_packet.h b/tinyRTP/include/tinyrtp/rtp/trtp_rtp_packet.h
new file mode 100644
index 0000000..c7f8cf3
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtp/trtp_rtp_packet.h
@@ -0,0 +1,74 @@
+/*
+* 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.
+*
+*/
+/**@file trtp_rtp_packet.h
+ * @brief RTP packet.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ */
+#ifndef TINYRTP_RTP_PACKET_H
+#define TINYRTP_RTP_PACKET_H
+
+#include "tinyrtp_config.h"
+
+#include "tinyrtp/rtp/trtp_rtp_header.h"
+
+#include "tsk_object.h"
+
+TRTP_BEGIN_DECLS
+
+
+typedef struct trtp_rtp_packet_s
+{
+ TSK_DECLARE_OBJECT;
+
+ trtp_rtp_header_t* header;
+
+ struct{
+ void* data;
+ const void* data_const; // never free()d. an alternative to "data"
+ tsk_size_t size;
+ } payload;
+
+ /* extension header as per RFC 3550 section 5.3.1 */
+ struct{
+ void* data;
+ tsk_size_t size; /* contains the first two 16-bit fields */
+ } extension;
+}
+trtp_rtp_packet_t;
+typedef tsk_list_t trtp_rtp_packets_L_t;
+
+TINYRTP_API trtp_rtp_packet_t* trtp_rtp_packet_create_null();
+TINYRTP_API 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);
+TINYRTP_API trtp_rtp_packet_t* trtp_rtp_packet_create_2(const trtp_rtp_header_t* header);
+TINYRTP_API tsk_size_t trtp_rtp_packet_guess_serialbuff_size(const trtp_rtp_packet_t *self);
+TINYRTP_API tsk_size_t trtp_rtp_packet_serialize_to(const trtp_rtp_packet_t *self, void* buffer, tsk_size_t size);
+TINYRTP_API tsk_buffer_t* trtp_rtp_packet_serialize(const trtp_rtp_packet_t *self, tsk_size_t num_bytes_pad);
+TINYRTP_API trtp_rtp_packet_t* trtp_rtp_packet_deserialize(const void *data, tsk_size_t size);
+
+
+TINYRTP_GEXTERN const tsk_object_def_t *trtp_rtp_packet_def_t;
+
+TRTP_END_DECLS
+
+#endif /* TINYRTP_RTP_PACKET_H */
diff --git a/tinyRTP/include/tinyrtp/rtp/trtp_rtp_session.h b/tinyRTP/include/tinyrtp/rtp/trtp_rtp_session.h
new file mode 100644
index 0000000..475502a
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/rtp/trtp_rtp_session.h
@@ -0,0 +1,42 @@
+/*
+* 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.
+*
+*/
+/**@file trtp_rtp_session.h
+ * @brief RTP session.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+
+ */
+#ifndef TINYMEDIA_RTP_SESSION_H
+#define TINYMEDIA_RTP_SESSION_H
+
+#include "tinyrtp_config.h"
+
+TRTP_BEGIN_DECLS
+
+struct trtp_rtp_packet_s;
+
+typedef int (*trtp_rtp_cb_f)(const void* callback_data, const struct trtp_rtp_packet_s* packet);
+
+TRTP_END_DECLS
+
+#endif /* TINYMEDIA_RTP_SESSION_H */
diff --git a/tinyRTP/include/tinyrtp/trtp.h b/tinyRTP/include/tinyrtp/trtp.h
new file mode 100644
index 0000000..3359a70
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/trtp.h
@@ -0,0 +1,38 @@
+/*
+* 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.
+*
+*/
+/**@file trtp.h
+ * @brief tinyRTP (Real-time Transport Protocol) as per RFC 3550.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+
+ */
+#ifndef TINYMEDIA_TRTP_H
+#define TINYMEDIA_TRTP_H
+
+#include "tinyrtp_config.h"
+
+TRTP_BEGIN_DECLS
+
+TRTP_END_DECLS
+
+#endif /* TINYMEDIA_TRTP_H */
diff --git a/tinyRTP/include/tinyrtp/trtp_manager.h b/tinyRTP/include/tinyrtp/trtp_manager.h
new file mode 100644
index 0000000..1594f9c
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/trtp_manager.h
@@ -0,0 +1,227 @@
+/*
+* 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.
+*
+*/
+/**@file trtp_manager.h
+ * @brief RTP/RTCP manager.
+ */
+#ifndef TINYRTP_MANAGER_H
+#define TINYRTP_MANAGER_H
+
+#include "tinyrtp_config.h"
+
+#include "tinyrtp/rtp/trtp_rtp_session.h"
+#include "tinyrtp/rtcp/trtp_rtcp_session.h"
+#include "tinyrtp/trtp_srtp.h"
+
+#include "tinymedia/tmedia_defaults.h"
+
+#include "tinynet.h"
+
+TRTP_BEGIN_DECLS
+
+struct trtp_rtp_packet_s;
+struct tnet_proxyinfo_s;
+
+/** RTP/RTCP manager */
+typedef struct trtp_manager_s
+{
+ TSK_DECLARE_OBJECT;
+
+ char* local_ip;
+ tsk_bool_t use_ipv6;
+ tsk_bool_t is_started;
+ tsk_bool_t use_rtcp;
+ tsk_bool_t use_rtcpmux;
+ tsk_bool_t is_socket_disabled;
+ tsk_bool_t is_ice_neg_ok;
+ tsk_bool_t is_ice_turn_active;
+ tsk_bool_t is_force_symetric_rtp;
+ tsk_bool_t is_symetric_rtp_checked;
+ tsk_bool_t is_symetric_rtcp_checked;
+ int32_t app_bw_max_upload; // application specific (kbps)
+ int32_t app_bw_max_download; // application specific (kbps)
+
+ tnet_transport_t* transport;
+
+ struct tnet_ice_ctx_s* ice_ctx;
+
+ tsk_timer_manager_handle_t* timer_mgr_global;
+
+ struct{
+ tmedia_rtcweb_type_t local;
+ tmedia_rtcweb_type_t remote;
+ } rtcweb_type;
+
+ struct {
+ tsk_bool_t auto_detect;
+ struct tnet_proxyinfo_s* info;
+ }
+ proxy;
+
+ struct{
+ uint16_t start;
+ uint16_t stop;
+ } port_range;
+
+ struct{
+ uint16_t seq_num;
+ uint32_t timestamp;
+ uint8_t payload_type;
+ int32_t dscp;
+
+ char* remote_ip;
+ tnet_port_t remote_port;
+ struct sockaddr_storage remote_addr;
+
+ char* public_ip;
+ tnet_port_t public_port;
+
+ struct{
+ uint32_t local;
+ uint32_t remote;
+ } ssrc;
+
+ struct{
+ const void* usrdata;
+ trtp_rtp_cb_f fun;
+ } cb;
+
+ struct{
+ void* ptr;
+ tsk_size_t size;
+ tsk_size_t index;
+ } serial_buffer;
+ } rtp;
+
+ struct{
+ char* cname;
+ char* remote_ip;
+ tnet_port_t remote_port;
+ struct sockaddr_storage remote_addr;
+ tnet_socket_t* local_socket;
+
+ char* public_ip;
+ tnet_port_t public_port;
+
+ struct{
+ const void* usrdata;
+ trtp_rtcp_cb_f fun;
+ } cb;
+
+ struct trtp_rtcp_session_s* session;
+ } rtcp;
+
+ TSK_DECLARE_SAFEOBJ;
+
+#if HAVE_SRTP
+ enum tmedia_srtp_type_e srtp_type;
+ enum tmedia_srtp_mode_e srtp_mode;
+ trtp_srtp_state_t srtp_state;
+ trtp_srtp_ctx_xt srtp_contexts[2/*LINE_IDX*/][2/*CRYPTO_TYPE*/];
+ const struct trtp_srtp_ctx_xs* srtp_ctx_neg_local;
+ const struct trtp_srtp_ctx_xs* srtp_ctx_neg_remote;
+
+ struct{
+ char* file_ca;
+ char* file_pbk;
+ char* file_pvk;
+ tsk_bool_t cert_verif;
+
+ trtp_srtp_state_t state;
+ // enable() could be postponed if net transport not ready yet (e.g. when ICE is ON)
+ tsk_bool_t enable_postponed;
+
+ tsk_bool_t srtp_connected;
+ tsk_bool_t srtcp_connected;
+ tsk_bool_t srtp_handshake_succeed;
+ tsk_bool_t srtcp_handshake_succeed;
+
+ trtp_srtp_crypto_type_t crypto_selected;
+
+ struct{
+ uint64_t timeout;
+ tsk_timer_id_t id;
+ } timer_hanshaking;
+
+ struct{
+ const void* usrdata;
+ trtp_srtp_dtls_cb_f fun;
+ } cb;
+
+ struct{
+ tnet_fingerprint_t fp;
+ tnet_dtls_hash_type_t fp_hash;
+ } remote;
+ struct{
+ tnet_dtls_setup_t setup;
+ tsk_bool_t connection_new;
+ }local;
+ } dtls;
+#endif
+}
+trtp_manager_t;
+
+TINYRTP_API trtp_manager_t* trtp_manager_create(tsk_bool_t use_rtcp, const char* local_ip, tsk_bool_t use_ipv6, enum tmedia_srtp_type_e srtp_type, enum tmedia_srtp_mode_e srtp_mode);
+TINYRTP_API trtp_manager_t* trtp_manager_create_2(struct tnet_ice_ctx_s* ice_ctx, enum tmedia_srtp_type_e srtp_type, enum tmedia_srtp_mode_e srtp_mode);
+TINYRTP_API int trtp_manager_set_ice_ctx(trtp_manager_t* self, struct tnet_ice_ctx_s* ice_ctx);
+TINYRTP_API int trtp_manager_prepare(trtp_manager_t* self);
+#if HAVE_SRTP
+TINYRTP_API int trtp_manager_set_dtls_certs(trtp_manager_t* self, const char* ca, const char* pbk, const char* pvk, tsk_bool_t verify);
+TINYRTP_API int trtp_manager_set_dtls_remote_fingerprint(trtp_manager_t* self, const tnet_fingerprint_t* fp, const char* hash);
+TINYRTP_API enum tnet_dtls_hash_type_e trtp_manager_get_dtls_remote_fingerprint_hash(trtp_manager_t* self);
+TINYRTP_API int trtp_manager_set_dtls_local_setup(trtp_manager_t* self, tnet_dtls_setup_t setup, tsk_bool_t connection_new);
+TINYRTP_API int trtp_manager_set_dtls_callback(trtp_manager_t* self, const void* usrdata, trtp_srtp_dtls_cb_f fun);
+TINYRTP_API const char* trtp_manager_get_dtls_local_fingerprint(trtp_manager_t* self, enum tnet_dtls_hash_type_e hash);
+TINYRTP_API tsk_bool_t trtp_manager_is_dtls_enabled(trtp_manager_t* self);
+TINYRTP_API tsk_bool_t trtp_manager_is_dtls_activated(trtp_manager_t* self);
+TINYRTP_API tsk_bool_t trtp_manager_is_dtls_started(trtp_manager_t* self);
+TINYRTP_API tsk_bool_t trtp_manager_is_srtp_activated(trtp_manager_t* self);
+TINYRTP_API tsk_bool_t trtp_manager_is_srtp_started(trtp_manager_t* self);
+TINYRTP_API int trtp_manager_set_srtp_type_remote(trtp_manager_t* self, enum tmedia_srtp_type_e srtp_type);
+TINYRTP_API 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);
+#endif /* HAVE_SRTP */
+TINYRTP_API tsk_bool_t trtp_manager_is_ready(trtp_manager_t* self);
+TINYRTP_API int trtp_manager_set_natt_ctx(trtp_manager_t* self, struct tnet_nat_ctx_s* natt_ctx);
+TINYRTP_API int trtp_manager_set_rtp_callback(trtp_manager_t* self, trtp_rtp_cb_f fun, const void* usrdata);
+TINYRTP_API int trtp_manager_set_rtcp_callback(trtp_manager_t* self, trtp_rtcp_cb_f fun, const void* usrdata);
+TINYRTP_API int trtp_manager_set_rtp_dscp(trtp_manager_t* self, int32_t dscp);
+TINYRTP_API int trtp_manager_set_payload_type(trtp_manager_t* self, uint8_t payload_type);
+TINYRTP_API int trtp_manager_set_rtp_remote(trtp_manager_t* self, const char* remote_ip, tnet_port_t remote_port);
+TINYRTP_API int trtp_manager_set_rtcp_remote(trtp_manager_t* self, const char* remote_ip, tnet_port_t remote_port);
+TINYRTP_API int trtp_manager_set_port_range(trtp_manager_t* self, uint16_t start, uint16_t stop);
+TINYRTP_API int trtp_manager_set_rtcweb_type_remote(trtp_manager_t* self, tmedia_rtcweb_type_t rtcweb_type);
+TINYRTP_API int trtp_manager_set_proxy_auto_detect(trtp_manager_t* self, tsk_bool_t auto_detect);
+TINYRTP_API 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);
+TINYRTP_API int trtp_manager_start(trtp_manager_t* self);
+TINYRTP_API 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);
+TINYRTP_API tsk_size_t trtp_manager_send_rtp_packet(trtp_manager_t* self, const struct trtp_rtp_packet_s* packet, tsk_bool_t bypass_encrypt);
+TINYRTP_API int trtp_manager_get_bytes_count(trtp_manager_t* self, uint64_t* bytes_in, uint64_t* bytes_out);
+TINYRTP_API tsk_size_t trtp_manager_send_rtp_raw(trtp_manager_t* self, const void* data, tsk_size_t size);
+TINYRTP_API int trtp_manager_set_app_bandwidth_max(trtp_manager_t* self, int32_t bw_upload_kbps, int32_t bw_download_kbps);
+TINYRTP_API int trtp_manager_signal_pkt_loss(trtp_manager_t* self, uint32_t ssrc_media, const uint16_t* seq_nums, tsk_size_t count);
+TINYRTP_API int trtp_manager_signal_frame_corrupted(trtp_manager_t* self, uint32_t ssrc_media);
+TINYRTP_API int trtp_manager_signal_jb_error(trtp_manager_t* self, uint32_t ssrc_media);
+TINYRTP_API int trtp_manager_stop(trtp_manager_t* self);
+
+TINYRTP_GEXTERN const tsk_object_def_t *trtp_manager_def_t;
+
+TRTP_END_DECLS
+
+#endif /* TINYRTP_MANAGER_H */
diff --git a/tinyRTP/include/tinyrtp/trtp_srtp.h b/tinyRTP/include/tinyrtp/trtp_srtp.h
new file mode 100644
index 0000000..9992bbb
--- /dev/null
+++ b/tinyRTP/include/tinyrtp/trtp_srtp.h
@@ -0,0 +1,131 @@
+/*
+* 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.
+*
+*/
+/**@file trtp_srtp.h
+ */
+#ifndef TINYRTP_SRTP_H
+#define TINYRTP_SRTP_H
+
+#include "tinyrtp_config.h"
+
+#if HAVE_SRTP
+# include "tsk_common.h"
+# include <srtp/srtp.h>
+
+struct trtp_manager_s;
+
+typedef enum trtp_srtp_dtls_event_type_e
+{
+ trtp_srtp_dtls_event_type_handshake_failed,
+ trtp_srtp_dtls_event_type_handshake_succeed,
+ trtp_srtp_dtls_event_type_fatal_error,
+ trtp_srtp_dtls_event_type_started
+}
+trtp_srtp_dtls_event_type_t;
+
+typedef enum trtp_srtp_crypto_type_e
+{
+ NONE = -1,
+ HMAC_SHA1_80,
+ HMAC_SHA1_32,
+
+ SRTP_CRYPTO_TYPES_MAX
+}
+trtp_srtp_crypto_type_t;
+
+typedef enum trtp_srtp_state_e
+{
+ trtp_srtp_state_none,
+ /* at this state we're able to generated DTLS "fingerprints" and SDES "crypro" attributes
+ but neither encrypt() nor decrypt() is possible.
+ it's possible to move backward and disable SRTP (e.g. because of negotiation error)
+ it's required to move to this state in order to be able to negotiate SRTP when mode is "optional" or "mandatory"
+ */
+ trtp_srtp_state_enabled,
+ /* at this state both required parameters (e.g. "crypto" attributes) have been successfuly proceeded
+ it's not possible to move backward and disable SRTP
+ if type="SDES": start()ing the engine means we'll be imediately able to encrypt()/decrypt() data
+ if type="DTLS": start()ing the engine doesn't mean we will be able to encrypt()/decrypt() data unless handshaking process successfuly completed
+ */
+ trtp_srtp_state_activated,
+ /* at this state we're able to encrypt()/decrypt() SRTP data
+ */
+ trtp_srtp_state_started
+}
+trtp_srtp_state_t;
+
+typedef int (*trtp_srtp_dtls_cb_f)(const void* usrdata, enum trtp_srtp_dtls_event_type_e type, const char* reason);
+
+#define TRTP_SRTP_AES_CM_128_HMAC_SHA1_80 "AES_CM_128_HMAC_SHA1_80"
+#define TRTP_SRTP_AES_CM_128_HMAC_SHA1_32 "AES_CM_128_HMAC_SHA1_32"
+
+#define TRTP_SRTP_LINE_IDX_LOCAL 0
+#define TRTP_SRTP_LINE_IDX_REMOTE 1
+
+static const char* trtp_srtp_crypto_type_strings[2] =
+{
+ TRTP_SRTP_AES_CM_128_HMAC_SHA1_80, TRTP_SRTP_AES_CM_128_HMAC_SHA1_32
+};
+
+
+typedef struct trtp_srtp_ctx_internal_xs
+{
+ int32_t tag;
+ trtp_srtp_crypto_type_t crypto_type;
+ char key_str[SRTP_MAX_KEY_LEN];
+ char key_bin[SRTP_MASTER_KEY_LEN];
+ tsk_bool_t have_valid_key;
+
+ srtp_t session;
+ srtp_policy_t policy;
+ tsk_bool_t initialized;
+}
+trtp_srtp_ctx_internal_xt;
+
+typedef struct trtp_srtp_ctx_xs
+{
+ // (rtp == rtcp) for SDES but different for DTLS
+ struct trtp_srtp_ctx_internal_xs rtp;
+ struct trtp_srtp_ctx_internal_xs rtcp;
+}
+trtp_srtp_ctx_xt;
+
+int trtp_srtp_ctx_internal_init(struct trtp_srtp_ctx_internal_xs* ctx, int32_t tag, trtp_srtp_crypto_type_t type, uint32_t ssrc);
+int trtp_srtp_ctx_internal_deinit(struct trtp_srtp_ctx_internal_xs* ctx);
+int trtp_srtp_ctx_init(struct trtp_srtp_ctx_xs* ctx, int32_t tag, trtp_srtp_crypto_type_t type, uint32_t ssrc);
+int trtp_srtp_ctx_deinit(struct trtp_srtp_ctx_xs* ctx);
+TINYRTP_API int trtp_srtp_match_line(const char* crypto_line, int32_t* tag, int32_t* crypto_type, char* key, tsk_size_t key_size);
+
+TINYRTP_API int trtp_srtp_set_crypto(struct trtp_manager_s* rtp_mgr, const char* crypto_line, int32_t idx);
+#define trtp_srtp_set_crypto_local(rtp_mgr, crypto_line) trtp_srtp_set_crypto((rtp_mgr), (crypto_line), TRTP_SRTP_LINE_IDX_LOCAL)
+#define trtp_srtp_set_crypto_remote(rtp_mgr, crypto_line) trtp_srtp_set_crypto((rtp_mgr), (crypto_line), TRTP_SRTP_LINE_IDX_REMOTE)
+TINYRTP_API int trtp_srtp_set_key_and_salt(struct trtp_manager_s* rtp_mgr, trtp_srtp_crypto_type_t crypto_type, const void* key, tsk_size_t key_size, const void* salt, tsk_size_t salt_size, int32_t idx, tsk_bool_t rtp);
+#define trtp_srtp_set_key_and_salt_local(rtp_mgr, crypto_type, key, key_size, salt, salt_size, is_rtp) trtp_srtp_set_key_and_salt((rtp_mgr), (crypto_type), (key), (key_size), (salt), (salt_size), TRTP_SRTP_LINE_IDX_LOCAL, (is_rtp))
+#define trtp_srtp_set_key_and_salt_remote(rtp_mgr, crypto_type, key, key_size, salt, salt_size, is_rtp) trtp_srtp_set_key_and_salt((rtp_mgr), (crypto_type), (key), (key_size), (salt), (salt_size), TRTP_SRTP_LINE_IDX_REMOTE, (is_rtp))
+TINYRTP_API tsk_size_t trtp_srtp_get_local_contexts(struct trtp_manager_s* rtp_mgr, const struct trtp_srtp_ctx_xs ** contexts, tsk_size_t contexts_count);
+TINYRTP_API tsk_bool_t trtp_srtp_is_initialized(struct trtp_manager_s* rtp_mgr);
+TINYRTP_API tsk_bool_t trtp_srtp_is_started(struct trtp_manager_s* rtp_mgr);
+
+#endif /* HAVE_SRTP */
+
+
+
+
+#endif /* TINYRTP_SRTP_H */
diff --git a/tinyRTP/include/tinyrtp_config.h b/tinyRTP/include/tinyrtp_config.h
new file mode 100644
index 0000000..422b68f
--- /dev/null
+++ b/tinyRTP/include/tinyrtp_config.h
@@ -0,0 +1,92 @@
+/*
+* 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.
+*
+*/
+
+#ifndef TINYRTP_CONFIG_H
+#define TINYRTP_CONFIG_H
+
+#ifdef __SYMBIAN32__
+#undef _WIN32 /* Because of WINSCW */
+#endif
+
+// Windows (XP/Vista/7/CE and Windows Mobile) macro definition.
+#if defined(WIN32)|| defined(_WIN32) || defined(_WIN32_WCE)
+# define TRTP_UNDER_WINDOWS 1
+# if defined(_WIN32_WCE) || defined(UNDER_CE)
+# define TRTP_UNDER_WINDOWS_CE 1
+# endif
+# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP)
+# define TRTP_UNDER_WINDOWS_RT 1
+# endif
+#endif
+
+#if (TRTP_UNDER_WINDOWS || defined(__SYMBIAN32__)) && defined(TINYRTP_EXPORTS)
+# define TINYRTP_API __declspec(dllexport)
+# define TINYRTP_GEXTERN __declspec(dllexport)
+#elif (TRTP_UNDER_WINDOWS || defined(__SYMBIAN32__)) && !defined(TINYRTP_IMPORTS_IGNORE)
+# define TINYRTP_API __declspec(dllimport)
+# define TINYRTP_GEXTERN __declspec(dllimport)
+#else
+# define TINYRTP_API
+# define TINYRTP_GEXTERN extern
+#endif
+
+/* Guards against C++ name mangling
+*/
+#ifdef __cplusplus
+# define TRTP_BEGIN_DECLS extern "C" {
+# define TRTP_END_DECLS }
+#else
+# define TRTP_BEGIN_DECLS
+# define TRTP_END_DECLS
+#endif
+
+/* Disable some well-known warnings
+*/
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_WARNINGS
+#endif
+
+/* Detecting C99 compilers
+ */
+#if (__STDC_VERSION__ == 199901L) && !defined(__C99__)
+# define __C99__
+#endif
+
+#if !defined(TRTP_RTP_VERSION)
+# define TRTP_RTP_VERSION 2
+#endif /* TRTP_RTP_VERSION */
+
+#include <stdint.h>
+#ifdef __SYMBIAN32__
+# include <stdlib.h>
+#endif
+
+#if defined(__APPLE__)
+# include <TargetConditionals.h>
+# include <Availability.h>
+#endif
+
+#if HAVE_CONFIG_H
+ #include <config.h>
+#endif
+
+#endif // TINYRTP_CONFIG_H
diff --git a/tinyRTP/src/rtcp/trtp_rtcp_header.c b/tinyRTP/src/rtcp/trtp_rtcp_header.c
new file mode 100644
index 0000000..e93772a
--- /dev/null
+++ b/tinyRTP/src/rtcp/trtp_rtcp_header.c
@@ -0,0 +1,134 @@
+/*
+* 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.
+*
+*/
+#include "tinyrtp/rtcp/trtp_rtcp_header.h"
+
+#include "tnet_endianness.h"
+
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+/*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+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);
+}
+
+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;
+ }
+
+ 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;
+}
+
+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;
+}
+
+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;
+
+ return 0;
+}
+
+//=================================================================================================
+// RTCP header object definition
+//
+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;
+}
+
+static tsk_object_t* trtp_rtcp_header_dtor(tsk_object_t * self)
+{
+ trtp_rtcp_header_t *header = self;
+ if(header){
+ }
+
+ 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,
+};
+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
new file mode 100644
index 0000000..d2ec856
--- /dev/null
+++ b/tinyRTP/src/rtcp/trtp_rtcp_packet.c
@@ -0,0 +1,255 @@
+/*
+* 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.
+*
+*/
+#include "tinyrtp/rtcp/trtp_rtcp_packet.h"
+
+#include "tinyrtp/rtcp/trtp_rtcp_header.h"
+#include "tinyrtp/rtcp/trtp_rtcp_report_sdes.h"
+#include "tinyrtp/rtcp/trtp_rtcp_report_sr.h"
+#include "tinyrtp/rtcp/trtp_rtcp_report_rr.h"
+#include "tinyrtp/rtcp/trtp_rtcp_report_bye.h"
+#include "tinyrtp/rtcp/trtp_rtcp_report_fb.h"
+
+#include "tsk_debug.h"
+
+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;
+}
+
+static tsk_object_t* trtp_rtcp_packet_dtor(tsk_object_t * self)
+{
+ trtp_rtcp_packet_t *packet = self;
+ if(packet){
+
+ }
+
+ 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,
+};
+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;
+}
+
+
+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;
+}
+
+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;
+}
+
+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;
+ }
+ }
+}
+
+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;
+}
+
+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;
+}
+
+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 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);
+}
+
+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;
+ }
+ }
+}
+
+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;
+}
diff --git a/tinyRTP/src/rtcp/trtp_rtcp_rblock.c b/tinyRTP/src/rtcp/trtp_rtcp_rblock.c
new file mode 100644
index 0000000..9a85b4b
--- /dev/null
+++ b/tinyRTP/src/rtcp/trtp_rtcp_rblock.c
@@ -0,0 +1,153 @@
+/*
+* 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.
+*
+*/
+#include "tinyrtp/rtcp/trtp_rtcp_rblock.h"
+
+#include "tnet_endianness.h"
+#include "tsk_debug.h"
+
+/* 6.4.1 SR: Sender Report RTCP Packet
+
+ +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+report | SSRC_1 (SSRC of first source) |
+block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 1 | fraction lost | cumulative number of packets lost |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | extended highest sequence number received |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | interarrival jitter |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | last SR (LSR) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | delay since last SR (DLSR) |
+ +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+*/
+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;
+}
+static tsk_object_t* trtp_rtcp_rblock_dtor(tsk_object_t * self)
+{
+ trtp_rtcp_rblock_t *block = self;
+ if(block){
+ }
+
+ 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,
+};
+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);
+}
+
+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");
+ }
+
+ 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;
+
+ 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;
+}
+
+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;
+ }
+
+ 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;
+} \ No newline at end of file
diff --git a/tinyRTP/src/rtcp/trtp_rtcp_report.c b/tinyRTP/src/rtcp/trtp_rtcp_report.c
new file mode 100644
index 0000000..5fb2697
--- /dev/null
+++ b/tinyRTP/src/rtcp/trtp_rtcp_report.c
@@ -0,0 +1,21 @@
+/*
+* 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.
+*
+*/ \ No newline at end of file
diff --git a/tinyRTP/src/rtcp/trtp_rtcp_report_bye.c b/tinyRTP/src/rtcp/trtp_rtcp_report_bye.c
new file mode 100644
index 0000000..0f44608
--- /dev/null
+++ b/tinyRTP/src/rtcp/trtp_rtcp_report_bye.c
@@ -0,0 +1,225 @@
+/*
+* 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.
+*
+*/
+#include "tinyrtp/rtcp/trtp_rtcp_report_bye.h"
+#include "tinyrtp/rtcp/trtp_rtcp_header.h"
+
+#include "tnet_endianness.h"
+
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+#define TRTP_RTCP_PACKET_BYE_MIN_SIZE (TRTP_RTCP_HEADER_SIZE + 0/* could have zero ssrc */)
+
+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;
+}
+
+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;
+}
+
+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* 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* 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;
+}
+
+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;
+ }
+
+bail:
+ 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;
+ }
+
+bail:
+ 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;
+}
diff --git a/tinyRTP/src/rtcp/trtp_rtcp_report_fb.c b/tinyRTP/src/rtcp/trtp_rtcp_report_fb.c
new file mode 100644
index 0000000..bbc80b1
--- /dev/null
+++ b/tinyRTP/src/rtcp/trtp_rtcp_report_fb.c
@@ -0,0 +1,651 @@
+/*
+* 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.
+*
+*/
+#include "tinyrtp/rtcp/trtp_rtcp_report_fb.h"
+#include "tinyrtp/rtcp/trtp_rtcp_header.h"
+
+#include "tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#define TRTP_RTCP_PACKET_FB_MIN_SIZE (TRTP_RTCP_HEADER_SIZE + 4 + 4)
+
+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;
+}
+
+
+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;
+}
+
+
+
+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;
+}
+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,
+};
+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* 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* 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;
+}
+
+// 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* 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;
+}
+
+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;
+}
+
+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;
+}
+
+
+
+
+
+
+
+
+
+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;
+}
+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,
+};
+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* 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* 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* 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);
+}
+
+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* 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* 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;
+ }
+ }
+ }
+ }
+
+bail:
+ 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;
+}
+
+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;
+} \ 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
new file mode 100644
index 0000000..2a38a4c
--- /dev/null
+++ b/tinyRTP/src/rtcp/trtp_rtcp_report_rr.c
@@ -0,0 +1,232 @@
+/*
+* 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.
+*
+*/
+#include "tinyrtp/rtcp/trtp_rtcp_report_rr.h"
+#include "tinyrtp/rtcp/trtp_rtcp_header.h"
+
+#include "tnet_endianness.h"
+
+#include "tsk_debug.h"
+
+#define TRTP_RTCP_PACKET_RR_MIN_SIZE (TRTP_RTCP_HEADER_SIZE + 4)
+
+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;
+}
+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,
+};
+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* 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* 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* 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;
+ }
+
+bail:
+ 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;
+ }
+
+bail:
+ 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;
+} \ 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
new file mode 100644
index 0000000..4f5e944
--- /dev/null
+++ b/tinyRTP/src/rtcp/trtp_rtcp_report_sdes.c
@@ -0,0 +1,214 @@
+/*
+* 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.
+*
+*/
+#include "tinyrtp/rtcp/trtp_rtcp_report_sdes.h"
+#include "tinyrtp/rtcp/trtp_rtcp_header.h"
+
+#include "tsk_debug.h"
+
+/*
+6.5 SDES: Source Description RTCP Packet
+ 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 |
+ +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+chunk | SSRC/CSRC_1 |
+ 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SDES items |
+ | ... |
+ +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+chunk | SSRC/CSRC_2 |
+ 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SDES items |
+ | ... |
+ +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+*/
+
+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;
+}
+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,
+};
+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* 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* 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;
+ }
+ }
+
+bail:
+ 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;
+ }
+ }
+
+bail:
+ 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;
+}
+
+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;
+ }
+}
+
diff --git a/tinyRTP/src/rtcp/trtp_rtcp_report_sr.c b/tinyRTP/src/rtcp/trtp_rtcp_report_sr.c
new file mode 100644
index 0000000..5d8ceda
--- /dev/null
+++ b/tinyRTP/src/rtcp/trtp_rtcp_report_sr.c
@@ -0,0 +1,270 @@
+/*
+* 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.
+*
+*/
+#include "tinyrtp/rtcp/trtp_rtcp_report_sr.h"
+#include "tinyrtp/rtcp/trtp_rtcp_header.h"
+
+#include "tnet_endianness.h"
+
+#include "tsk_debug.h"
+
+#define TRTP_RTCP_PACKET_SR_MIN_SIZE (TRTP_RTCP_HEADER_SIZE + 4 + 20)
+
+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;
+}
+
+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;
+}
+
+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* 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* 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;
+ }
+
+bail:
+ 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;
+ }
+
+bail:
+ 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;
+}
+
+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;
+}
+
diff --git a/tinyRTP/src/rtcp/trtp_rtcp_report_xr.c b/tinyRTP/src/rtcp/trtp_rtcp_report_xr.c
new file mode 100644
index 0000000..5fb2697
--- /dev/null
+++ b/tinyRTP/src/rtcp/trtp_rtcp_report_xr.c
@@ -0,0 +1,21 @@
+/*
+* 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.
+*
+*/ \ No newline at end of file
diff --git a/tinyRTP/src/rtcp/trtp_rtcp_sdes_chunck.c b/tinyRTP/src/rtcp/trtp_rtcp_sdes_chunck.c
new file mode 100644
index 0000000..9104580
--- /dev/null
+++ b/tinyRTP/src/rtcp/trtp_rtcp_sdes_chunck.c
@@ -0,0 +1,190 @@
+/*
+* 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.
+*
+*/
+#include "tinyrtp/rtcp/trtp_rtcp_sdes_chunck.h"
+
+#include "tnet_endianness.h"
+
+#include "tsk_debug.h"
+
+/*
+Each chunk consists of an SSRC/CSRC identifier followed by a list of
+ zero or more items, which carry information about the SSRC/CSRC.
+ Each chunk starts on a 32-bit boundary. Each item consists of an 8-
+ bit type field, an 8-bit octet count describing the length of the
+ text (thus, not including this two-octet header), and the text
+ itself. Note that the text can be no longer than 255 octets, but
+ this is consistent with the need to limit RTCP bandwidth consumption.
+
++=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+| SSRC/CSRC_1 |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| SDES items |
+| ... |
++=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+*/
+
+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;
+}
+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);
+ }
+
+ 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,
+};
+const tsk_object_def_t *trtp_rtcp_sdes_chunck_def_t = &trtp_rtcp_sdes_chunck_def_s;
+
+
+
+trtp_rtcp_sdes_chunck_t* trtp_rtcp_sdes_chunck_create_null()
+{
+ 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* 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;
+}
+
+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;
+ }
+
+bail:
+ 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;
+}
+
+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;
+ }
+}
+
diff --git a/tinyRTP/src/rtcp/trtp_rtcp_sdes_item.c b/tinyRTP/src/rtcp/trtp_rtcp_sdes_item.c
new file mode 100644
index 0000000..7f22537
--- /dev/null
+++ b/tinyRTP/src/rtcp/trtp_rtcp_sdes_item.c
@@ -0,0 +1,148 @@
+/*
+* 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.
+*
+*/
+#include "tinyrtp/rtcp/trtp_rtcp_sdes_item.h"
+#include "tinyrtp/rtcp/trtp_rtcp_packet.h"
+
+#include "tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+#include <string.h> /* strlen() */
+
+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;
+}
+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);
+ }
+
+ 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,
+};
+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);
+}
+
+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* 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]);
+}
+
+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;
+}
+
+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;
+}
+
+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);
+ }
+}
+
diff --git a/tinyRTP/src/rtcp/trtp_rtcp_session.c b/tinyRTP/src/rtcp/trtp_rtcp_session.c
new file mode 100644
index 0000000..3172278
--- /dev/null
+++ b/tinyRTP/src/rtcp/trtp_rtcp_session.c
@@ -0,0 +1,1584 @@
+/*
+* 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.
+*
+*/
+/**@file trtp_rtcp_session.c
+ * @brief RTCP session.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+
+ */
+#include "tinyrtp/rtcp/trtp_rtcp_session.h"
+#include "tinyrtp/rtcp/trtp_rtcp_packet.h"
+#include "tinyrtp/rtcp/trtp_rtcp_header.h"
+#include "tinyrtp/rtcp/trtp_rtcp_report_rr.h"
+#include "tinyrtp/rtcp/trtp_rtcp_report_sr.h"
+#include "tinyrtp/rtcp/trtp_rtcp_report_sdes.h"
+#include "tinyrtp/rtcp/trtp_rtcp_report_bye.h"
+#include "tinyrtp/rtcp/trtp_rtcp_report_fb.h"
+#include "tinyrtp/rtp/trtp_rtp_packet.h"
+
+#include "ice/tnet_ice_ctx.h"
+#include "turn/tnet_turn_session.h"
+#include "tnet_transport.h"
+
+#include "tnet_utils.h"
+
+#include "tsk_string.h"
+#include "tsk_md5.h"
+#include "tsk_list.h"
+#include "tsk_time.h"
+#include "tsk_timer.h"
+#include "tsk_safeobj.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+#include <stdlib.h>
+#include <string.h>
+#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); }
+#endif
+
+#define RTCP_BW (160 * 50) // FIXME: default bandwidth (octet/second)
+#define CODEC_RATE 8000 // FIXME
+#define RTP_SEQ_MOD (1 << 16)
+#define MAX_DROPOUT 3000
+#define MAX_MISORDER 100
+#define MIN_SEQUENTIAL 2
+
+typedef double time_tp;
+typedef void* packet_;
+
+typedef enum event_
+{
+ EVENT_BYE,
+ EVENT_REPORT,
+ EVENT_RTP
+}
+event_;
+
+typedef enum PacketType_
+{
+ PACKET_RTCP_REPORT,
+ PACKET_BYE,
+ PACKET_RTP,
+}
+PacketType_;
+
+#define TypeOfEvent(e) (e)
+
+#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 */
+}
+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;
+}
+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,
+};
+const tsk_object_def_t *trtp_rtcp_source_def_t = &trtp_rtcp_source_def_s;
+
+static int _trtp_rtcp_source_init_seq(trtp_rtcp_source_t* self, uint16_t seq, uint32_t ts);
+static tsk_bool_t _trtp_rtcp_source_update_seq(trtp_rtcp_source_t* self, uint16_t seq, uint32_t ts);
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+static tsk_bool_t _trtp_rtcp_source_is_probed(const trtp_rtcp_source_t* self)
+{
+ return (self && self->probation == 0);
+}
+
+
+
+
+
+
+
+typedef time_tp (*tc_f)();
+static time_tp _trtp_rtcp_session_tc() { 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
+ 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,
+ 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>
+
+ trtp_rtcp_sources_L_t *sources;
+
+ TSK_DECLARE_SAFEOBJ;
+
+#if HAVE_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;
+}
+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);
+ 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);
+
+ 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,
+};
+const tsk_object_def_t *trtp_rtcp_session_def_t = &trtp_rtcp_session_def_s;
+
+
+static tsk_bool_t _trtp_rtcp_session_have_source(trtp_rtcp_session_t* self, uint32_t ssrc);
+static trtp_rtcp_source_t* _trtp_rtcp_session_find_source(trtp_rtcp_session_t* self, uint32_t ssrc);
+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);
+static int _trtp_rtcp_session_add_source(trtp_rtcp_session_t* self, trtp_rtcp_source_t* source);
+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);
+static int _trtp_rtcp_session_remove_source(trtp_rtcp_session_t* self, uint32_t ssrc, tsk_bool_t *removed);
+static tsk_size_t _trtp_rtcp_session_send_pkt(trtp_rtcp_session_t* self, trtp_rtcp_packet_t* pkt);
+static tsk_size_t _trtp_rtcp_session_send_raw(trtp_rtcp_session_t* self, const void* data, tsk_size_t size);
+static int _trtp_rtcp_session_timer_callback(const void* arg, tsk_timer_id_t timer_id);
+
+static void Schedule(trtp_rtcp_session_t* session, double tn, event_ e);
+static void OnReceive(trtp_rtcp_session_t* session, const packet_ p, event_ e, tsk_size_t ReceivedPacketSize);
+static void OnExpire(trtp_rtcp_session_t* session, event_ e);
+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);
+
+bail:
+ 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;
+}
+
+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 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;
+ }
+
+ tsk_safeobj_lock(self);
+ self->srtp.session = session;
+ tsk_safeobj_unlock(self);
+
+ 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)
+{
+ 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;
+}
+
+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 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 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 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 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 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;
+}
+
+// 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;
+}
+
+// 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);
+}
+
+tnet_fd_t trtp_rtcp_session_get_local_fd(const struct trtp_rtcp_session_s* self)
+{
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return TNET_INVALID_FD;
+ }
+ return self->local_fd;
+}
+
+int trtp_rtcp_session_set_local_fd(struct trtp_rtcp_session_s* self, tnet_fd_t local_fd)
+{
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->local_fd = local_fd;
+ return 0;
+}
+
+int trtp_rtcp_session_set_net_transport(struct trtp_rtcp_session_s* self, struct tnet_transport_s* transport)
+{
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ TSK_OBJECT_SAFE_FREE(self->transport);
+ self->transport = tsk_object_ref(transport);
+ return 0;
+}
+
+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;
+}
+
+// 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;
+}
+
+// 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;
+}
+
+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;
+ }
+
+ 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;
+}
+
+// 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;
+ }
+ }
+
+ tsk_list_unlock(self->sources);
+
+ if((source = _trtp_rtcp_source_create(ssrc, seq, ts))){
+ ret = _trtp_rtcp_session_add_source(self, source);
+ }
+
+ TSK_OBJECT_SAFE_FREE(source);
+
+ *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;
+}
+
+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;
+
+ 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);
+#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;
+#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");
+ }
+ }
+#endif
+ ret = _trtp_rtcp_session_send_raw(self, data, size);
+ TSK_OBJECT_SAFE_FREE(buffer);
+ }
+
+ 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 {
+ 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;
+}
+
+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;
+}
+
+static tsk_bool_t IsRtpPacket(const packet_ p)
+{
+ 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;
+ }
+ }
+}
+
+// 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);
+}
+
+#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;
+ }
+ }
+
+ 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;
+}
+
+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;
+}
+
+#define AddMember(session, p) AddMember_((session), (p), tsk_false)
+#define AddSender(session, p) AddMember_((session), (p), tsk_true)
+
+
+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;
+ }
+ }
+
+ 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;
+}
+
+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;
+}
+
+#define RemoveSender(session, p) RemoveMember((session), (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;
+
+ if(!session->remote_addr || session->local_fd <= 0){
+ TSK_DEBUG_ERROR("Invalid network settings");
+ return;
+ }
+
+ tsk_safeobj_lock(session);
+
+#if HAVE_SRTP
+ 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 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");
+ }
+ }
+#endif
+ _trtp_rtcp_session_send_raw(session, data, size);
+ TSK_OBJECT_SAFE_FREE(buffer);
+ }
+ TSK_OBJECT_SAFE_FREE(bye);
+ }
+
+ 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;
+#if 1
+ 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);
+#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())){
+ uint32_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);
+}
+
+#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)
+{
+ /*
+ * 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);
+#if 0
+ exit(1);
+#endif
+ } else {
+#if 0
+ Schedule(session, tn, e);
+#else
+ 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);
+#if 0
+ Schedule(session, t+tc, e);
+#else
+ Schedule(session, t, e);
+#endif
+ session->initial = tsk_false;
+ } else {
+#if 0
+ Schedule(session, tn, e);
+#else
+ Schedule(session, 0, e);
+#endif
+ }
+ 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) {
+#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;
+ }
+#else
+ 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;
+#if 0
+ 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));
+
+ /* Reschedule the next report for time tn */
+
+ Reschedule(session, session->tn, e);
+ session->pmembers = session->members;
+ }
+
+ } 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
new file mode 100644
index 0000000..e833b10
--- /dev/null
+++ b/tinyRTP/src/rtp/trtp_rtp_header.c
@@ -0,0 +1,259 @@
+/*
+* 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.
+*
+*/
+/**@file trtp_rtp_header.c
+ * @brief RTP header.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+
+ */
+#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 = 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));
+}
+
+/* serialize the RTP header to a buffer */
+// the buffer size must be at least equal to "trtp_rtp_header_guess_serialbuff_size()"
+// 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;
+}
+
+/** 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;
+}
+
+/** 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;
+}
+
+
+
+
+
+
+//=================================================================================================
+// 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;
diff --git a/tinyRTP/src/rtp/trtp_rtp_packet.c b/tinyRTP/src/rtp/trtp_rtp_packet.c
new file mode 100644
index 0000000..dc5c7ea
--- /dev/null
+++ b/tinyRTP/src/rtp/trtp_rtp_packet.c
@@ -0,0 +1,260 @@
+/*
+* 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.
+*
+*/
+/**@file trtp_rtp_packet.c
+ * @brief RTP packet.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+
+ */
+#include "tinyrtp/rtp/trtp_rtp_packet.h"
+
+#include "tnet_endianness.h"
+
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+#include <string.h> /* 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;
+}
+
+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;
+}
+
+/* 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;
+}
+
+/* serialize the RTP packet to a buffer */
+// the buffer size must be at least equal to "trtp_rtp_packet_guess_serialbuff_size()"
+// 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;
+}
+
+/** Serialize rtp packet object into binary buffer */
+// num_bytes_pad: number of bytes to add to the buffer. Useful to have the packet byte aligned or to prepare for SRTP protection
+// 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;
+}
+
+/** 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;
+}
+
+
+
+
+
+
+
+
+
+//=================================================================================================
+// 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;
+}
+// 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;
+}
+
+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
new file mode 100644
index 0000000..3ebfe03
--- /dev/null
+++ b/tinyRTP/src/rtp/trtp_rtp_session.c
@@ -0,0 +1,29 @@
+/*
+* 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.
+*
+*/
+/**@file trtp_rtp_session.c
+ * @brief RTP session.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+
+ */
+#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..a0150d9
--- /dev/null
+++ b/tinyRTP/src/trtp.c
@@ -0,0 +1,30 @@
+/*
+* 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.
+*
+*/
+/**@file trtp.h
+ * @brief tinyRTP (Real-time Transport Protocol) as per RFC 3550.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+
+ */
+#include "tinyrtp/trtp.h"
+
diff --git a/tinyRTP/src/trtp_manager.c b/tinyRTP/src/trtp_manager.c
new file mode 100644
index 0000000..6e6b00e
--- /dev/null
+++ b/tinyRTP/src/trtp_manager.c
@@ -0,0 +1,1960 @@
+/*
+* 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.
+*
+*/
+/**@file trtp_manager.c
+* @brief RTP/RTCP manager.
+*
+*/
+#include "tinyrtp/trtp_manager.h"
+
+#include "tinyrtp/rtp/trtp_rtp_packet.h"
+#include "tinyrtp/rtcp/trtp_rtcp_packet.h"
+#include "tinyrtp/rtcp/trtp_rtcp_session.h"
+
+#include "tnet_proxydetect.h"
+#include "turn/tnet_turn_session.h"
+#include "ice/tnet_ice_candidate.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_base64.h"
+#include "tsk_md5.h"
+#include "tsk_debug.h"
+
+#include <limits.h> /* INT_MAX */
+
+#if !defined(TRTP_TRANSPORT_NAME)
+# define TRTP_TRANSPORT_NAME "RTP/RTCP Manager"
+#endif
+
+#if !defined(TRTP_DISABLE_SOCKETS_BEFORE_START)
+# define TRTP_DISABLE_SOCKETS_BEFORE_START 0
+#endif
+#if !defined(TRTP_TINY_RCVBUF)
+# define TRTP_TINY_RCVBUF (256>>1/*Will be doubled and min on linux is 256*/) /* tiny buffer used to disable receiving */
+#endif
+
+#if !defined(TRTP_DSCP_RTP_DEFAULT)
+# define TRTP_DSCP_RTP_DEFAULT /* 0x2e */ 0x00
+#endif
+
+#if !defined(TRTP_PORT_RANGE_START)
+# define TRTP_PORT_RANGE_START 1024
+#endif
+#if !defined(TRTP_PORT_RANGE_STOP)
+# define TRTP_PORT_RANGE_STOP 65535
+#endif
+
+#if !defined(TRTP_DTLS_HANDSHAKING_TIMEOUT)
+# define TRTP_DTLS_HANDSHAKING_TIMEOUT 1000
+#endif
+#if !defined(TRTP_DTLS_HANDSHAKING_TIMEOUT_MAX)
+# define TRTP_DTLS_HANDSHAKING_TIMEOUT_MAX (TRTP_DTLS_HANDSHAKING_TIMEOUT << 20)
+#endif
+
+static const tmedia_srtp_type_t __srtp_types[] = { tmedia_srtp_type_sdes, tmedia_srtp_type_dtls };
+
+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);
+#define _trtp_manager_is_rtcpmux_active(self) ( (self) && ( (self)->use_rtcpmux && (!(self)->rtcp.local_socket || ((self)->transport && (self)->transport->master && (self)->transport->master->fd == (self)->rtcp.local_socket->fd)) ) )
+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);
+#define _trtp_manager_send_turn_dtls_rtp(ice_ctx, handshaking_data_ptr, handshaking_data_size) _trtp_manager_send_turn_dtls((ice_ctx), (handshaking_data_ptr), (handshaking_data_size), /*use_rtcp_channel =*/tsk_false)
+#define _trtp_manager_send_turn_dtls_rtcp(ice_ctx, handshaking_data_ptr, handshaking_data_size) _trtp_manager_send_turn_dtls((ice_ctx), (handshaking_data_ptr), (handshaking_data_size), /*use_rtcp_channel =*/tsk_true)
+#if HAVE_SRTP
+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);
+static int _trtp_manager_srtp_activate(trtp_manager_t* self, tmedia_srtp_type_t srtp_type);
+static int _trtp_manager_srtp_start(trtp_manager_t* self, tmedia_srtp_type_t srtp_type);
+#endif /* HAVE_SRTP */
+
+
+/* ======================= 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:
+ {
+ tsk_safeobj_lock(manager);
+ tnet_fd_t broken_fd = e->local_fd;
+ tnet_socket_t* socket = tsk_null;
+ tsk_bool_t 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 (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;
+ }
+#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;
+
+#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);
+#else
+ 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);
+#else
+ 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;
+ }
+#endif /* HAVE_SRTP */
+
+ 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;
+#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);
+#endif
+
+ 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;
+}
+#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;
+
+#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);
+ }
+#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 HAVE_SRTP
+ manager->srtp_type = srtp_type;
+ manager->srtp_mode = srtp_mode;
+#endif
+ 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){
+ 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'");
+ return 0;
+ }
+ else {
+ 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){
+ 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'");
+ return 0;
+ }
+ else {
+ 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;
+}
+
+// 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;
+}
+
+#if HAVE_SRTP
+/*
+Enables SDES-SRTP and DTLS-SRTP
+Enabling SRTP will allow us to get "crypto" lines for negotiation
+At this stage the sockets are not ready to send DTLS datagrams -> Good for ICE negotiation
+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;
+}
+
+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;
+}
+
+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;
+}
+
+#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
+
+bail:
+ 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;
+}
+
+/** 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;
+}
+
+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;
+}
+
+/** 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;
+#if 0
+ 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);
+#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) */
+#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);
+ }
+#endif
+ }
+
+ /* 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);
+ }
+ }
+#endif
+
+ 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;
+}
+
+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;
+}
+
+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;
+}
+
+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);
+}
+
+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;
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+/** 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;
+}
+
+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);
+}
+
+#endif /* HAVE_SRTP */
+
+/** 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);
+}
+
+/** 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
+#if 0
+ _trtp_manager_enable_sockets(self);
+#endif
+ }
+ 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;
+ }
+
+ self->rtp.cb.fun = fun;
+ self->rtp.cb.usrdata = usrdata;
+
+ 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;
+}
+
+/** 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;
+}
+
+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;
+}
+
+/** 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;
+}
+
+/** 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;
+}
+
+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;
+}
+
+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;
+}
+
+int trtp_manager_set_proxy_auto_detect(trtp_manager_t* self, tsk_bool_t auto_detect)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->proxy.auto_detect = auto_detect;
+ return 0;
+}
+
+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){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!self->proxy.info && !(self->proxy.info = tnet_proxyinfo_create())) {
+ return -2;
+ }
+ self->proxy.info->type = type;
+ self->proxy.info->port = port;
+ tsk_strupdate(&self->proxy.info->hostname, host);
+ tsk_strupdate(&self->proxy.info->username, login);
+ tsk_strupdate(&self->proxy.info->password, password);
+ return 0;
+}
+
+/** 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();
+#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;
+ }
+
+ /* Proxy */
+ // Proxy info
+ if ((ret = tnet_transport_set_proxy_auto_detect(self->transport, self->proxy.auto_detect))) {
+ TSK_DEBUG_ERROR("Failed to set proxy autodetect option");
+ goto bail;
+ }
+ if (self->proxy.info) {
+ if ((ret = tnet_transport_set_proxy_info(self->transport, self->proxy.info->type, self->proxy.info->hostname, self->proxy.info->port, self->proxy.info->username, self->proxy.info->password))) {
+ TSK_DEBUG_ERROR("Failed to set proxy info");
+ goto bail;
+ }
+ }
+
+ /* 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);
+#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");
+ }
+
+ /* 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);
+ }
+#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);
+ 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 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);
+ }
+ }
+#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;
+ }
+
+ self->is_started = tsk_true;
+
+bail:
+
+ tsk_safeobj_unlock(self);
+
+ return ret;
+}
+
+/* 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;
+ }
+#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;
+ }
+#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 */
+#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
+
+ 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);
+
+ // 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;
+ }
+#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);
+ }
+#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;
+#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;
+ }
+ }
+#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");
+ }
+
+bail:
+ 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 {
+#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
+#endif
+ }
+ tsk_safeobj_unlock(self);
+ return ret;
+}
+
+int trtp_manager_get_bytes_count(trtp_manager_t* self, uint64_t* bytes_in, uint64_t* bytes_out)
+{
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ 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;
+ 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)
+{
+ 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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+/** Stops the RTP/RTCP manager */
+int trtp_manager_stop(trtp_manager_t* self)
+{
+ int ret = 0;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ TSK_DEBUG_INFO("trtp_manager_stop()");
+
+ 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);
+ //}
+
+ // 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);
+ 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);
+#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);
+ }
+#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(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;
+
+ self->is_started = tsk_false;
+
+ tsk_safeobj_unlock(self);
+
+ return ret;
+}
+
+
+
+
+//=================================================================================================
+// RTP manager object definition
+//
+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 */
+#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;
+#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();
+ manager->rtp.dscp = TRTP_DSCP_RTP_DEFAULT;
+
+ /* rtcp */
+ {
+ // use MD5 string to avoid padding issues
+ tsk_md5string_t md5 = { 0 };
+ tsk_sprintf(&manager->rtcp.cname, "doubango.%llu", (tsk_time_now() + rand()));
+ tsk_md5compute(manager->rtcp.cname, tsk_strlen(manager->rtcp.cname), &md5);
+ tsk_strupdate(&manager->rtcp.cname, md5);
+ }
+
+ /* timer */
+ manager->timer_mgr_global = tsk_timer_mgr_global_ref();
+
+ 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 */
+#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);
+ }
+#endif /* HAVE_SRTP */
+
+ /* 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);
+ }
+
+ /* Proxy */
+ TSK_OBJECT_SAFE_FREE(manager->proxy.info);
+
+ tsk_safeobj_deinit(manager);
+
+ TSK_DEBUG_INFO("*** RTP manager destroyed ***");
+ }
+
+ 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;
diff --git a/tinyRTP/src/trtp_srtp.c b/tinyRTP/src/trtp_srtp.c
new file mode 100644
index 0000000..5e2d033
--- /dev/null
+++ b/tinyRTP/src/trtp_srtp.c
@@ -0,0 +1,332 @@
+/*
+ * 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.
+ *
+ */
+/**@file trtp_srtp.c
+ */
+#include "tinyrtp/trtp_srtp.h"
+#include "tinyrtp/trtp_manager.h"
+
+#if HAVE_SRTP
+
+extern err_status_t
+crypto_get_random(unsigned char *buffer, unsigned int length);
+
+int trtp_srtp_ctx_internal_init(struct trtp_srtp_ctx_internal_xs* ctx, int32_t tag, trtp_srtp_crypto_type_t type, uint32_t ssrc)
+{
+ 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-)
+ if ((srtp_err = crypto_get_random((unsigned char*)ctx->key_bin, sizeof(ctx->key_bin))) != err_status_ok) {
+ TSK_DEBUG_ERROR("crypto_get_random() failed");
+ return -2;
+ }
+ size = tsk_base64_encode((const uint8_t*)ctx->key_bin, sizeof(ctx->key_bin), &key_str);
+ 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;
+ }
+ }
+
+ ctx->policy.key = (unsigned char*)ctx->key_bin;
+ ctx->policy.ssrc.type = ssrc_any_outbound;
+ ctx->policy.ssrc.value = ssrc;
+ ctx->policy.window_size = 2048;
+ ctx->policy.allow_repeat_tx = 1;
+ if ((srtp_err = srtp_create(&ctx->session, &ctx->policy)) != err_status_ok) {
+ TSK_DEBUG_ERROR("srtp_create() failed");
+ return -3;
+ }
+ ctx->initialized = tsk_true;
+ return 0;
+}
+
+int trtp_srtp_ctx_internal_deinit(struct trtp_srtp_ctx_internal_xs* ctx)
+{
+ if(!ctx){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if(ctx->initialized){
+ /*err_status_t srtp_err =*/ srtp_dealloc(ctx->session);
+ memset(&ctx->policy, 0, sizeof(ctx->policy));
+ ctx->initialized = tsk_false;
+ }
+ return 0;
+}
+
+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){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ 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);
+}
+
+int trtp_srtp_ctx_deinit(trtp_srtp_ctx_xt* ctx)
+{
+ int ret;
+ if(!ctx){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if((ret = trtp_srtp_ctx_internal_deinit(&ctx->rtp))){
+ return ret;
+ }
+ return trtp_srtp_ctx_internal_deinit(&ctx->rtcp);
+}
+
+int trtp_srtp_match_line(const char* crypto_line, int32_t* tag, int32_t* crypto_type, char* key, tsk_size_t key_size)
+{
+ char* copyptr = tsk_strdup(crypto_line); // "strtok_r" will insert "\0" and modify the string
+ char* saveptr = tsk_null;
+ 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;
+ }
+ 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 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);
+ }
+bail:
+ TSK_FREE(copyptr);
+ return ret;
+}
+
+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){
+ 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];
+ }
+ if (contexts_count > ret && rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32].rtp.initialized) {
+ contexts[ret++] = &rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32];
+ }
+ return ret;
+}
+
+int trtp_srtp_set_crypto(struct trtp_manager_s* rtp_mgr, const char* crypto_line, int32_t idx)
+{
+ //e.g. 2 F8_128_HMAC_SHA1_80 inline:MTIzNDU2Nzg5QUJDREUwMTIzNDU2Nzg5QUJjZGVm|2^20|1:4;inline:QUJjZGVmMTIzNDU2Nzg5QUJDREUwMTIzNDU2Nzg5|2^20|2:4"
+ trtp_srtp_ctx_xt* srtp_ctx;
+ int ret;
+ uint8_t *key_bin;
+ 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 =
+ 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 =
+ rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_LOCAL][HMAC_SHA1_32].rtcp.tag = srtp_ctx->rtp.tag;
+ }
+ 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;
+ srtp_ctx->rtp.policy.ssrc.type = idx == TRTP_SRTP_LINE_IDX_REMOTE ? ssrc_any_inbound : ssrc_any_outbound;
+ srtp_ctx->rtp.policy.window_size = 2048;
+ srtp_ctx->rtp.policy.allow_repeat_tx = 1;
+ if ((srtp_err = srtp_create(&srtp_ctx->rtp.session, &srtp_ctx->rtp.policy)) != err_status_ok) {
+ TSK_DEBUG_ERROR("srtp_create() failed: %d", srtp_err);
+ return -3;
+ }
+ srtp_ctx->rtp.initialized = tsk_true;
+ return 0;
+}
+
+int trtp_srtp_set_key_and_salt(trtp_manager_t* rtp_mgr, trtp_srtp_crypto_type_t crypto_type, const void* key, tsk_size_t key_size, const void* salt, tsk_size_t salt_size, int32_t idx, tsk_bool_t is_rtp)
+{
+ int ret;
+ trtp_srtp_ctx_internal_xt* srtp_ctx;
+ err_status_t srtp_err;
+ if (!rtp_mgr || !key || !key_size || !salt || !salt_size) {
+ 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;
+ }
+ }
+
+ 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){
+ TSK_DEBUG_ERROR("srtp_create() failed: %d", srtp_err);
+ return -3;
+ }
+ srtp_ctx->initialized = tsk_true;
+ return 0;
+}
+
+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)
+ && rtp_mgr->srtp_contexts[TRTP_SRTP_LINE_IDX_REMOTE][0].rtp.initialized);
+}
+
+tsk_bool_t trtp_srtp_is_started(trtp_manager_t* rtp_mgr)
+{
+ if (!rtp_mgr) {
+ TSK_DEBUG_ERROR("Invalid argument");
+ return tsk_false;
+ }
+ return (rtp_mgr ->srtp_ctx_neg_remote && rtp_mgr ->srtp_ctx_neg_local);
+}
+
+#endif /* HAVE_SRTP */ \ No newline at end of file
diff --git a/tinyRTP/test/test.c b/tinyRTP/test/test.c
new file mode 100644
index 0000000..f0f15f6
--- /dev/null
+++ b/tinyRTP/test/test.c
@@ -0,0 +1,65 @@
+/*
+* Copyright (C) 2009 Mamadou Diop.
+*
+* 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 Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+#include <string.h>
+#include <stdlib.h>
+
+#include "tinyrtp.h"
+
+#define LOOP 1
+
+#define RUN_TEST_ALL 0
+#define RUN_TEST_PARSER 0
+#define RUN_TEST_MANAGER 1
+
+#include "test_parser.h"
+#include "test_manager.h"
+
+
+
+#ifdef _WIN32_WCE
+int _tmain(int argc, _TCHAR* argv[])
+#else
+int main()
+#endif
+{
+ tnet_startup();
+
+ do{
+ /* Print copyright information */
+ printf("Doubango Project\nCopyright (C) 2009-2010 Mamadou Diop \n\n");
+
+#if RUN_TEST_PARSER || RUN_TEST_ALL
+ test_parser();
+#endif
+
+#if RUN_TEST_MANAGER || RUN_TEST_ALL
+ test_manager();
+#endif
+
+ }
+ while(LOOP);
+
+ tnet_cleanup();
+
+ return 0;
+}
+
diff --git a/tinyRTP/test/test.vcproj b/tinyRTP/test/test.vcproj
new file mode 100644
index 0000000..53adaaf
--- /dev/null
+++ b/tinyRTP/test/test.vcproj
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="test"
+ ProjectGUID="{A6C1CDCE-63E1-4B60-AC4C-EF0410ED4432}"
+ RootNamespace="test"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\thirdparties\win32\include;..\..\tinyRTP\include;..\..\tinySAK\src;..\..\tinyNET\src"
+ PreprocessorDefinitions="DEBUG_LEVEL=DEBUG_LEVEL_INFO;WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="$(OutDir)\tinySAK.lib $(OutDir)\tinyNET.lib $(OutDir)\tinyRTP.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="source"
+ >
+ <File
+ RelativePath=".\test.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="include"
+ >
+ </Filter>
+ <Filter
+ Name="tests"
+ >
+ <File
+ RelativePath=".\test_manager.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_parser.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/tinyRTP/test/test_manager.h b/tinyRTP/test/test_manager.h
new file mode 100644
index 0000000..29c2dcc
--- /dev/null
+++ b/tinyRTP/test/test_manager.h
@@ -0,0 +1,69 @@
+/*
+* Copyright (C) 2009 Mamadou Diop.
+*
+* 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 Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef _TEST_MANAGER_H_
+#define _TEST_MANAGER_H_
+
+void test_manager()
+{
+ tsk_size_t i;
+ trtp_manager_t* manager;
+
+ if(!(manager = trtp_manager_create(tsk_true, "192.168.0.12", tsk_false))){
+ goto bail;
+ }
+
+ trtp_manager_set_payload_type(manager, 8);
+
+ /* Prepare: this will allow you to generate local port and ip */
+ if(trtp_manager_prepare(manager)){
+ goto bail;
+ }
+
+ /* set remote parameters (rtcp ip:port not mandator, could be retrieved from rtp values) */
+ if(trtp_manager_set_rtp_remote(manager, "192.168.0.13", 5081)){
+ goto bail;
+ }
+ if(trtp_manager_set_rtcp_remote(manager, "192.168.0.13", 2861)){
+ goto bail;
+ }
+
+ /* start */
+ if(trtp_manager_start(manager)){
+ goto bail;
+ }
+
+ /* send data */
+ for(i=0;i<2; i++){
+ if(trtp_manager_send_rtp(manager, "test", tsk_strlen("test"), 160, tsk_true)){
+ goto bail;
+ }
+ }
+
+ getchar();
+
+bail:
+ /* stop and destroy */
+ TSK_OBJECT_SAFE_FREE(manager);
+}
+
+#endif /* _TEST_MANAGER_H_ */
+
diff --git a/tinyRTP/test/test_parser.h b/tinyRTP/test/test_parser.h
new file mode 100644
index 0000000..a65b816
--- /dev/null
+++ b/tinyRTP/test/test_parser.h
@@ -0,0 +1,331 @@
+/*
+* Copyright (C) 2009 Mamadou Diop.
+*
+* 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 Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+#ifndef _TEST_PARSER_H_
+#define _TEST_PARSER_H_
+
+char packet_0[] = {
+0x80, 0x88, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0,
+0xd2, 0xbd, 0x4e, 0x3e, 0xdc, 0xde, 0xc4, 0xc5,
+0xdc, 0xd0, 0xd5, 0x51, 0x53, 0x5d, 0x5f, 0x5b,
+0x46, 0x46, 0x46, 0x5b, 0x44, 0x41, 0x42, 0x4f,
+0x42, 0x47, 0x42, 0x43, 0x59, 0x58, 0x59, 0x5f,
+0x5f, 0x52, 0x59, 0x44, 0x44, 0x5f, 0x51, 0x54,
+0x55, 0x55, 0x51, 0x56, 0x50, 0x52, 0x5e, 0x58,
+0x5d, 0x52, 0x52, 0x50, 0x57, 0x54, 0xd4, 0xd6,
+0xd5, 0x51, 0x53, 0x57, 0xd6, 0xd6, 0xd0, 0xd7,
+0x57, 0x56, 0x57, 0xd0, 0xd3, 0xd6, 0xd5, 0x55,
+0x51, 0x50, 0xd6, 0xdf, 0xd2, 0xd1, 0xd4, 0xd6,
+0xdc, 0xdb, 0xda, 0xdd, 0xd6, 0x55, 0xdc, 0xd0,
+0xd4, 0x5d, 0x44, 0x5c, 0x56, 0xd6, 0xd5, 0xd4,
+0xd5, 0xd7, 0x50, 0xd4, 0x51, 0xd0, 0x61, 0x6f,
+0x76, 0xfe, 0xef, 0xf7, 0x77, 0x66, 0x50, 0xff,
+0xe5, 0xd7, 0x74, 0x4a, 0xc9, 0xf9, 0xf7, 0x5c,
+0x76, 0x5f, 0xf5, 0xf3, 0xdd, 0x4e, 0x42, 0xd8,
+0xf7, 0xc9, 0x50, 0x44, 0x50, 0xcd, 0xc9, 0xd4,
+0x4d, 0x41, 0x57, 0xd1, 0x51, 0x58, 0x44, 0x52,
+0xd3, 0xd1, 0x50, 0x58, 0x5b, 0x55, 0xd4, 0x53,
+0x59, 0x43, 0x47, 0x5f, 0x51, 0x5d, 0x56, 0xd2,
+0xde, 0xd7, 0x52, 0xd5 };
+char packet_1[] = {
+0x80, 0x08, 0x00, 0x02, 0x00, 0x00, 0x01, 0x40,
+0xd2, 0xbd, 0x4e, 0x3e, 0xd2, 0xc7, 0xc5, 0xd3,
+0xd1, 0xd6, 0xd5, 0x55, 0xd2, 0xd2, 0xd3, 0xdf,
+0xc4, 0xd9, 0xdb, 0xc6, 0xc6, 0xc9, 0xc1, 0xf5,
+0xcf, 0xf0, 0xcb, 0xe4, 0x7d, 0x14, 0x7a, 0xfd,
+0xfd, 0x62, 0x63, 0x41, 0xee, 0xe7, 0x40, 0x6c,
+0x46, 0xf8, 0xf3, 0x74, 0x7b, 0x58, 0xf3, 0xf1,
+0xd6, 0x5d, 0xc7, 0xfd, 0xff, 0xf5, 0x55, 0xd9,
+0xcb, 0xcb, 0xde, 0xd1, 0xda, 0xca, 0xcd, 0xc5,
+0xc4, 0x41, 0x72, 0x41, 0x55, 0xda, 0x54, 0x5c,
+0x40, 0x59, 0xd1, 0x5f, 0x4b, 0x40, 0x51, 0x52,
+0x45, 0x4b, 0x77, 0x49, 0x4e, 0x4e, 0x48, 0x4a,
+0x75, 0x47, 0x75, 0x7b, 0x72, 0x42, 0x58, 0x4c,
+0x46, 0xd5, 0xc2, 0xd1, 0x5d, 0x44, 0x50, 0xd0,
+0x53, 0x43, 0x41, 0x52, 0x53, 0x5a, 0x44, 0x50,
+0xdd, 0x45, 0x65, 0x7d, 0x74, 0x4c, 0x70, 0x43,
+0x53, 0xc4, 0xc5, 0x5b, 0x5a, 0x5c, 0x51, 0x4f,
+0x70, 0x4a, 0x58, 0x5e, 0x75, 0x76, 0x40, 0x57,
+0x51, 0x46, 0x5e, 0x5c, 0xd5, 0x5c, 0x5c, 0x5e,
+0x5e, 0x4d, 0x41, 0x44, 0xd4, 0xd6, 0xd5, 0x52,
+0x54, 0xdd, 0xd7, 0xd3, 0x56, 0x51, 0x55, 0xdf,
+0x54, 0xd1, 0xd2, 0xda };
+char packet_2[] = {
+0x80, 0x08, 0x00, 0x03, 0x00, 0x00, 0x01, 0xe0,
+0xd2, 0xbd, 0x4e, 0x3e, 0xdb, 0xd1, 0xd5, 0xd0,
+0xd2, 0xd3, 0x57, 0xd5, 0xd6, 0xd6, 0xd1, 0xd5,
+0xd1, 0xdd, 0xd5, 0xd1, 0xd1, 0xd4, 0x5f, 0x56,
+0x5f, 0x5a, 0x53, 0x59, 0x5c, 0x5f, 0x5d, 0x5d,
+0xd6, 0xd0, 0xd8, 0x54, 0xc4, 0xd9, 0xc6, 0xdc,
+0x57, 0x56, 0x56, 0x57, 0x51, 0x54, 0x53, 0x57,
+0x59, 0x44, 0x44, 0x5e, 0x45, 0x45, 0x5a, 0x5e,
+0x53, 0x58, 0x4c, 0x45, 0x59, 0x45, 0x5b, 0x57,
+0x52, 0x5e, 0x5e, 0x59, 0x5c, 0x51, 0xd7, 0xd0,
+0xc5, 0xc1, 0xd8, 0xc1, 0xcd, 0xcd, 0xc2, 0xcd,
+0xc6, 0xcc, 0xc0, 0xc6, 0xc1, 0xc9, 0xcb, 0xdb,
+0xd0, 0xdd, 0xc6, 0xd8, 0xd5, 0x5f, 0x41, 0x46,
+0x4f, 0x74, 0x76, 0x70, 0x72, 0x7f, 0x72, 0x77,
+0x49, 0x4a, 0x76, 0x4a, 0x44, 0x45, 0x44, 0x59,
+0x50, 0x55, 0xd3, 0xd9, 0xcc, 0xf7, 0xf1, 0xca,
+0xc2, 0xf7, 0xf8, 0xe7, 0xe7, 0xe2, 0xee, 0xe9,
+0xed, 0xe4, 0xc2, 0xcb, 0xf7, 0xd2, 0x48, 0x76,
+0x45, 0x77, 0x64, 0x64, 0x4a, 0x51, 0x46, 0x41,
+0xdd, 0xc2, 0xd4, 0x51, 0x50, 0x4a, 0x74, 0x71,
+0x7e, 0x61, 0x67, 0x7e, 0x67, 0x60, 0x67, 0x77,
+0x45, 0x43, 0x5f, 0xc8 };
+char packet_3[] = {
+0x80, 0x08, 0x2c, 0x43, 0x11, 0x47, 0x31, 0xa2,
+0x58, 0xf3, 0x3d, 0xea, 0x53, 0x45, 0x56, 0x47,
+0x5f, 0xd4, 0xd4, 0x55, 0x56, 0x58, 0x40, 0x53,
+0x54, 0xd5, 0xc7, 0xc4, 0x57, 0xd5, 0xdd, 0xd9,
+0xde, 0xdd, 0xdc, 0xd4, 0x55, 0x54, 0xdc, 0xcf,
+0xc7, 0x5e, 0x43, 0x5a, 0x5a, 0x43, 0x5b, 0x51,
+0x54, 0x51, 0xd6, 0xd4, 0x5b, 0x53, 0xd3, 0x57,
+0xd5, 0xc0, 0xc7, 0x53, 0x5d, 0xd1, 0xc5, 0xc1,
+0xd9, 0x5d, 0x57, 0xdc, 0xd0, 0xd0, 0x54, 0x45,
+0x44, 0x42, 0x45, 0xd0, 0xd4, 0xd5, 0xd9, 0xc7,
+0x57, 0x5e, 0x5f, 0x47, 0x56, 0xc5, 0xca, 0xc5,
+0xd3, 0xdf, 0x57, 0x43, 0x4b, 0x5a, 0x5c, 0x5f,
+0x45, 0x52, 0xd0, 0xc7, 0xcb, 0xc9, 0xc5, 0x5f,
+0x47, 0x57, 0x55, 0xdc, 0xc7, 0x5d, 0x4b, 0x5a,
+0xdb, 0xcf, 0xc5, 0x52, 0x43, 0x5a, 0x56, 0xde,
+0xdf, 0xd6, 0xd5, 0x45, 0x5b, 0xdc, 0xdb, 0x55,
+0x52, 0x54, 0x51, 0xd5, 0xc4, 0xdf, 0xd1, 0x56,
+0x51, 0xd5, 0xd3, 0xde, 0x54, 0x44, 0x46, 0x52,
+0x56, 0x5b, 0x5a, 0xd3, 0xc3, 0xdf, 0x57, 0xd1,
+0xd9, 0xd6, 0x5f, 0x5f, 0xd4, 0xd6, 0xd5, 0xd1,
+0x53, 0xd4, 0xc1, 0xdb, 0xdd, 0xd8, 0xd7, 0x47,
+0x4b, 0x75, 0x4c, 0x5c };
+char packet_4[] = {
+0x80, 0x08, 0x00, 0x04, 0x00, 0x00, 0x02, 0x80,
+0xd2, 0xbd, 0x4e, 0x3e, 0xff, 0xf3, 0xff, 0xe1,
+0xe7, 0xe4, 0xe5, 0xe2, 0xec, 0xef, 0xeb, 0xe9,
+0x95, 0x97, 0xf8, 0xcc, 0xe4, 0xf9, 0x58, 0x6d,
+0x72, 0x46, 0x7c, 0x62, 0x60, 0x42, 0x40, 0x70,
+0x4e, 0xd3, 0xcb, 0xda, 0xd9, 0x54, 0x57, 0xd6,
+0x4a, 0x62, 0x6e, 0x64, 0x60, 0x15, 0x15, 0x63,
+0x67, 0x62, 0x60, 0x7f, 0x46, 0x46, 0x40, 0xd5,
+0xcf, 0xf6, 0xc9, 0xcb, 0xf0, 0xfd, 0xf8, 0xe6,
+0xec, 0xe9, 0x94, 0x91, 0x96, 0xf7, 0xd0, 0xe7,
+0xf3, 0x7d, 0x6b, 0x7d, 0x5d, 0x65, 0x68, 0x61,
+0x5d, 0x5c, 0x72, 0x43, 0xcd, 0xf6, 0xdf, 0xd2,
+0xd2, 0x51, 0xdf, 0x49, 0x62, 0x14, 0x68, 0x6e,
+0x10, 0x11, 0x69, 0x64, 0x61, 0x6d, 0x64, 0x75,
+0x44, 0x74, 0x5e, 0xcf, 0xff, 0xf1, 0xc1, 0xf7,
+0xf6, 0xe5, 0xe4, 0xe6, 0xe9, 0x91, 0x93, 0x90,
+0x95, 0xce, 0xe5, 0xe0, 0xc7, 0x66, 0x62, 0x45,
+0x75, 0x63, 0x6e, 0x79, 0x55, 0x49, 0x71, 0x53,
+0xca, 0xcb, 0xd0, 0xdb, 0xd3, 0xd5, 0x5b, 0x67,
+0x6b, 0x15, 0x61, 0x69, 0x17, 0x14, 0x6c, 0x66,
+0x6f, 0x62, 0x7f, 0x48, 0x74, 0x75, 0x59, 0xd0,
+0xdb, 0x54, 0xd7, 0xc3 };
+char packet_5[] = {
+0x80, 0x08, 0x2c, 0x44, 0x11, 0x47, 0x32, 0x42,
+0x58, 0xf3, 0x3d, 0xea, 0x54, 0xd5, 0xde, 0xc4,
+0xc0, 0xce, 0xd8, 0xd5, 0xdc, 0xde, 0xd4, 0xd9,
+0x54, 0x4d, 0x74, 0x47, 0x44, 0x58, 0xc7, 0xc3,
+0xc4, 0xd4, 0x55, 0x50, 0x43, 0x45, 0xd4, 0xc7,
+0xcf, 0xc0, 0x55, 0x42, 0x48, 0x76, 0x4f, 0xd7,
+0xc7, 0xcf, 0xc6, 0xc6, 0xf5, 0xc6, 0x53, 0x5a,
+0x42, 0x5e, 0x51, 0xd6, 0xc4, 0xde, 0x56, 0x42,
+0x42, 0x5e, 0xd7, 0xd4, 0xdb, 0xcb, 0xda, 0xd6,
+0xd7, 0x53, 0x47, 0x4d, 0xd4, 0xdf, 0xdc, 0xd5,
+0x5a, 0x59, 0x5a, 0x5a, 0xd5, 0xc4, 0xd7, 0x55,
+0xc3, 0xce, 0xde, 0xd2, 0xd6, 0x46, 0x71, 0x7c,
+0x4c, 0xd8, 0xf5, 0xf7, 0xcf, 0x54, 0x56, 0xd5,
+0xdc, 0xda, 0xd7, 0xd7, 0x57, 0x5a, 0x5c, 0x52,
+0x47, 0x5c, 0xd4, 0xd3, 0xd4, 0x47, 0x42, 0x4d,
+0x54, 0xcf, 0xf3, 0xf0, 0xc0, 0xdb, 0xd1, 0x50,
+0x47, 0x5e, 0x58, 0x49, 0x43, 0x5a, 0x54, 0xdc,
+0x56, 0x56, 0xd9, 0xc8, 0xc2, 0xd2, 0x5d, 0x5a,
+0x5a, 0x49, 0x40, 0x57, 0xda, 0xdb, 0xd6, 0x55,
+0xdd, 0xcf, 0xdb, 0x5c, 0x51, 0xd0, 0xd5, 0x5f,
+0x53, 0xd8, 0xc3, 0xc3, 0xd0, 0x5c, 0x5b, 0x44,
+0x4e, 0x74, 0x4f, 0x56 };
+char packet_6[] = {
+0x80, 0x08, 0x00, 0x05, 0x00, 0x00, 0x03, 0x20,
+0xd2, 0xbd, 0x4e, 0x3e, 0xca, 0xf0, 0xfd, 0xe2,
+0xea, 0x96, 0x91, 0x91, 0xe7, 0xd9, 0xf9, 0xf9,
+0x48, 0x6b, 0x61, 0x74, 0x66, 0x15, 0x69, 0x74,
+0x42, 0x7d, 0x75, 0xd2, 0xf7, 0xc8, 0xc3, 0xd1,
+0x5f, 0x5f, 0x7d, 0x6f, 0x15, 0x6d, 0x6e, 0x16,
+0x16, 0x68, 0x61, 0x62, 0x6c, 0x66, 0x79, 0x7d,
+0x7f, 0x77, 0x5c, 0xd9, 0xdb, 0x5e, 0x55, 0xcf,
+0xf1, 0xf0, 0xe5, 0xef, 0x95, 0x96, 0x93, 0x97,
+0xcd, 0xc3, 0xe4, 0xf7, 0x64, 0x15, 0x7a, 0x73,
+0x60, 0x68, 0x64, 0xd1, 0x53, 0x4e, 0x5d, 0xf7,
+0xf9, 0xf3, 0xf5, 0xd5, 0xd4, 0x58, 0x67, 0x6e,
+0x6c, 0x61, 0x68, 0x14, 0x68, 0x61, 0x64, 0x63,
+0x61, 0x79, 0x75, 0x4b, 0x4f, 0x44, 0xd7, 0xcb,
+0xc0, 0xd8, 0xf6, 0xe4, 0xe1, 0xe7, 0xed, 0x97,
+0x91, 0x93, 0x9d, 0x96, 0xff, 0xfd, 0xe5, 0xc7,
+0x66, 0x67, 0x4d, 0x4e, 0x64, 0x62, 0x71, 0x54,
+0xd5, 0x5f, 0xd0, 0xce, 0xce, 0xdf, 0x5d, 0x73,
+0x72, 0x73, 0x6c, 0x15, 0x6d, 0x6d, 0x15, 0x14,
+0x69, 0x63, 0x62, 0x62, 0x66, 0x78, 0x72, 0x76,
+0x43, 0x5b, 0xd5, 0xc0, 0xd9, 0xdd, 0xca, 0xf8,
+0xe4, 0xe7, 0xef, 0x96 };
+char packet_7[] = {
+0x80, 0x08, 0x2c, 0x45, 0x11, 0x47, 0x32, 0xe2,
+0x58, 0xf3, 0x3d, 0xea, 0xdd, 0xd9, 0xd2, 0xd6,
+0xd0, 0xd6, 0xdf, 0xd7, 0xd7, 0x54, 0xd5, 0x57,
+0x57, 0xd0, 0xd4, 0x55, 0xd5, 0xd8, 0xdb, 0xc0,
+0xc2, 0x53, 0x58, 0x5d, 0x57, 0x5e, 0x47, 0x41,
+0x4a, 0x5f, 0xde, 0xd9, 0x55, 0xd0, 0xc5, 0xdd,
+0xd3, 0xdd, 0xc6, 0xc1, 0xd1, 0x52, 0x5b, 0xd1,
+0xcc, 0xd9, 0x43, 0x7a, 0x78, 0x4e, 0x55, 0xd2,
+0xc5, 0xc3, 0xda, 0xc5, 0xd4, 0xd3, 0xc7, 0xd2,
+0xd9, 0xdb, 0x55, 0x45, 0x59, 0x51, 0x59, 0xd4,
+0xc2, 0xc6, 0xd0, 0xd1, 0x59, 0x48, 0x40, 0x47,
+0x5a, 0x55, 0xd2, 0xdc, 0xd9, 0xc9, 0xf6, 0xd9,
+0x42, 0x72, 0x40, 0xd1, 0x50, 0xd7, 0xc4, 0xc9,
+0xc5, 0xc1, 0xc3, 0x54, 0x5b, 0x48, 0x43, 0x57,
+0xd3, 0xd1, 0x5c, 0x47, 0x47, 0x49, 0x47, 0x59,
+0xd1, 0xf5, 0xd8, 0xd6, 0xdd, 0xd8, 0x5c, 0x53,
+0xc7, 0xc9, 0xc9, 0xc0, 0xd4, 0x4d, 0x4f, 0x47,
+0x50, 0xdf, 0xce, 0xd8, 0x5d, 0x43, 0x40, 0x5f,
+0xd1, 0x56, 0x58, 0xd0, 0xd0, 0xd0, 0xdb, 0x55,
+0x5b, 0x5b, 0xd4, 0xda, 0xc0, 0xc6, 0xd4, 0x58,
+0x5a, 0xd8, 0xc7, 0xdf, 0x54, 0x4a, 0x71, 0x43,
+0xd0, 0xc3, 0xc9, 0xde };
+char packet_8[] = {
+0x80, 0x08, 0x00, 0x06, 0x00, 0x00, 0x03, 0xc0,
+0xd2, 0xbd, 0x4e, 0x3e, 0x90, 0x93, 0x92, 0x92,
+0xe0, 0xf1, 0xff, 0xf6, 0x73, 0x60, 0x73, 0x75,
+0x7f, 0x66, 0x7e, 0x5b, 0xd7, 0x56, 0xd5, 0xd2,
+0xdf, 0xd2, 0xd0, 0x48, 0x78, 0x65, 0x66, 0x6f,
+0x6b, 0x6c, 0x6f, 0x68, 0x6b, 0x6e, 0x6c, 0x62,
+0x65, 0x78, 0x7d, 0x48, 0x4b, 0x4a, 0x42, 0xda,
+0xf4, 0xc0, 0xcf, 0xfd, 0xe6, 0xe0, 0xe3, 0xe9,
+0x91, 0x92, 0x9c, 0x9f, 0x90, 0xe2, 0xe7, 0xfa,
+0xc3, 0x46, 0x75, 0x5f, 0x47, 0x42, 0x48, 0x44,
+0xd3, 0xd0, 0xc5, 0xdf, 0xd2, 0xd8, 0xd8, 0x58,
+0x7c, 0x72, 0x73, 0x7e, 0x60, 0x61, 0x65, 0x67,
+0x60, 0x6d, 0x66, 0x7c, 0x71, 0x7d, 0x7d, 0x4a,
+0xd4, 0xd8, 0xd2, 0xc1, 0xf5, 0xce, 0xdb, 0xf0,
+0xe6, 0xe6, 0xe6, 0xed, 0xea, 0x97, 0x91, 0x92,
+0x9c, 0x97, 0xe4, 0xfb, 0xe4, 0xc1, 0x74, 0x40,
+0x54, 0x50, 0x4e, 0x75, 0x45, 0x54, 0x50, 0x44,
+0x5f, 0x5d, 0x5b, 0x46, 0x73, 0x64, 0x7a, 0x7e,
+0x67, 0x63, 0x66, 0x60, 0x6c, 0x69, 0x6c, 0x60,
+0x64, 0x7a, 0x7b, 0x7c, 0x48, 0x45, 0x5b, 0x59,
+0xd8, 0xca, 0xcc, 0xc3, 0xf0, 0xfa, 0xe5, 0xe1,
+0xed, 0xea, 0x96, 0x91 };
+char packet_9[] = {
+0x80, 0x08, 0x2c, 0x46, 0x11, 0x47, 0x33, 0x82,
+0x58, 0xf3, 0x3d, 0xea, 0x5b, 0x47, 0x55, 0xdf,
+0xd1, 0xd5, 0x54, 0xd3, 0xc4, 0x55, 0x5e, 0x56,
+0xd1, 0xd2, 0xde, 0xdd, 0x54, 0x5c, 0x45, 0x5d,
+0x55, 0x5d, 0x59, 0xd6, 0x55, 0x5a, 0xd3, 0xd9,
+0xd0, 0xdc, 0xd8, 0xd8, 0xc6, 0xca, 0xc6, 0xd1,
+0x5a, 0x7f, 0x7e, 0x4f, 0xdd, 0xd9, 0x57, 0x45,
+0x59, 0xd7, 0xdd, 0xc3, 0xc6, 0x54, 0x5c, 0xd4,
+0xdd, 0xdd, 0x5d, 0x43, 0x55, 0xdf, 0xda, 0xcc,
+0xc9, 0x54, 0x4f, 0x5c, 0x55, 0xd2, 0xd0, 0xd1,
+0x52, 0x5f, 0xdd, 0x53, 0x58, 0x53, 0xd6, 0xdd,
+0xd9, 0xdc, 0xc1, 0xd7, 0x4a, 0x4e, 0x47, 0x51,
+0xdf, 0xf5, 0xc6, 0x57, 0x5b, 0x75, 0x74, 0x55,
+0xf6, 0xdb, 0x5e, 0x50, 0xd4, 0xd3, 0x56, 0x58,
+0x5f, 0xd7, 0xdd, 0xde, 0xd2, 0xd5, 0x4d, 0x71,
+0x5f, 0xf4, 0xf2, 0xc0, 0x50, 0x41, 0x5c, 0xd0,
+0xd7, 0xdc, 0xd1, 0x45, 0x4e, 0x5c, 0x54, 0x5e,
+0x77, 0x72, 0x5a, 0xcf, 0xf2, 0xf4, 0xda, 0xd2,
+0xd6, 0x58, 0x5e, 0xdf, 0xc1, 0xc2, 0x57, 0x40,
+0x56, 0xd7, 0xd7, 0xd5, 0x56, 0x45, 0x43, 0x50,
+0xd9, 0xd2, 0x52, 0x5e, 0x5d, 0xd2, 0xd8, 0xd2,
+0x54, 0x58, 0x41, 0x43 };
+char packet_10[] = {
+0x80, 0x08, 0x2c, 0x47, 0x11, 0x47, 0x34, 0x22,
+0x58, 0xf3, 0x3d, 0xea, 0x56, 0xd4, 0xd6, 0x58,
+0x42, 0x53, 0xc4, 0xf7, 0xcb, 0xf5, 0xf4, 0xc1,
+0xd0, 0x4d, 0x45, 0xd6, 0x57, 0xd0, 0xd9, 0xdb,
+0x50, 0x44, 0x59, 0x4b, 0x4f, 0xd6, 0xd8, 0x57,
+0x5e, 0xd6, 0x57, 0xd0, 0xc5, 0xdf, 0xc6, 0xcd,
+0xc5, 0x51, 0x50, 0xd0, 0xd6, 0xd2, 0xdb, 0x5d,
+0x75, 0x75, 0x73, 0x75, 0xc0, 0xf7, 0xf0, 0xf6,
+0xc9, 0xd8, 0xd5, 0x57, 0x56, 0x48, 0x70, 0x75,
+0x42, 0x42, 0x5f, 0xd0, 0x5d, 0x5b, 0x5c, 0x55,
+0xd6, 0xc1, 0xcf, 0xd8, 0xd3, 0xd0, 0x45, 0x4f,
+0x54, 0xc6, 0xd0, 0x59, 0x55, 0xc4, 0xd1, 0x5a,
+0x73, 0x7f, 0x47, 0x54, 0xd1, 0xdf, 0xdc, 0xd7,
+0xc7, 0xc8, 0xdb, 0xc7, 0xca, 0xc9, 0xc0, 0xc7,
+0xc1, 0x51, 0x40, 0x5f, 0x52, 0xd7, 0xda, 0xdf,
+0x41, 0x4c, 0x56, 0x54, 0x5f, 0x4a, 0x4a, 0x4e,
+0x5d, 0xc4, 0xc6, 0xcd, 0xc7, 0xd6, 0x52, 0xd4,
+0xc4, 0xc4, 0xc6, 0xd5, 0x5b, 0x41, 0x4e, 0x56,
+0xc4, 0xd8, 0x54, 0x5e, 0x4d, 0x48, 0x76, 0x73,
+0x4d, 0x5b, 0x59, 0xd8, 0xf0, 0xf7, 0xde, 0x52,
+0xd0, 0xc3, 0xfd, 0xfa, 0xfd, 0xc1, 0x40, 0x4a,
+0x5a, 0x45, 0x5d, 0xd0 };
+
+#define MAKE_TEST(n) \
+ /* deserialize the packet*/ \
+ if((packet = trtp_rtp_packet_deserialize(packet_##n, sizeof(packet_##n)))){ \
+ /* serialize the packet */ \
+ if((buffer = trtp_rtp_packet_serialize(packet))){ \
+ /* compare data */ \
+ if(sizeof(packet_##n) != buffer->size){ \
+ TSK_DEBUG_ERROR("Test-%d: Sizes are different", n); \
+ } \
+ else{ \
+ for(i=0; i<buffer->size; i++){ \
+ if(packet_##n[i] != ((char*)buffer->data)[i]){ \
+ TSK_DEBUG_ERROR("Test-%d: Data is different", n); \
+ break; \
+ } \
+ } \
+ if(i==buffer->size){ \
+ TSK_DEBUG_INFO("Test-%d: OK", n); \
+ } \
+ } \
+ } \
+ else{ \
+ TSK_DEBUG_ERROR("Failed to serialize packet-%d", n); \
+ } \
+ \
+ TSK_OBJECT_SAFE_FREE(buffer); \
+ TSK_OBJECT_SAFE_FREE(packet); \
+ } \
+ else{ \
+ TSK_DEBUG_ERROR("Failed to deserialize packet-%d", n); \
+ }
+
+void test_parser()
+{
+ trtp_rtp_packet_t* packet;
+ tsk_buffer_t* buffer;
+ tsk_size_t i;
+
+ MAKE_TEST(0);
+ MAKE_TEST(1);
+ MAKE_TEST(2);
+ MAKE_TEST(3);
+ MAKE_TEST(4);
+ MAKE_TEST(5);
+ MAKE_TEST(6);
+ MAKE_TEST(7);
+ MAKE_TEST(8);
+ MAKE_TEST(9);
+ MAKE_TEST(10);
+}
+
+
+#endif /* _TEST_PARSER_H_ */
diff --git a/tinyRTP/tinyRTP.pc.in b/tinyRTP/tinyRTP.pc.in
new file mode 100644
index 0000000..621003d
--- /dev/null
+++ b/tinyRTP/tinyRTP.pc.in
@@ -0,0 +1,14 @@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+libdir = @libdir@
+includedir = @includedir@
+
+Name : libtinyRTP
+Description : Doubango Telecom tinyRTP ((S)RTP/(S)RTCP protocols) library
+Version : @PACKAGE_VERSION@
+Requires:
+Requires.private: tinySAK = @PACKAGE_VERSION@ tinyNET = @PACKAGE_VERSION@ tinyMEDIA = @PACKAGE_VERSION@
+Conflicts:
+Cflags : -I${includedir}/tinyrtp
+Libs : -L${libdir} -ltinyRTP
+Libs.private:
diff --git a/tinyRTP/tinyRTP.sln b/tinyRTP/tinyRTP.sln
new file mode 100644
index 0000000..ec6e279
--- /dev/null
+++ b/tinyRTP/tinyRTP.sln
@@ -0,0 +1,92 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinyRTP", "tinyRTP.vcproj", "{99B7D02F-8C70-4B45-AF3C-92313C3CEE15}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinySAK", "..\tinySAK\tinySAK.vcproj", "{6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinyNET", "..\tinyNET\tinyNET.vcproj", "{7522A458-92F4-4259-B906-E84C2A65D9F1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcproj", "{A6C1CDCE-63E1-4B60-AC4C-EF0410ED4432}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ Release|Win32 = Release|Win32
+ Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ Static_Debug|Win32 = Static_Debug|Win32
+ Static_Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Static_Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ Static_Release|Win32 = Static_Release|Win32
+ Static_Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I) = Static_Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {99B7D02F-8C70-4B45-AF3C-92313C3CEE15}.Debug|Win32.ActiveCfg = Debug|Win32
+ {99B7D02F-8C70-4B45-AF3C-92313C3CEE15}.Debug|Win32.Build.0 = Debug|Win32
+ {99B7D02F-8C70-4B45-AF3C-92313C3CEE15}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32
+ {99B7D02F-8C70-4B45-AF3C-92313C3CEE15}.Release|Win32.ActiveCfg = Release|Win32
+ {99B7D02F-8C70-4B45-AF3C-92313C3CEE15}.Release|Win32.Build.0 = Release|Win32
+ {99B7D02F-8C70-4B45-AF3C-92313C3CEE15}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32
+ {99B7D02F-8C70-4B45-AF3C-92313C3CEE15}.Static_Debug|Win32.ActiveCfg = Debug|Win32
+ {99B7D02F-8C70-4B45-AF3C-92313C3CEE15}.Static_Debug|Win32.Build.0 = Debug|Win32
+ {99B7D02F-8C70-4B45-AF3C-92313C3CEE15}.Static_Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32
+ {99B7D02F-8C70-4B45-AF3C-92313C3CEE15}.Static_Release|Win32.ActiveCfg = Release|Win32
+ {99B7D02F-8C70-4B45-AF3C-92313C3CEE15}.Static_Release|Win32.Build.0 = Release|Win32
+ {99B7D02F-8C70-4B45-AF3C-92313C3CEE15}.Static_Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Debug|Win32.Build.0 = Debug|Win32
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Release|Win32.ActiveCfg = Release|Win32
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Release|Win32.Build.0 = Release|Win32
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Static_Debug|Win32.ActiveCfg = Static_Debug|Win32
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Static_Debug|Win32.Build.0 = Static_Debug|Win32
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Static_Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Static_Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Static_Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Static_Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Static_Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Static_Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Static_Release|Win32.ActiveCfg = Static_Release|Win32
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Static_Release|Win32.Build.0 = Static_Release|Win32
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Static_Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Static_Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Static_Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Static_Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}.Static_Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Static_Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Debug|Win32.Build.0 = Debug|Win32
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Release|Win32.ActiveCfg = Release|Win32
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Release|Win32.Build.0 = Release|Win32
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Static_Debug|Win32.ActiveCfg = Debug|Win32
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Static_Debug|Win32.Build.0 = Debug|Win32
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Static_Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Static_Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Static_Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Static_Release|Win32.ActiveCfg = Release|Win32
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Static_Release|Win32.Build.0 = Release|Win32
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Static_Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Static_Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Build.0 = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {7522A458-92F4-4259-B906-E84C2A65D9F1}.Static_Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).Deploy.0 = Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)
+ {A6C1CDCE-63E1-4B60-AC4C-EF0410ED4432}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A6C1CDCE-63E1-4B60-AC4C-EF0410ED4432}.Debug|Win32.Build.0 = Debug|Win32
+ {A6C1CDCE-63E1-4B60-AC4C-EF0410ED4432}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32
+ {A6C1CDCE-63E1-4B60-AC4C-EF0410ED4432}.Release|Win32.ActiveCfg = Release|Win32
+ {A6C1CDCE-63E1-4B60-AC4C-EF0410ED4432}.Release|Win32.Build.0 = Release|Win32
+ {A6C1CDCE-63E1-4B60-AC4C-EF0410ED4432}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32
+ {A6C1CDCE-63E1-4B60-AC4C-EF0410ED4432}.Static_Debug|Win32.ActiveCfg = Debug|Win32
+ {A6C1CDCE-63E1-4B60-AC4C-EF0410ED4432}.Static_Debug|Win32.Build.0 = Debug|Win32
+ {A6C1CDCE-63E1-4B60-AC4C-EF0410ED4432}.Static_Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32
+ {A6C1CDCE-63E1-4B60-AC4C-EF0410ED4432}.Static_Release|Win32.ActiveCfg = Release|Win32
+ {A6C1CDCE-63E1-4B60-AC4C-EF0410ED4432}.Static_Release|Win32.Build.0 = Release|Win32
+ {A6C1CDCE-63E1-4B60-AC4C-EF0410ED4432}.Static_Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/tinyRTP/tinyRTP.vcproj b/tinyRTP/tinyRTP.vcproj
new file mode 100644
index 0000000..794128b
--- /dev/null
+++ b/tinyRTP/tinyRTP.vcproj
@@ -0,0 +1,384 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="tinyRTP"
+ ProjectGUID="{99B7D02F-8C70-4B45-AF3C-92313C3CEE15}"
+ RootNamespace="tinyRTP"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="include;..\tinySAK\src;..\tinyNET\src;..\tinyMEDIA\include;..\thirdparties\win32\include"
+ PreprocessorDefinitions="DEBUG_LEVEL=DEBUG_LEVEL_INFO;HAVE_SRTP=1;WIN32;_DEBUG;_WINDOWS;_USRDLL;TINYRTP_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ WarnAsError="true"
+ DebugInformationFormat="4"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib $(OutDir)\tinySAK.lib $(OutDir)\tinyNET.lib $(OutDir)\tinyMEDIA.lib &quot;..\thirdparties\win32\lib\srtp\libsrtp.a&quot; ..\thirdparties\win32\lib\libgcc.a"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="..\thirdparties\win32\include;include;..\tinySAK\src;..\tinyNET\src;..\tinyMEDIA\include"
+ PreprocessorDefinitions="HAVE_SRTP=1;WIN32;NDEBUG;_WINDOWS;_USRDLL;TINYRTP_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ WarnAsError="true"
+ DebugInformationFormat="0"
+ CompileAs="1"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib $(OutDir)\tinySAK.lib $(OutDir)\tinyNET.lib $(OutDir)\tinyMEDIA.lib &quot;..\thirdparties\win32\lib\srtp\libsrtp.a&quot; &quot;..\thirdparties\win32\lib\libgcc.a&quot;"
+ LinkIncremental="1"
+ IgnoreDefaultLibraryNames="MSVCRTD"
+ GenerateDebugInformation="false"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="source(*.c)"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\src\trtp.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\trtp_manager.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\trtp_srtp.c"
+ >
+ </File>
+ <Filter
+ Name="rtp"
+ >
+ <File
+ RelativePath=".\src\rtp\trtp_rtp_header.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\rtp\trtp_rtp_packet.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\rtp\trtp_rtp_session.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="rtcp"
+ >
+ <File
+ RelativePath=".\src\rtcp\trtp_rtcp_header.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\rtcp\trtp_rtcp_packet.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\rtcp\trtp_rtcp_rblock.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\rtcp\trtp_rtcp_report.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\rtcp\trtp_rtcp_report_bye.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\rtcp\trtp_rtcp_report_fb.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\rtcp\trtp_rtcp_report_rr.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\rtcp\trtp_rtcp_report_sdes.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\rtcp\trtp_rtcp_report_sr.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\rtcp\trtp_rtcp_report_xr.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\rtcp\trtp_rtcp_sdes_chunck.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\rtcp\trtp_rtcp_sdes_item.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\rtcp\trtp_rtcp_session.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="rtsp"
+ >
+ </Filter>
+ </Filter>
+ <Filter
+ Name="include(*.h)"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\include\tinyrtp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp_config.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\trtp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\trtp_manager.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\trtp_srtp.h"
+ >
+ </File>
+ <Filter
+ Name="rtp"
+ >
+ <File
+ RelativePath=".\include\tinyrtp\rtp\trtp_rtp_header.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\rtp\trtp_rtp_packet.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\rtp\trtp_rtp_session.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="rtcp"
+ >
+ <File
+ RelativePath=".\include\tinyrtp\rtcp\trtp_rtcp_header.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\rtcp\trtp_rtcp_packet.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\rtcp\trtp_rtcp_rblock.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\rtcp\trtp_rtcp_report.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\rtcp\trtp_rtcp_report_bye.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\rtcp\trtp_rtcp_report_fb.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\rtcp\trtp_rtcp_report_rr.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\rtcp\trtp_rtcp_report_sdes.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\rtcp\trtp_rtcp_report_sr.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\rtcp\trtp_rtcp_report_xr.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\rtcp\trtp_rtcp_sdes_chunck.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\rtcp\trtp_rtcp_sdes_item.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinyrtp\rtcp\trtp_rtcp_session.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="rtsp"
+ >
+ </Filter>
+ </Filter>
+ <Filter
+ Name="resources(*.rc)"
+ >
+ <File
+ RelativePath=".\version.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/tinyRTP/version.rc b/tinyRTP/version.rc
new file mode 100644
index 0000000..9592d2e
--- /dev/null
+++ b/tinyRTP/version.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+// #include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 2.0.0.1156
+ PRODUCTVERSION 2.0.0.1156
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Doubango telecom"
+ VALUE "FileDescription", "Doubango IMS Framework"
+ VALUE "FileVersion", "2.0.0.1156"
+ VALUE "InternalName", "tinyrtp.dll"
+ VALUE "LegalCopyright", "(c) 2010-2013 Doubango Telecom. All rights reserved."
+ VALUE "OriginalFilename", "tinyrtp.dll"
+ VALUE "ProductName", "Doubango IMS Framework"
+ VALUE "ProductVersion", "2.0.0.1156"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
OpenPOWER on IntegriCloud