summaryrefslogtreecommitdiffstats
path: root/tinyMEDIA
diff options
context:
space:
mode:
authorMamadou DIOP <bossiel@yahoo.fr>2015-08-17 01:56:35 +0200
committerMamadou DIOP <bossiel@yahoo.fr>2015-08-17 01:56:35 +0200
commit631fffee8a28b1bec5ed1f1d26a20e0135967f99 (patch)
tree74afe3bf3efe15aa82bcd0272b2b0f4d48c2d837 /tinyMEDIA
parent7908865936604036e6f200f1b5e069f8752f3a3a (diff)
downloaddoubango-631fffee8a28b1bec5ed1f1d26a20e0135967f99.zip
doubango-631fffee8a28b1bec5ed1f1d26a20e0135967f99.tar.gz
-
Diffstat (limited to 'tinyMEDIA')
-rw-r--r--tinyMEDIA/Makefile.am44
-rw-r--r--tinyMEDIA/droid-makefile49
-rw-r--r--tinyMEDIA/include/tinymedia.h60
-rw-r--r--tinyMEDIA/include/tinymedia/content/tmedia_content.h126
-rw-r--r--tinyMEDIA/include/tinymedia/content/tmedia_content_cpim.h59
-rw-r--r--tinyMEDIA/include/tinymedia/content/tmedia_content_multipart.h0
-rw-r--r--tinyMEDIA/include/tinymedia/content/tmedia_content_sip_frag.h0
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia.h121
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_codec.h468
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_codec_dummy.h78
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_common.h285
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_consumer.h147
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_converter_video.h114
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_defaults.h146
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_denoise.h97
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_imageattr.h108
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_jitterbuffer.h102
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_params.h119
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_producer.h144
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_qos.h194
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_resampler.h86
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_session.h578
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_session_dummy.h76
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_session_ghost.h55
-rw-r--r--tinyMEDIA/include/tinymedia/tmedia_vad.h0
-rw-r--r--tinyMEDIA/include/tinymedia_config.h98
-rw-r--r--tinyMEDIA/ragel.sh11
-rw-r--r--tinyMEDIA/ragel/tmedia_content_cpim.rl244
-rw-r--r--tinyMEDIA/ragel/tmedia_imageattr.rl183
-rw-r--r--tinyMEDIA/ragel/tmedia_machine_utils.rl78
-rw-r--r--tinyMEDIA/src/content/tmedia_content.c357
-rw-r--r--tinyMEDIA/src/content/tmedia_content_cpim.c449
-rw-r--r--tinyMEDIA/src/content/tmedia_content_multipart.c0
-rw-r--r--tinyMEDIA/src/content/tmedia_content_sip_frag.c0
-rw-r--r--tinyMEDIA/src/tmedia.c289
-rw-r--r--tinyMEDIA/src/tmedia_codec.c833
-rw-r--r--tinyMEDIA/src/tmedia_codec_dummy.c369
-rw-r--r--tinyMEDIA/src/tmedia_common.c442
-rw-r--r--tinyMEDIA/src/tmedia_consumer.c288
-rw-r--r--tinyMEDIA/src/tmedia_converter_video.c126
-rw-r--r--tinyMEDIA/src/tmedia_defaults.c618
-rw-r--r--tinyMEDIA/src/tmedia_denoise.c242
-rw-r--r--tinyMEDIA/src/tmedia_imageattr.c954
-rw-r--r--tinyMEDIA/src/tmedia_jitterbuffer.c281
-rw-r--r--tinyMEDIA/src/tmedia_params.c197
-rw-r--r--tinyMEDIA/src/tmedia_producer.c304
-rw-r--r--tinyMEDIA/src/tmedia_qos.c862
-rw-r--r--tinyMEDIA/src/tmedia_resampler.c152
-rw-r--r--tinyMEDIA/src/tmedia_session.c2524
-rw-r--r--tinyMEDIA/src/tmedia_session_dummy.c490
-rw-r--r--tinyMEDIA/src/tmedia_session_ghost.c154
-rw-r--r--tinyMEDIA/src/tmedia_vad.c0
-rw-r--r--tinyMEDIA/test/droid-makefile29
-rw-r--r--tinyMEDIA/test/dummy.c173
-rw-r--r--tinyMEDIA/test/dummy.h43
-rw-r--r--tinyMEDIA/test/test.c170
-rw-r--r--tinyMEDIA/test/test.vcproj217
-rw-r--r--tinyMEDIA/test/test_codecs.h37
-rw-r--r--tinyMEDIA/test/test_contents.h89
-rw-r--r--tinyMEDIA/test/test_image_attr.h54
-rw-r--r--tinyMEDIA/test/test_qos.h267
-rw-r--r--tinyMEDIA/test/test_sessions.h246
-rw-r--r--tinyMEDIA/tinyMEDIA.pc.in15
-rw-r--r--tinyMEDIA/tinyMEDIA.sln64
-rw-r--r--tinyMEDIA/tinyMEDIA.vcproj408
-rw-r--r--tinyMEDIA/version.rc102
-rw-r--r--tinyMEDIA/winrt/tinyMEDIA.sln67
-rw-r--r--tinyMEDIA/winrt/tinyMEDIA.vcxproj208
-rw-r--r--tinyMEDIA/winrt/tinyMEDIA.vcxproj.filters166
69 files changed, 16156 insertions, 0 deletions
diff --git a/tinyMEDIA/Makefile.am b/tinyMEDIA/Makefile.am
new file mode 100644
index 0000000..2e541a6
--- /dev/null
+++ b/tinyMEDIA/Makefile.am
@@ -0,0 +1,44 @@
+lib_LTLIBRARIES = libtinyMEDIA.la
+libtinyMEDIA_la_LIBADD = ../tinySAK/libtinySAK.la ../tinyNET/libtinyNET.la ../tinySDP/libtinySDP.la
+libtinyMEDIA_la_CPPFLAGS = -Iinclude -I../tinySAK/src -I../tinyNET/src -I../tinySDP/include
+
+libtinyMEDIA_la_SOURCES = \
+ src/tmedia.c \
+ src/tmedia_codec.c \
+ src/tmedia_codec_dummy.c \
+ src/tmedia_common.c \
+ src/tmedia_consumer.c \
+ src/tmedia_converter_video.c \
+ src/tmedia_defaults.c \
+ src/tmedia_denoise.c \
+ src/tmedia_imageattr.c \
+ src/tmedia_jitterbuffer.c \
+ src/tmedia_params.c \
+ src/tmedia_producer.c \
+ src/tmedia_qos.c \
+ src/tmedia_resampler.c \
+ src/tmedia_session.c \
+ src/tmedia_session_dummy.c \
+ src/tmedia_session_ghost.c
+
+libtinyMEDIA_la_SOURCES += \
+ src/content/tmedia_content.c \
+ src/content/tmedia_content_cpim.c \
+ src/content/tmedia_content_multipart.c \
+ src/content/tmedia_content_sip_frag.c
+
+libtinyMEDIA_la_LDFLAGS = $LDFLAGS -no-undefined
+if TARGET_OS_IS_ANDROID
+libtinyMEDIA_la_LDFLAGS += -static
+endif
+
+_includedir = $(includedir)/tinymedia
+_include_HEADERS = include/*.h
+__includedir = $(includedir)/tinymedia/tinymedia
+__include_HEADERS = include/tinymedia/*.h
+content_includedir = $(includedir)/tinymedia/tinymedia/content
+content_include_HEADERS = include/tinymedia/content/*.h
+
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = tinyMEDIA.pc \ No newline at end of file
diff --git a/tinyMEDIA/droid-makefile b/tinyMEDIA/droid-makefile
new file mode 100644
index 0000000..f56d3dd
--- /dev/null
+++ b/tinyMEDIA/droid-makefile
@@ -0,0 +1,49 @@
+APP := lib$(PROJECT)_$(MARCH).$(EXT)
+
+CFLAGS := $(CFLAGS_LIB) -I../tinySAK/src -I../tinyNET/src -I../tinySDP/include -I./include
+LDFLAGS := $(LDFLAGS_LIB) -ltinySAK_$(MARCH) -ltinyNET_$(MARCH) -ltinySDP_$(MARCH) -lm
+
+all: $(APP)
+
+OBJS = \
+ src/tmedia.o \
+ src/tmedia_codec.o \
+ src/tmedia_codec_dummy.o \
+ src/tmedia_common.o \
+ src/tmedia_consumer.o \
+ src/tmedia_converter_video.o \
+ src/tmedia_defaults.o \
+ src/tmedia_denoise.o \
+ src/tmedia_imageattr.o \
+ src/tmedia_jitterbuffer.o \
+ src/tmedia_params.o \
+ src/tmedia_producer.o \
+ src/tmedia_qos.o \
+ src/tmedia_resampler.o \
+ src/tmedia_session.o \
+ src/tmedia_session_dummy.o \
+ src/tmedia_session_ghost.o \
+ \
+ src/content/tmedia_content.o \
+ src/content/tmedia_content_cpim.o \
+ src/content/tmedia_content_multipart.o \
+ src/content/tmedia_content_sip_frag.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/tinyMEDIA/include/tinymedia.h b/tinyMEDIA/include/tinymedia.h
new file mode 100644
index 0000000..bdee2d8
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia.h
@@ -0,0 +1,60 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tinymedia.h
+ * @brief tinyMEDIA API.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TINYMEDIA_TINYMEDIA_H
+#define TINYMEDIA_TINYMEDIA_H
+
+/* == tinyMEDIA == */
+#include "tinymedia/tmedia_codec_dummy.h"
+#include "tinymedia/tmedia_session_dummy.h"
+#include "tinymedia/tmedia_session_ghost.h"
+#include "tinymedia/tmedia_jitterbuffer.h"
+#include "tinymedia/tmedia_resampler.h"
+#include "tinymedia/tmedia_denoise.h"
+#include "tinymedia/tmedia_imageattr.h"
+
+#include "tinymedia/tmedia_consumer.h"
+#include "tinymedia/tmedia_producer.h"
+
+#include "tinymedia/tmedia_common.h"
+#include "tinymedia/tmedia_qos.h"
+#include "tinymedia/tmedia_defaults.h"
+
+#include "tinymedia/content/tmedia_content.h"
+#include "tinymedia/content/tmedia_content_cpim.h"
+#include "tinymedia/content/tmedia_content_multipart.h"
+#include "tinymedia/content/tmedia_content_sip_frag.h"
+
+/* == tinyNET == */
+#include "tinynet.h"
+
+/* == tinySDP == */
+#include "tinysdp.h"
+
+#endif /* TINYMEDIA_TINYMEDIA_H */
diff --git a/tinyMEDIA/include/tinymedia/content/tmedia_content.h b/tinyMEDIA/include/tinymedia/content/tmedia_content.h
new file mode 100644
index 0000000..41b1ecb
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/content/tmedia_content.h
@@ -0,0 +1,126 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_content.h
+ * @brief Base content object.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+ */
+#ifndef TINYMEDIA_CONTENT_H
+#define TINYMEDIA_CONTENT_H
+
+#include "tinymedia_config.h"
+
+#include "tsk_buffer.h"
+#include "tsk_list.h"
+#include "tsk_params.h"
+
+TMEDIA_BEGIN_DECLS
+
+/**Max number of plugins (content types) we can create */
+#define TMEDIA_CONTENT_MAX_PLUGINS 0x0F
+
+/** cast any pointer to @ref tmedia_content_t* object */
+#define TMEDIA_CONTENT(self) ((tmedia_content_t*)(self))
+
+/** Base object for all contents */
+typedef struct tmedia_content_s
+{
+ TSK_DECLARE_OBJECT;
+
+ const char* type;
+ //! plugin used to create the codec
+ const struct tmedia_content_plugin_def_s* plugin;
+}
+tmedia_content_t;
+
+/** Virtual table used to define a content plugin */
+typedef struct tmedia_content_plugin_def_s
+{
+ //! object definition used to create an instance of the codec
+ const tsk_object_def_t* objdef;
+
+ //! e.g. 'message/CPIM'
+ const char* type;
+
+ int (*parse) (tmedia_content_t*, const void* in_data, tsk_size_t in_size);
+ tsk_buffer_t* (*get_data) (tmedia_content_t*);
+}
+tmedia_content_plugin_def_t;
+
+/** List of @ref tmedia_codec_t elements */
+typedef tsk_list_t tmedia_contents_L_t;
+
+/**< Declare base class as content */
+#define TMEDIA_DECLARE_CONTENT tmedia_content_t __content__
+
+TINYMEDIA_API int tmedia_content_plugin_register(const char* type, const tmedia_content_plugin_def_t* plugin);
+TINYMEDIA_API int tmedia_content_plugin_unregister(const char* type, const tmedia_content_plugin_def_t* plugin);
+TINYMEDIA_API int tmedia_content_plugin_unregister_all();
+
+TINYMEDIA_API tmedia_content_t* tmedia_content_create(const char* type);
+TINYMEDIA_API tmedia_content_t* tmedia_content_parse(const void* data, tsk_size_t size, const char* type);
+
+TINYMEDIA_API int tmedia_content_init(tmedia_content_t* self);
+TINYMEDIA_API int tmedia_content_deinit(tmedia_content_t* self);
+TINYMEDIA_API tsk_buffer_t* tmedia_content_get_data(tmedia_content_t* self);
+
+/** dummy content */
+typedef struct tmedia_content_dummy_s
+{
+ TMEDIA_DECLARE_CONTENT;
+
+ tsk_buffer_t* data;
+}
+tmedia_content_dummy_t;
+
+#define TMEDIA_CONTENT_DUMMY(self) ((tmedia_content_dummy_t*)(self))
+#define TMEDIA_CONTENT_IS_DUMMY(self) ( (self) && (TMEDIA_CONTENT((self))->plugin==tmedia_content_dummy_plugin_def_t) )
+
+TINYMEDIA_GEXTERN const tmedia_content_plugin_def_t *tmedia_content_dummy_plugin_def_t;
+
+
+/** content header */
+typedef struct tmedia_content_header_s
+{
+ TSK_DECLARE_OBJECT;
+
+ char* name;
+ char* value;
+ tsk_params_L_t* params;
+}
+tmedia_content_header_t;
+
+tmedia_content_header_t* tmedia_content_header_create(const char* name, const char* value);
+int tmedia_content_header_deinit(tmedia_content_header_t* self);
+char* tmedia_content_header_tostring(const tmedia_content_header_t* self);
+
+#define TMEDIA_CONTENT_HEADER(self) ((tmedia_content_header_t*)(self))
+#define TMEDIA_DECLARE_CONTENT_HEADER tmedia_content_header_t __content_header__
+typedef tsk_list_t tmedia_content_headers_L_t;
+
+TINYMEDIA_GEXTERN const tsk_object_def_t *tmedia_content_header_def_t;
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_CONTENT_H */
diff --git a/tinyMEDIA/include/tinymedia/content/tmedia_content_cpim.h b/tinyMEDIA/include/tinymedia/content/tmedia_content_cpim.h
new file mode 100644
index 0000000..db1aa02
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/content/tmedia_content_cpim.h
@@ -0,0 +1,59 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_content_cpim.h
+ * @brief Common Presence and Instant Messaging (CPIM): Message Format (RFC 3862)
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+ */
+#ifndef TINYMEDIA_CONTENT_CPIM_H
+#define TINYMEDIA_CONTENT_CPIM_H
+
+#include "tinymedia_config.h"
+
+#include "tmedia_content.h"
+
+TMEDIA_BEGIN_DECLS
+
+#define TMEDIA_CONTENT_CPIM_TYPE "message/CPIM"
+
+/** message/CPIM content */
+typedef struct tmedia_content_cpim_s
+{
+ TMEDIA_DECLARE_CONTENT;
+
+ tmedia_content_headers_L_t* m_headers; /**< MIME headers for the overall message */
+ tmedia_content_headers_L_t* h_headers; /**< message headers */
+ tsk_buffer_t* e; /**< encapsulated MIME object containing the message content */
+ tsk_buffer_t* x; /**< MIME security multipart message wrapper */
+}
+tmedia_content_cpim_t;
+
+#define TMEDIA_CONTENT_CPIM(self) ((tmedia_content_cpim_t*)(self))
+#define TMEDIA_CONTENT_IS_CPIM(self) ( (self) && (TMEDIA_CONTENT((self))->plugin==tmedia_content_cpim_plugin_def_t) )
+
+TINYMEDIA_GEXTERN const tmedia_content_plugin_def_t *tmedia_content_cpim_plugin_def_t;
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_CONTENT_CPIM_H */
diff --git a/tinyMEDIA/include/tinymedia/content/tmedia_content_multipart.h b/tinyMEDIA/include/tinymedia/content/tmedia_content_multipart.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/content/tmedia_content_multipart.h
diff --git a/tinyMEDIA/include/tinymedia/content/tmedia_content_sip_frag.h b/tinyMEDIA/include/tinymedia/content/tmedia_content_sip_frag.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/content/tmedia_content_sip_frag.h
diff --git a/tinyMEDIA/include/tinymedia/tmedia.h b/tinyMEDIA/include/tinymedia/tmedia.h
new file mode 100644
index 0000000..d10ee69
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia.h
@@ -0,0 +1,121 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia.h
+ * @brief Base media object.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TINYMEDIA_TMEDIA_H
+#define TINYMEDIA_TMEDIA_H
+
+#include "tinymedia_config.h"
+
+#include "tinysdp/tsdp_message.h"
+
+#include "tnet_socket.h"
+
+#include "tsk_params.h"
+
+TMEDIA_BEGIN_DECLS
+
+
+#if 0
+
+#define TMEDIA_VA_ARGS(name, host, socket_type) tmedia_def_t, (const char*) name, (const char*) host, (tnet_socket_type_t) socket_type
+
+#define TMEDIA(self) ((tmedia_t*)(self))
+
+typedef enum tmedia_action_e
+{
+ // Dummy
+ tma_dummy_say_hello,
+
+ // MSRP
+ tma_msrp_send_data,
+ tma_msrp_send_file,
+
+ // Audio / Video
+
+ // T.38
+}
+tmedia_action_t;
+
+typedef struct tmedia_s
+{
+ TSK_DECLARE_OBJECT;
+
+ const struct tmedia_plugin_def_s* plugin;
+
+ char* name;
+ uint32_t port;
+ char* protocol;
+}
+tmedia_t;
+typedef tsk_list_t tmedias_L_t;
+
+#define TMED_DECLARE_MEDIA tmedia_t media
+
+typedef struct tmedia_plugin_def_s
+{
+ const tsk_object_def_t* objdef;
+ const char* name;
+ const char* media;
+
+ int (* start) (tmedia_t* );
+ int (* pause) (tmedia_t* );
+ int (* stop) (tmedia_t* );
+
+ const tsdp_header_M_t* (* get_local_offer) (tmedia_t* , va_list* );
+ const tsdp_header_M_t* (* get_negotiated_offer) (tmedia_t* );
+ int (* set_remote_offer) (tmedia_t* , const tsdp_message_t* );
+
+ int (* perform) (tmedia_t* , tmedia_action_t action, const tsk_params_L_t* );
+}
+tmedia_plugin_def_t;
+
+TINYMEDIA_API int tmedia_init(tmedia_t* self, const char* name);
+TINYMEDIA_API int tmedia_deinit(tmedia_t* self);
+
+TINYMEDIA_API int tmedia_plugin_register(const tmedia_plugin_def_t* def);
+TINYMEDIA_API tmedia_t* tmedia_factory_create(const char* name, const char* host, tnet_socket_type_t socket_type);
+
+TINYMEDIA_API int tmedia_start(tmedia_t* );
+TINYMEDIA_API int tmedia_pause(tmedia_t* );
+TINYMEDIA_API int tmedia_stop(tmedia_t* );
+
+TINYMEDIA_API const tsdp_header_M_t* tmedia_get_local_offer(tmedia_t* , ...);
+TINYMEDIA_API const tsdp_header_M_t* tmedia_get_negotiated_offer(tmedia_t* );
+TINYMEDIA_API int tmedia_set_remote_offer(tmedia_t* , const tsdp_message_t* );
+
+TINYMEDIA_API int tmedia_perform(tmedia_t* , tmedia_action_t, ... );
+
+TINYMEDIA_GEXTERN const void *tmedia_def_t;
+
+#endif
+
+TMEDIA_END_DECLS
+
+
+#endif /* TINYMEDIA_TMEDIA_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_codec.h b/tinyMEDIA/include/tinymedia/tmedia_codec.h
new file mode 100644
index 0000000..f29abf6
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_codec.h
@@ -0,0 +1,468 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tmedia_codec.h
+ * @brief Base codec object.
+ *
+ */
+#ifndef TINYMEDIA_CODEC_H
+#define TINYMEDIA_CODEC_H
+
+#include "tinymedia_config.h"
+
+#include "tmedia_common.h"
+
+#include "tsk_list.h"
+
+
+TMEDIA_BEGIN_DECLS
+
+/* =====
+* http://www.iana.org/assignments/rtp-parameters
+* http://www.networksorcery.com/enp/protocol/rtp.htm
+=====*/
+/******* Fixed Payload Type *************/
+#define TMEDIA_CODEC_FORMAT_G711u "0"
+#define TMEDIA_CODEC_FORMAT_1016 "1"
+#define TMEDIA_CODEC_FORMAT_G721 "2"
+#define TMEDIA_CODEC_FORMAT_GSM "3"
+#define TMEDIA_CODEC_FORMAT_G723 "4"
+#define TMEDIA_CODEC_FORMAT_DVI4_8000 "5"
+#define TMEDIA_CODEC_FORMAT_DVI4_16000 "6"
+#define TMEDIA_CODEC_FORMAT_LPC "7"
+#define TMEDIA_CODEC_FORMAT_G711a "8"
+#define TMEDIA_CODEC_FORMAT_G722 "9"
+#define TMEDIA_CODEC_FORMAT_L16_STEREO "10"
+#define TMEDIA_CODEC_FORMAT_L16 "11"
+#define TMEDIA_CODEC_FORMAT_QCELP "12"
+#define TMEDIA_CODEC_FORMAT_CN "13"
+#define TMEDIA_CODEC_FORMAT_MPA "14"
+#define TMEDIA_CODEC_FORMAT_G728 "15"
+#define TMEDIA_CODEC_FORMAT_DVI4_11025 "16"
+#define TMEDIA_CODEC_FORMAT_DVI4_22050 "17"
+#define TMEDIA_CODEC_FORMAT_G729 "18"
+
+#define TMEDIA_CODEC_FORMAT_CELLB "25"
+#define TMEDIA_CODEC_FORMAT_JPEG "26"
+#define TMEDIA_CODEC_FORMAT_NV "28"
+
+#define TMEDIA_CODEC_FORMAT_H261 "31"
+#define TMEDIA_CODEC_FORMAT_MPV "32"
+#define TMEDIA_CODEC_FORMAT_MP2T "33"
+#define TMEDIA_CODEC_FORMAT_H263 "34"
+
+/******* Dynamic Payload Type
+Must starts at 96 to be conform to RFC 5761 (rtcp-mux)
+**********/
+
+#define TMEDIA_CODEC_FORMAT_ILBC "96"
+
+#define TMEDIA_CODEC_FORMAT_SPEEX_NB "97"
+#define TMEDIA_CODEC_FORMAT_SPEEX_WB "98"
+#define TMEDIA_CODEC_FORMAT_SPEEX_UWB "99"
+#define TMEDIA_CODEC_FORMAT_VP8 "100" /* Must to ease neg. with chrome and Asterisk */
+#define TMEDIA_CODEC_FORMAT_DTMF "101"
+
+#define TMEDIA_CODEC_FORMAT_H263_2000 "102"
+#define TMEDIA_CODEC_FORMAT_H263_1998 "103"
+#define TMEDIA_CODEC_FORMAT_H264_BP "104"
+#define TMEDIA_CODEC_FORMAT_H264_MP "105"
+#define TMEDIA_CODEC_FORMAT_H264_HP "106"
+
+#define TMEDIA_CODEC_FORMAT_AMR_WBP_BE "107"
+#define TMEDIA_CODEC_FORMAT_AMR_WBP_OA "108"
+#define TMEDIA_CODEC_FORMAT_AAC "109"
+#define TMEDIA_CODEC_FORMAT_AACPLUS "110"
+
+#define TMEDIA_CODEC_FORMAT_OPUS "111"
+
+#define TMEDIA_CODEC_FORMAT_AMR_NB_BE "112"
+#define TMEDIA_CODEC_FORMAT_AMR_NB_OA "113"
+#define TMEDIA_CODEC_FORMAT_AMR_WB_BE "114"
+#define TMEDIA_CODEC_FORMAT_AMR_WB_OA "115"
+
+#define TMEDIA_CODEC_FORMAT_BV16 "116"
+
+#define TMEDIA_CODEC_FORMAT_MP4V_ES "121"
+
+#define TMEDIA_CODEC_FORMAT_ULPFEC "122"
+#define TMEDIA_CODEC_FORMAT_RED "123"
+#define TMEDIA_CODEC_FORMAT_T140 "124"
+
+#define TMEDIA_CODEC_FORMAT_THEORA "125"
+
+
+#define TMEDIA_CODEC_FORMAT_MSRP "*"
+#define TMEDIA_CODEC_FORMAT_BFCP "*"
+
+
+
+// @tinyWRAP
+typedef enum tmedia_codec_id_e
+{
+ tmedia_codec_id_none = 0x00000000,
+
+ tmedia_codec_id_amr_nb_oa = 0x00000001<<0,
+ tmedia_codec_id_amr_nb_be = 0x00000001<<1,
+ tmedia_codec_id_amr_wb_oa = 0x00000001<<2,
+ tmedia_codec_id_amr_wb_be = 0x00000001<<3,
+ tmedia_codec_id_gsm = 0x00000001<<4,
+ tmedia_codec_id_pcma = 0x00000001<<5,
+ tmedia_codec_id_pcmu = 0x00000001<<6,
+ tmedia_codec_id_ilbc = 0x00000001<<7,
+ tmedia_codec_id_speex_nb = 0x00000001<<8,
+ tmedia_codec_id_speex_wb = 0x00000001<<9,
+ tmedia_codec_id_speex_uwb = 0x00000001<<10,
+ tmedia_codec_id_bv16 = 0x00000001<<11,
+ tmedia_codec_id_bv32 = 0x00000001<<12,
+ tmedia_codec_id_opus = 0x00000001<<13,
+ tmedia_codec_id_g729ab = 0x00000001<<14,
+ tmedia_codec_id_g722 = 0x00000001<<15,
+
+ /* room for new Audio codecs */
+
+ tmedia_codec_id_h261 = 0x00010000<<0,
+ tmedia_codec_id_h263 = 0x00010000<<1,
+ tmedia_codec_id_h263p = 0x00010000<<2,
+ tmedia_codec_id_h263pp = 0x00010000<<3,
+ tmedia_codec_id_h264_bp = 0x00010000<<4,
+ tmedia_codec_id_h264_mp = 0x00010000<<5,
+ tmedia_codec_id_h264_hp = 0x00010000<<6,
+ tmedia_codec_id_h264_bp10 = tmedia_codec_id_h264_bp, // @deprecated
+ tmedia_codec_id_h264_bp20 = tmedia_codec_id_h264_bp, // @deprecated
+ tmedia_codec_id_h264_bp30 = tmedia_codec_id_h264_bp, // @deprecated
+ tmedia_codec_id_h264_svc = 0x00010000<<7,
+ tmedia_codec_id_theora = 0x00010000<<8,
+ tmedia_codec_id_mp4ves_es = 0x00010000<<9,
+ tmedia_codec_id_vp8 = 0x00010000<<10,
+
+ /* room for new Video codecs */
+
+ tmedia_codec_id_t140 = 0x00010000<<14,
+ tmedia_codec_id_red = 0x00010000<<15,
+
+
+ tmedia_codec_id_all = 0xffffffff,
+}
+tmedia_codec_id_t;
+
+
+
+/**Max number of plugins (codec types) we can create */
+#if !defined(TMED_CODEC_MAX_PLUGINS)
+# define TMED_CODEC_MAX_PLUGINS 0xFF
+#endif
+
+/** cast any pointer to @ref tmedia_codec_t* object */
+#define TMEDIA_CODEC(self) ((tmedia_codec_t*)(self))
+
+
+#define TMEDIA_CODEC_RATE_DECODING(self) (TMEDIA_CODEC((self))->in.rate)
+#define TMEDIA_CODEC_RATE_ENCODING(self) (TMEDIA_CODEC((self))->out.rate)
+
+#define TMEDIA_CODEC_PTIME_AUDIO_DECODING(self) (TMEDIA_CODEC_AUDIO((self))->in.ptime)
+#define TMEDIA_CODEC_PTIME_AUDIO_ENCODING(self) (TMEDIA_CODEC_AUDIO((self))->out.ptime)
+
+#define TMEDIA_CODEC_CHANNELS_AUDIO_DECODING(self) (TMEDIA_CODEC_AUDIO((self))->in.channels)
+#define TMEDIA_CODEC_CHANNELS_AUDIO_ENCODING(self) (TMEDIA_CODEC_AUDIO((self))->out.channels)
+
+#define TMEDIA_CODEC_PCM_FRAME_SIZE_AUDIO_DECODING(self) ((TMEDIA_CODEC_PTIME_AUDIO_DECODING((self)) * TMEDIA_CODEC_RATE_DECODING((self)))/1000)
+#define TMEDIA_CODEC_PCM_FRAME_SIZE_AUDIO_ENCODING(self) ((TMEDIA_CODEC_PTIME_AUDIO_ENCODING((self)) * TMEDIA_CODEC_RATE_ENCODING((self)))/1000)
+
+#define TMEDIA_CODEC_FRAME_DURATION_AUDIO_ENCODING(self) (int32_t)((float)TMEDIA_CODEC_PCM_FRAME_SIZE_AUDIO_ENCODING(self) * (float)TMEDIA_CODEC_AUDIO((self))->out.timestamp_multiplier)
+
+/** callbacks for video codecs */
+typedef int (*tmedia_codec_video_enc_cb_f)(const tmedia_video_encode_result_xt* result);
+typedef int (*tmedia_codec_video_dec_cb_f)(const tmedia_video_decode_result_xt* result);
+
+
+struct tmedia_param_s;
+struct tsdp_header_M_s;
+
+typedef enum tmedia_codec_action_e
+{
+ tmedia_codec_action_encode_idr,
+ tmedia_codec_action_bw_down,
+ tmedia_codec_action_bw_up,
+}
+tmedia_codec_action_t;
+
+/** Base object for all Codecs */
+typedef struct tmedia_codec_s
+{
+ TSK_DECLARE_OBJECT;
+
+ //! the type of the codec
+ tmedia_type_t type;
+ //! the codec identifier
+ tmedia_codec_id_t id;
+ //! whether the codec is opened
+ tsk_bool_t opened;
+ //! whether the pay. type is dyn. or not
+ tsk_bool_t dyn;
+ //! the name of the codec. e.g. "G.711U" or "G.711A" etc used in the sdp
+ char* name;
+ //! full description
+ char* desc;
+ //! the format. e.g. "0" for PCMU or "8" for PCMA or "*" for MSRP.
+ char* format;
+ //! bandwidth level
+ tmedia_bandwidth_level_t bl; // @deprecated
+ //! maximum bandwidth to use for outgoing RTP (INT_MAX or <=0 means undefined)
+ int32_t bandwidth_max_upload;
+ //! maximum bandwidth to use for incoming RTP (INT_MAX or <=0 means undefined)
+ int32_t bandwidth_max_download;
+ //! the negociated format (only useful for codecs with dyn. payload type)
+ char* neg_format;
+ //! whether this is a passthrough codec
+ tsk_bool_t passthrough;
+
+ struct{
+ // !negotiated decoding rate (for codecs with dynamic rate, e.g. opus)
+ uint32_t rate;
+ } in; //decoding direction
+ struct{
+ // !negotiated encoding rate (for codecs with dynamic rate, e.g. opus)
+ uint32_t rate;
+ } out; //encoding direction
+
+ //! plugin used to create the codec
+ const struct tmedia_codec_plugin_def_s* plugin;
+}
+tmedia_codec_t;
+#define TMEDIA_CODEC(self) ((tmedia_codec_t*)(self))
+
+/** Virtual table used to define a codec plugin */
+typedef struct tmedia_codec_plugin_def_s
+{
+ //! object definition used to create an instance of the codec
+ const tsk_object_def_t* objdef;
+
+ //! the type of the codec
+ tmedia_type_t type;
+ //! the codec identifier
+ tmedia_codec_id_t codec_id;
+ //! the name of the codec. e.g. "G.711U" or "G.711A" etc using in the sdp.
+ const char* name;
+ //! full description
+ const char* desc;
+ //! the format. e.g. "0" for PCMU or "8" for PCMA or "*" for MSRP.
+ const char* format;
+ //! whether the pay. type is dyn. or not
+ tsk_bool_t dyn;
+ uint32_t rate;
+
+ /* default values could be updated at any time */
+ struct{
+ int8_t channels;
+ uint8_t ptime;
+ /* ...to be continued */
+ } audio;
+
+ /* default values could be updated at any time */
+ struct{
+ unsigned width;
+ unsigned height;
+ unsigned fps;
+ /* ...to be continued */
+ } video;
+
+ //! set parameters
+ int (*set) (tmedia_codec_t* , const struct tmedia_param_s*);
+ //! open the codec
+ int (*open) (tmedia_codec_t*);
+ //! close the codec
+ int (*close) (tmedia_codec_t*);
+ //! encode data
+ tsk_size_t (*encode) (tmedia_codec_t*, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size);
+ //! decode data
+ tsk_size_t (*decode) (tmedia_codec_t*, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size, const tsk_object_t* proto_hdr);
+ //! whether the codec can handle this sdp attribute
+ tsk_bool_t (* sdp_att_match) (const tmedia_codec_t*, const char* att_name, const char* att_value);
+ //! gets sdp attribute value. e.g. "mode-set=0,2,5,7; mode-change-period=2; mode-change-neighbor=1"
+ char* (* sdp_att_get) (const tmedia_codec_t*, const char* att_name);
+}
+tmedia_codec_plugin_def_t;
+
+/** List of @ref tmedia_codec_t elements */
+typedef tsk_list_t tmedia_codecs_L_t;
+
+/**< Declare base class as codec */
+#define TMEDIA_DECLARE_CODEC tmedia_codec_t __codec__
+
+TINYMEDIA_API int tmedia_codec_init(tmedia_codec_t* self, tmedia_type_t type, const char* name, const char* desc, const char* format);
+TINYMEDIA_API int tmedia_codec_set(tmedia_codec_t* self, const struct tmedia_param_s* param);
+TINYMEDIA_API int tmedia_codec_open(tmedia_codec_t* self);
+TINYMEDIA_API int tmedia_codec_close(tmedia_codec_t* self);
+TINYMEDIA_API int tmedia_codec_cmp(const tsk_object_t* codec1, const tsk_object_t* codec2);
+TINYMEDIA_API int tmedia_codec_plugin_register(const tmedia_codec_plugin_def_t* plugin);
+TINYMEDIA_API int tmedia_codec_plugin_register_2(const tmedia_codec_plugin_def_t* plugin, int prio);
+TINYMEDIA_API tsk_bool_t tmedia_codec_plugin_is_registered(const tmedia_codec_plugin_def_t* plugin);
+TINYMEDIA_API tsk_bool_t tmedia_codec_plugin_is_registered_2(tmedia_codec_id_t codec_id);
+TINYMEDIA_API int tmedia_codec_plugin_registered_get_all(const struct tmedia_codec_plugin_def_s*(** plugins)[TMED_CODEC_MAX_PLUGINS], tsk_size_t* count);
+TINYMEDIA_API const struct tmedia_codec_plugin_def_s* tmedia_codec_plugin_registered_get_const(tmedia_codec_id_t codec_id);
+TINYMEDIA_API int tmedia_codec_plugin_unregister(const tmedia_codec_plugin_def_t* plugin);
+TINYMEDIA_API int tmedia_codec_plugin_unregister_all();
+TINYMEDIA_API tmedia_codec_t* tmedia_codec_create(const char* format);
+TINYMEDIA_API char* tmedia_codec_get_rtpmap(const tmedia_codec_t* self);
+TINYMEDIA_API tsk_bool_t tmedia_codec_sdp_att_match(const tmedia_codec_t* self, const char* att_name, const char* att_value);
+TINYMEDIA_API char* tmedia_codec_sdp_att_get(const tmedia_codec_t* self, const char* att_name);
+TINYMEDIA_API int tmedia_codec_removeAll_exceptThese(tmedia_codecs_L_t* codecs, const tmedia_codecs_L_t * codecs2keep);
+TINYMEDIA_API int tmedia_codec_to_sdp(const tmedia_codecs_L_t* codecs, struct tsdp_header_M_s* m);
+TINYMEDIA_API tmedia_codec_t* tmedia_codec_find_by_format(tmedia_codecs_L_t* codecs, const char* format);
+TINYMEDIA_API int tmedia_codec_parse_fmtp(const char* fmtp, unsigned* maxbr, unsigned* fps, unsigned *width, unsigned *height);
+TINYMEDIA_API int tmedia_codec_deinit(tmedia_codec_t* self);
+
+/** Audio codec */
+typedef struct tmedia_codec_audio_s
+{
+ TMEDIA_DECLARE_CODEC;
+
+ struct{
+ // !negotiated decoding ptime
+ uint8_t ptime;
+ // !negotiated decoding channels
+ int8_t channels;
+ // ! timestamp multiplier
+ float timestamp_multiplier;
+ } in; //decoding direction
+ struct{
+ // !negotiated decoding ptime
+ uint8_t ptime;
+ // !negotiated encoding channels
+ int8_t channels;
+ // ! timestamp multiplier
+ float timestamp_multiplier;
+ } out; //encoding direction
+}
+tmedia_codec_audio_t;
+
+/**@def TMEDIA_DECLARE_CODEC_AUDIO
+* Declares base class as audio codec.
+*/
+/**@def TMEDIA_CODEC_AUDIO
+* Cast any pointer as @ref tmedia_codec_audio_t* object.
+*/
+/**@def tmedia_codec_audio_init
+* Initialize a audio codec.
+*/
+/**@def tmedia_codec_audio_deinit
+* DeInitialize a audio codec.
+*/
+#define TMEDIA_DECLARE_CODEC_AUDIO tmedia_codec_audio_t __audio__
+#define TMEDIA_CODEC_AUDIO(self) ((tmedia_codec_audio_t*)(self))
+#define tmedia_codec_audio_init(self, name, desc, format) tmedia_codec_init(TMEDIA_CODEC(self), tmedia_audio, name, desc, format)
+#define tmedia_codec_audio_deinit(self) tmedia_codec_deinit(TMEDIA_CODEC(self))
+TINYMEDIA_API float tmedia_codec_audio_get_timestamp_multiplier(tmedia_codec_id_t id, uint32_t sample_rate);
+
+/** Video codec */
+typedef struct tmedia_codec_video_s
+{
+ TMEDIA_DECLARE_CODEC;
+
+ struct{
+ unsigned width;
+ unsigned height;
+ unsigned fps;
+ unsigned max_br;
+ unsigned max_mbps;
+ tmedia_chroma_t chroma;
+ tsk_bool_t flip;
+
+ tmedia_codec_video_dec_cb_f callback;
+ tmedia_video_decode_result_xt result;
+ }in;// decoded
+ struct{
+ unsigned width;
+ unsigned height;
+ unsigned fps;
+ unsigned max_br;
+ unsigned max_mbps;
+ tmedia_chroma_t chroma;
+ tsk_bool_t flip;
+
+ tmedia_codec_video_enc_cb_f callback;
+ tmedia_video_encode_result_xt result;
+ }out;// encoded
+
+ //! preferred video size
+ tmedia_pref_video_size_t pref_size;
+}
+tmedia_codec_video_t;
+
+/**@def TMEDIA_DECLARE_CODEC_VIDEO
+* Declares base class as video codec.
+*/
+/**@def TMEDIA_CODEC_VIDEO
+* Cast any pointer as @ref tmedia_codec_video_t* object.
+*/
+/**@def tmedia_codec_video_init
+* Initialize a video codec.
+*/
+/**@def tmedia_codec_video_deinit
+* DeInitialize a video codec.
+*/
+#define TMEDIA_DECLARE_CODEC_VIDEO tmedia_codec_video_t __video__
+#define TMEDIA_CODEC_VIDEO(self) ((tmedia_codec_video_t*)(self))
+#define tmedia_codec_video_init(self, name, desc, format) tmedia_codec_init(TMEDIA_CODEC(self), tmedia_video, name, desc, format)
+TINYMEDIA_API int tmedia_codec_video_set_enc_callback(tmedia_codec_video_t *self, tmedia_codec_video_enc_cb_f callback, const void* callback_data);
+TINYMEDIA_API int tmedia_codec_video_set_dec_callback(tmedia_codec_video_t *self, tmedia_codec_video_dec_cb_f callback, const void* callback_data);
+#define tmedia_codec_video_deinit(self) tmedia_codec_deinit(TMEDIA_CODEC(self))
+
+
+/** MSRP codec */
+typedef struct tmedia_codec_msrp_s
+{
+ TMEDIA_DECLARE_CODEC;
+}
+tmedia_codec_msrp_t;
+
+/**@def TMEDIA_DECLARE_CODEC_MSRP
+* Declares base class as msrp codec.
+*/
+/**@def TMEDIA_CODEC_MSRP
+* Cast any pointer as @ref tmedia_codec_msrp_t* object.
+*/
+/**@def tmedia_codec_msrp_init
+* Initialize a msrp codec.
+*/
+/**@def tmedia_codec_msrp_deinit
+* DeInitialize a msrp codec.
+*/
+#define TMEDIA_DECLARE_CODEC_MSRP tmedia_codec_msrp_t __msrp__
+#define TMEDIA_CODEC_MSRP(self) ((tmedia_codec_msrp_t*)(self))
+#define tmedia_codec_msrp_init(self, name, desc) tmedia_codec_init(TMEDIA_CODEC(self), tmedia_msrp, name, desc, "*")
+#define tmedia_codec_msrp_deinit(self) tmedia_codec_deinit(TMEDIA_CODEC(self))
+
+
+/** BFCP codec */
+typedef struct tmedia_codec_bfcp_s
+{
+ TMEDIA_DECLARE_CODEC;
+}
+tmedia_codec_bfcp_t;
+#define TMEDIA_DECLARE_CODEC_BFCP tmedia_codec_bfcp_t __bfcp__
+#define TMEDIA_CODEC_BFCP(self) ((tmedia_codec_bfcp_t*)(self))
+#define tmedia_codec_bfcp_init(self, name, desc) tmedia_codec_init(TMEDIA_CODEC(self), tmedia_bfcp, name, desc, "*")
+#define tmedia_codec_bfcp_deinit(self) tmedia_codec_deinit(TMEDIA_CODEC(self))
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_CODEC_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_codec_dummy.h b/tinyMEDIA/include/tinymedia/tmedia_codec_dummy.h
new file mode 100644
index 0000000..9957eba
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_codec_dummy.h
@@ -0,0 +1,78 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_codec_dummy.h
+ * @brief Dummy codecs used for test only.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TINYMEDIA_CODEC_DUMMY_H
+#define TINYMEDIA_CODEC_DUMMY_H
+
+#include "tinymedia_config.h"
+
+#include "tmedia_codec.h"
+
+#include "tsk_object.h"
+
+TMEDIA_BEGIN_DECLS
+
+/** Dummy PCMU codec */
+typedef struct tmedia_codec_dpcmu_s
+{
+ TMEDIA_DECLARE_CODEC_AUDIO;
+}
+tmedia_codec_dpcmu_t;
+
+/** Dummy PCMA codec */
+typedef struct tmedia_codec_dpcma_s
+{
+ TMEDIA_DECLARE_CODEC_AUDIO;
+}
+tmedia_codec_dpcma_t;
+
+/** Dummy H.263 codec */
+typedef struct tmedia_codec_dh263_s
+{
+ TMEDIA_DECLARE_CODEC_VIDEO;
+}
+tmedia_codec_dh263_t;
+
+/** Dummy H.264 codec */
+typedef struct tmedia_codec_dh264_s
+{
+ TMEDIA_DECLARE_CODEC_VIDEO;
+}
+tmedia_codec_dh264_t;
+
+
+TINYMEDIA_GEXTERN const tmedia_codec_plugin_def_t *tmedia_codec_dpcma_plugin_def_t;
+TINYMEDIA_GEXTERN const tmedia_codec_plugin_def_t *tmedia_codec_dpcmu_plugin_def_t;
+
+TINYMEDIA_GEXTERN const tmedia_codec_plugin_def_t *tmedia_codec_dh263_plugin_def_t;
+TINYMEDIA_GEXTERN const tmedia_codec_plugin_def_t *tmedia_codec_dh264_plugin_def_t;
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_CODEC_DUMMY_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_common.h b/tinyMEDIA/include/tinymedia/tmedia_common.h
new file mode 100644
index 0000000..411007b
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_common.h
@@ -0,0 +1,285 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_common.h
+ * @brief Common functions and definitions.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TINYMEDIA_COMMON_H
+#define TINYMEDIA_COMMON_H
+
+#include "tinymedia_config.h"
+
+#include "tsk_plugin.h"
+#include "tsk_object.h"
+
+TMEDIA_BEGIN_DECLS
+
+struct tsdp_message_s;
+struct tsdp_header_M_s;
+
+/** List of all supported media types */
+// @tinyWRAP
+typedef enum tmedia_type_e
+{
+ tmedia_none = 0x00,
+ tmedia_ghost = (0x01 << 0),
+
+ tmedia_audio = (0x01 << 1),
+ tmedia_video = (0x01 << 2),
+ tmedia_chat = (0x01 << 3),
+ tmedia_file = (0x01 << 4),
+ tmedia_t38 = (0x01 << 5),
+ tmedia_t140 = (0x01 << 6),
+ tmedia_bfcp = (0x01 << 7),
+ tmedia_bfcp_audio = (0x01 << 8)/*must*/ | tmedia_bfcp, /* do not add "| audio". Otherwise it will be impossible to start an "video+bfcp-audio" session. */
+ tmedia_bfcp_video = (0x01 << 9)/*must*/ | tmedia_bfcp, /* do not add "| video". Otherwise it will be impossible to start an "audio+bfcp-video" session. */
+
+ tmedia_msrp = (tmedia_chat | tmedia_file),
+ tmedia_audiovideo = (tmedia_audio | tmedia_video),
+
+ tmedia_all = 0xff
+}
+tmedia_type_t;
+
+// @tinyWRAP
+typedef enum tmedia_mode_e
+{
+ tmedia_mode_none,
+ tmedia_mode_optional,
+ tmedia_mode_mandatory
+}
+tmedia_mode_t;
+
+// @tinyWRAP
+typedef enum tmedia_srtp_mode_e
+{
+ tmedia_srtp_mode_none,
+ tmedia_srtp_mode_optional,
+ tmedia_srtp_mode_mandatory
+}
+tmedia_srtp_mode_t;
+
+// @tinyWRAP
+typedef enum tmedia_srtp_type_e
+{
+ tmedia_srtp_type_none = 0x00,
+ tmedia_srtp_type_sdes = 0x01,
+ tmedia_srtp_type_dtls = 0x02,
+ tmedia_srtp_type_sdes_dtls = (tmedia_srtp_type_sdes | tmedia_srtp_type_dtls)
+}
+tmedia_srtp_type_t;
+
+// @tinyWRAP
+typedef enum tmedia_t140_data_type_e
+{
+ tmedia_t140_data_type_utf8,
+ tmedia_t140_data_type_zero_width_no_break_space = 0xefbbbf,
+ tmedia_t140_data_type_backspace = 0x08,
+ tmedia_t140_data_type_esc = 0x1b,
+ tmedia_t140_data_type_cr = 0x0d,
+ tmedia_t140_data_type_lf = 0x0a,
+ tmedia_t140_data_type_cr_lf = 0x0d0a,
+ tmedia_t140_data_type_bell = 0x07,
+ tmedia_t140_data_type_sos = 0x98,
+ tmedia_t140_data_type_string_term = 0x9c,
+ tmedia_t140_data_type_graphic_start = 0x9b,
+ tmedia_t140_data_type_graphic_end = 0x6d,
+ tmedia_t140_data_type_loss_char_char = 0xfffd,
+ tmedia_t140_data_type_loss_utf8 = 0xefbfbd,
+}
+tmedia_t140_data_type_t;
+
+// @tinyWRAP
+typedef enum tmedia_rtcp_event_type_e
+{
+ tmedia_rtcp_event_type_fir, // Full Intra Refresh
+}
+tmedia_rtcp_event_type_t;
+
+// @tinyWRAP
+typedef enum tmedia_profile_e
+{
+ tmedia_profile_default,
+ // Enable all RTCWeb specifications:
+ // ICE, DTLS-SRTP, RTP/AVPF, FEC, RED, SDPCapNeg, RTCP-MUX, imageattr...
+ tmedia_profile_rtcweb
+}
+tmedia_profile_t;
+
+// @tinyWRAP
+typedef enum tmedia_pref_video_size_s
+{ /* must be sorted like this */
+ tmedia_pref_video_size_sqcif, // 128 x 98
+ tmedia_pref_video_size_qcif, // 176 x 144
+ tmedia_pref_video_size_qvga, // 320 x 240
+ tmedia_pref_video_size_cif, // 352 x 288
+ tmedia_pref_video_size_hvga, // 480 x 320
+ tmedia_pref_video_size_vga, // 640 x 480
+ tmedia_pref_video_size_4cif, // 704 x 576
+ tmedia_pref_video_size_wvga, // 800 x 480
+ tmedia_pref_video_size_svga, // 800 x 600
+ tmedia_pref_video_size_480p, // 852 x 480
+ tmedia_pref_video_size_xga, // 1024 x 768
+ tmedia_pref_video_size_720p, // 1280 x 720
+ tmedia_pref_video_size_16cif, // 1408 x 1152
+ tmedia_pref_video_size_1080p, // 1920 x 1080
+ tmedia_pref_video_size_2160p, // 3840 x 2160
+}
+tmedia_pref_video_size_t;
+
+typedef enum tmedia_rtcweb_type_e
+{
+ tmedia_rtcweb_type_none,
+ tmedia_rtcweb_type_firefox,
+ tmedia_rtcweb_type_chrome,
+ tmedia_rtcweb_type_ie,
+ tmedia_rtcweb_type_safari,
+ tmedia_rtcweb_type_opera,
+ tmedia_rtcweb_type_ericsson,
+ tmedia_rtcweb_type_doubango
+}
+tmedia_rtcweb_type_t;
+
+typedef enum tmedia_video_encode_result_type_e
+{
+ tmedia_video_encode_result_type_none = 0x00,
+ tmedia_video_encode_result_type_params = (0x01 << 0), // e.g. SPS or PPS, DCT coeff., Quant params....
+ tmedia_video_encode_result_type_intra = (0x01 << 1),
+ tmedia_video_encode_result_type_key = tmedia_video_encode_result_type_intra,
+ tmedia_video_encode_result_type_gold = tmedia_video_encode_result_type_intra,
+ tmedia_video_encode_result_type_predicted = (0x01 << 2),
+ tmedia_video_encode_result_type_bipredicted = (0x01 << 3)
+}
+tmedia_video_encode_result_type_t;
+
+typedef struct tmedia_video_encode_result_xs
+{
+ tmedia_video_encode_result_type_t type;
+ const void* usr_data;
+ struct{
+ const void* ptr;
+ tsk_size_t size;
+ } buffer;
+ uint32_t duration;
+ tsk_bool_t last_chunck;
+ const tsk_object_t* proto_hdr;
+}
+tmedia_video_encode_result_xt;
+
+#define tmedia_video_encode_result_reset(result) \
+ (result)->type = tmedia_video_encode_result_type_none; \
+ (result)->usr_data = tsk_null; \
+ (result)->proto_hdr = tsk_null; \
+ (result)->buffer.ptr = tsk_null; \
+ (result)->buffer.size = 0; \
+ (result)->duration = 0; \
+ (result)->last_chunck = tsk_false; \
+ (result)->proto_hdr = tsk_null; \
+
+typedef enum tmedia_video_decode_result_type_e
+{
+ tmedia_video_decode_result_type_none,
+
+ tmedia_video_decode_result_type_error,
+ tmedia_video_decode_result_type_idr,
+}
+tmedia_video_decode_result_type_t;
+
+typedef struct tmedia_video_decode_result_xs
+{
+ tmedia_video_decode_result_type_t type;
+ const void* usr_data;
+ const tsk_object_t* proto_hdr; // RTP, RTSP....
+}
+tmedia_video_decode_result_xt;
+
+#define tmedia_video_decode_result_reset(result) \
+ (result)->type = tmedia_video_decode_result_type_none; \
+ (result)->usr_data = tsk_null; \
+ (result)->proto_hdr = tsk_null; \
+
+
+// @tinyWRAP
+typedef enum tmedia_chroma_e
+{
+ tmedia_chroma_none=0,
+ tmedia_chroma_rgb24, // will be stored as bgr24 on x86 (little endians) machines; e.g. WindowsPhone7
+ tmedia_chroma_bgr24, // used by windows consumer (DirectShow) -
+ tmedia_chroma_rgb32, // used by iOS4 consumer (iPhone and iPod touch)
+ tmedia_chroma_rgb565le, // (used by both android and wince consumers)
+ tmedia_chroma_rgb565be,
+ tmedia_chroma_nv12, // used by iOS4 producer (iPhone and iPod Touch 3GS and 4)
+ tmedia_chroma_nv21, // Yuv420 SP (used by android producer)
+ tmedia_chroma_yuv422p,
+ tmedia_chroma_uyvy422, // used by iOS4 producer (iPhone and iPod Touch 3G) - Microsoft: MFVideoFormat_YUY2
+ tmedia_chroma_yuv420p, // Default
+ tmedia_chroma_mjpeg, // VirtualBox default camera mode (Windows as host and Linux as guest)
+ tmedia_chroma_yuyv422, // YUYV422 (V4L2 preferred format)
+}
+tmedia_chroma_t;
+
+// @tinyWRAP
+// @deprecated
+// keep order (low->unrestricted)
+typedef enum tmedia_bandwidth_level_e
+{
+ tmedia_bl_low,
+ tmedia_bl_medium,
+ tmedia_bl_hight,
+ tmedia_bl_unrestricted
+}
+tmedia_bandwidth_level_t;
+
+typedef enum tmedia_ro_type_e
+{
+ tmedia_ro_type_none = 0x00,
+ tmedia_ro_type_offer = (0x01 << 0),
+ tmedia_ro_type_answer = (0x01 << 1),
+ tmedia_ro_type_provisional = tmedia_ro_type_answer | (0x01 << 2),
+}
+tmedia_ro_type_t;
+
+TINYMEDIA_API tsk_size_t tmedia_plugin_register(struct tsk_plugin_s* plugin, enum tsk_plugin_def_type_e type, enum tsk_plugin_def_media_type_e media);
+TINYMEDIA_API tsk_size_t tmedia_plugin_unregister(struct tsk_plugin_s* plugin, enum tsk_plugin_def_type_e type, enum tsk_plugin_def_media_type_e media);
+TINYMEDIA_API tmedia_type_t tmedia_type_from_sdp(const struct tsdp_message_s* sdp);
+TINYMEDIA_API tmedia_type_t tmedia_type_from_sdp_headerM(const struct tsdp_header_M_s* M);
+TINYMEDIA_API int tmedia_parse_rtpmap(const char* rtpmap, char** name, int32_t* rate, int32_t* channels);
+TINYMEDIA_API int tmedia_video_get_size(tmedia_pref_video_size_t pref_vs, unsigned *width, unsigned *height);
+TINYMEDIA_API int tmedia_video_get_closest_cif_size(tmedia_pref_video_size_t pref_vs, tmedia_pref_video_size_t *cif_vs);
+TINYMEDIA_API int tmedia_video_get_closest_pref_size(unsigned width, unsigned height, tmedia_pref_video_size_t *pref_vs);
+TINYMEDIA_API int tmedia_parse_video_fmtp(const char* fmtp, tmedia_pref_video_size_t pref_vs, unsigned* width, unsigned* height, unsigned* fps);
+TINYMEDIA_API int tmedia_parse_video_imageattr(const char* imageattr, tmedia_pref_video_size_t pref_vs, unsigned* in_width, unsigned* in_height, unsigned* out_width, unsigned* out_height);
+TINYMEDIA_API char* tmedia_get_video_fmtp(tmedia_pref_video_size_t pref_vs);
+TINYMEDIA_API char* tmedia_get_video_imageattr(tmedia_pref_video_size_t pref_vs, unsigned in_width, unsigned in_height, unsigned out_width, unsigned out_height);
+TINYMEDIA_API int tmedia_get_video_quality(tmedia_bandwidth_level_t bl);
+TINYMEDIA_API int32_t tmedia_get_video_bandwidth_kbps(unsigned width, unsigned height, unsigned fps, unsigned motion_rank);
+TINYMEDIA_API int32_t tmedia_get_video_bandwidth_kbps_2(unsigned width, unsigned height, unsigned fps);
+TINYMEDIA_API int32_t tmedia_get_video_bandwidth_kbps_3();
+#define tmedia_get_video_qscale tmedia_get_video_quality
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_COMMON_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_consumer.h b/tinyMEDIA/include/tinymedia/tmedia_consumer.h
new file mode 100644
index 0000000..0e88f45
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_consumer.h
@@ -0,0 +1,147 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_consumer.h
+ * @brief Base consumer object.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+ */
+#ifndef TINYMEDIA_CONSUMER_H
+#define TINYMEDIA_CONSUMER_H
+
+#include "tinymedia_config.h"
+
+#include "tinymedia/tmedia_codec.h"
+#include "tinymedia/tmedia_params.h"
+#include "tmedia_common.h"
+
+TMEDIA_BEGIN_DECLS
+
+#define TMEDIA_CONSUMER_BITS_PER_SAMPLE_DEFAULT 16
+#define TMEDIA_CONSUMER_CHANNELS_DEFAULT 2
+#define TMEDIA_CONSUMER_RATE_DEFAULT 8000
+
+
+/**Max number of plugins (consumer types) we can create */
+#if !defined(TMED_CONSUMER_MAX_PLUGINS)
+# define TMED_CONSUMER_MAX_PLUGINS 0x0F
+#endif
+
+/** cast any pointer to @ref tmedia_consumer_t* object */
+#define TMEDIA_CONSUMER(self) ((tmedia_consumer_t*)(self))
+
+/** Default Video chroma */
+#if !defined(TMEDIA_CONSUMER_CHROMA_DEFAULT)
+# define TMEDIA_CONSUMER_CHROMA_DEFAULT tmedia_chroma_yuv420p
+#endif
+
+/** Base object for all Consumers */
+typedef struct tmedia_consumer_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tmedia_type_t type;
+ const char* desc;
+
+ struct{
+ int fps;
+ struct {
+ tmedia_chroma_t chroma;
+ tsk_size_t width;
+ tsk_size_t height;
+ } in;
+ struct {
+ tmedia_chroma_t chroma;
+ tsk_size_t width;
+ tsk_size_t height;
+ tsk_bool_t auto_resize; // auto_resize to "in.width, in.height"
+ } display;
+ } video;
+
+ struct{
+ uint8_t bits_per_sample;
+ uint8_t ptime;
+ uint8_t gain;
+ struct{
+ uint8_t channels;
+ uint32_t rate;
+ } in;
+ struct{
+ uint8_t channels;
+ uint32_t rate;
+ } out;
+ int32_t volume;
+ } audio;
+
+ tsk_bool_t is_started;
+ tsk_bool_t is_prepared;
+ uint64_t session_id;
+
+ struct{
+ enum tmedia_codec_id_e codec_id;
+ // other options to be added
+ } decoder;
+
+ const struct tmedia_consumer_plugin_def_s* plugin;
+}
+tmedia_consumer_t;
+
+/** Virtual table used to define a consumer plugin */
+typedef struct tmedia_consumer_plugin_def_s
+{
+ //! object definition used to create an instance of the consumer
+ const tsk_object_def_t* objdef;
+
+ //! the type of the consumer
+ tmedia_type_t type;
+ //! full description (usefull for debugging)
+ const char* desc;
+
+ int (*set) (tmedia_consumer_t* , const tmedia_param_t*);
+ int (* prepare) (tmedia_consumer_t*, const tmedia_codec_t* );
+ int (* start) (tmedia_consumer_t* );
+ int (* consume) (tmedia_consumer_t*, const void* buffer, tsk_size_t size, const tsk_object_t* proto_hdr);
+ int (* pause) (tmedia_consumer_t* );
+ int (* stop) (tmedia_consumer_t* );
+}
+tmedia_consumer_plugin_def_t;
+
+#define TMEDIA_DECLARE_CONSUMER tmedia_consumer_t __consumer__
+
+TINYMEDIA_API tmedia_consumer_t* tmedia_consumer_create(tmedia_type_t type, uint64_t session_id);
+TINYMEDIA_API int tmedia_consumer_init(tmedia_consumer_t* self);
+TINYMEDIA_API int tmedia_consumer_set(tmedia_consumer_t *self, const tmedia_param_t* param);
+TINYMEDIA_API int tmedia_consumer_prepare(tmedia_consumer_t *self, const tmedia_codec_t* codec);
+TINYMEDIA_API int tmedia_consumer_start(tmedia_consumer_t *self);
+TINYMEDIA_API int tmedia_consumer_consume(tmedia_consumer_t* self, const void* buffer, tsk_size_t size, const tsk_object_t* proto_hdr);
+TINYMEDIA_API int tmedia_consumer_pause(tmedia_consumer_t *self);
+TINYMEDIA_API int tmedia_consumer_stop(tmedia_consumer_t *self);
+TINYMEDIA_API int tmedia_consumer_deinit(tmedia_consumer_t* self);
+
+TINYMEDIA_API int tmedia_consumer_plugin_register(const tmedia_consumer_plugin_def_t* plugin);
+TINYMEDIA_API int tmedia_consumer_plugin_unregister(const tmedia_consumer_plugin_def_t* plugin);
+TINYMEDIA_API int tmedia_consumer_plugin_unregister_by_type(tmedia_type_t type);
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_CONSUMER_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_converter_video.h b/tinyMEDIA/include/tinymedia/tmedia_converter_video.h
new file mode 100644
index 0000000..133dfab
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_converter_video.h
@@ -0,0 +1,114 @@
+/*
+* Copyright (C) 2012 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tmedia_converter_video.h
+ * @brief Video converter plugin (chroma, rotation, scaling, ...)
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+ */
+#ifndef TINYMEDIA_CONVERTER_VIDEO_H
+#define TINYMEDIA_CONVERTER_VIDEO_H
+
+#include "tinymedia_config.h"
+#include "tmedia_common.h"
+
+TMEDIA_BEGIN_DECLS
+
+/** cast any pointer to @ref tmedia_converter_video_t* object */
+#define TMEDIA_CONVERTER_VIDEO(self) ((tmedia_converter_video_t*)(self))
+
+/**Max number of plugins (consumer types) we can create */
+#if !defined(TMED_CONVERTER_VIDEO_MAX_PLUGINS)
+# define TMED_CONVERTER_VIDEO_MAX_PLUGINS 0x0F
+#endif
+
+typedef struct tmedia_converter_video_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_size_t srcWidth;
+ tsk_size_t srcHeight;
+
+ tsk_size_t dstWidth;
+ tsk_size_t dstHeight;
+
+ tmedia_chroma_t srcChroma;
+ tmedia_chroma_t dstChroma;
+
+ // one shot parameters
+ int rotation;
+ tsk_bool_t flip;
+ tsk_bool_t mirror;
+ tsk_bool_t scale_rotated_frames;
+
+ const struct tmedia_converter_video_plugin_def_s* plugin;
+}
+tmedia_converter_video_t;
+
+#define TMEDIA_DECLARE_CONVERTER_VIDEO tmedia_converter_video_t __converter__
+
+#define tmedia_converter_video_set(self, _rotation, _flip, _mirror, _scale_rotated_frames) \
+ if((self)){ \
+ (self)->rotation = (_rotation); \
+ (self)->flip = (_flip); \
+ (self)->mirror = (_mirror); \
+ (self)->scale_rotated_frames = (_scale_rotated_frames); \
+ }
+#define tmedia_converter_video_set_rotation(self, _rotation) \
+ if((self)){ \
+ (self)->rotation = (_rotation); \
+ }
+#define tmedia_converter_video_set_flip(self, _flip) \
+ if((self)){ \
+ (self)->flip = (_flip); \
+ }
+#define tmedia_converter_video_set_mirror(self, _mirror) \
+ if((self)){ \
+ (self)->mirror = (_mirror); \
+ }
+#define tmedia_converter_video_set_scale_rotated_frames(self, _scale_rotated_frames) \
+ if((self)){ \
+ (self)->scale_rotated_frames = (_scale_rotated_frames); \
+ }
+
+#define tmedia_converter_video_process(_self, _buffer, _size, _output, _output_max_size) \
+ (_self)->plugin->process((_self), (_buffer), (_size), (_output), (_output_max_size))
+
+/** Virtual table used to define a consumer plugin */
+typedef struct tmedia_converter_video_plugin_def_s
+{
+ //! object definition used to create an instance of the converter
+ const tsk_object_def_t* objdef;
+
+ int (* init) ( struct tmedia_converter_video_s* self, tsk_size_t srcWidth, tsk_size_t srcHeight, tmedia_chroma_t srcChroma, tsk_size_t dstWidth, tsk_size_t dstHeight, tmedia_chroma_t dstChroma );
+ tsk_size_t (* process) ( struct tmedia_converter_video_s* self, const void* buffer, tsk_size_t buffer_size, void** output, tsk_size_t* output_max_size );
+}
+tmedia_converter_video_plugin_def_t;
+
+TINYMEDIA_API tmedia_converter_video_t* tmedia_converter_video_create(tsk_size_t srcWidth, tsk_size_t srcHeight, tmedia_chroma_t srcChroma, tsk_size_t dstWidth, tsk_size_t dstHeight, tmedia_chroma_t dstChroma);
+
+TINYMEDIA_API int tmedia_converter_video_plugin_register(const tmedia_converter_video_plugin_def_t* plugin);
+TINYMEDIA_API tsk_size_t tmedia_converter_video_plugin_registry_count();
+TINYMEDIA_API int tmedia_converter_video_plugin_unregister(const tmedia_converter_video_plugin_def_t* plugin);
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_CONVERTER_VIDEO_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_defaults.h b/tinyMEDIA/include/tinymedia/tmedia_defaults.h
new file mode 100644
index 0000000..324c241
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_defaults.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2010-2011 Mamadou Diop.
+ *
+ * Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 TINYMEDIA_DEFAULTS_H
+#define TINYMEDIA_DEFAULTS_H
+
+#include "tinymedia_config.h"
+
+#include "tmedia_common.h"
+
+TMEDIA_BEGIN_DECLS
+
+
+TINYMEDIA_API int tmedia_defaults_set_profile(tmedia_profile_t profile);
+TINYMEDIA_API tmedia_profile_t tmedia_defaults_get_profile();
+TINYMEDIA_API int tmedia_defaults_set_bl(tmedia_bandwidth_level_t bl); // @deprecated
+TINYMEDIA_API tmedia_bandwidth_level_t tmedia_defaults_get_bl(); // @deprecated
+TINYMEDIA_API int tmedia_defaults_set_congestion_ctrl_enabled(tsk_bool_t enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_congestion_ctrl_enabled();
+TINYMEDIA_API int tmedia_defaults_set_video_fps(int32_t video_fps);
+TINYMEDIA_API int32_t tmedia_defaults_get_video_fps();
+TINYMEDIA_API int tmedia_defaults_set_video_motion_rank(int32_t video_motion_rank);
+TINYMEDIA_API int32_t tmedia_defaults_get_video_motion_rank();
+TINYMEDIA_API int tmedia_defaults_set_bandwidth_video_upload_max(int32_t bw_video_up_max_kbps);
+TINYMEDIA_API int32_t tmedia_defaults_get_bandwidth_video_upload_max();
+TINYMEDIA_API int tmedia_defaults_set_bandwidth_video_download_max(int32_t bw_video_down_max_kbps);
+TINYMEDIA_API int32_t tmedia_defaults_get_bandwidth_video_download_max();
+TINYMEDIA_API int tmedia_defaults_set_pref_video_size(tmedia_pref_video_size_t pref_video_size);
+TINYMEDIA_API tmedia_pref_video_size_t tmedia_defaults_get_pref_video_size();
+TINYMEDIA_API int tmedia_defaults_set_jb_margin(int32_t jb_margin_ms);
+TINYMEDIA_API int32_t tmedia_defaults_get_jb_margin();
+TINYMEDIA_API int tmedia_defaults_set_jb_max_late_rate(int32_t jb_max_late_rate_percent);
+TINYMEDIA_API int32_t tmedia_defaults_get_jb_max_late_rate();
+TINYMEDIA_API int tmedia_defaults_set_echo_tail(uint32_t echo_tail);
+TINYMEDIA_API int tmedia_defaults_set_echo_skew(uint32_t echo_skew);
+TINYMEDIA_API uint32_t tmedia_defaults_get_echo_tail();
+TINYMEDIA_API uint32_t tmedia_defaults_get_echo_skew();
+TINYMEDIA_API int tmedia_defaults_set_echo_supp_enabled(tsk_bool_t echo_supp_enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_echo_supp_enabled();
+TINYMEDIA_API int tmedia_defaults_set_agc_enabled(tsk_bool_t agc_enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_agc_enabled();
+TINYMEDIA_API int tmedia_defaults_set_agc_level(float agc_level);
+TINYMEDIA_API float tmedia_defaults_get_agc_level();
+TINYMEDIA_API int tmedia_defaults_set_vad_enabled(tsk_bool_t vad_enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_vad_enabled();
+TINYMEDIA_API int tmedia_defaults_set_noise_supp_enabled(tsk_bool_t noise_supp_enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_noise_supp_enabled();
+TINYMEDIA_API int tmedia_defaults_set_noise_supp_level(int32_t noise_supp_level);
+TINYMEDIA_API int32_t tmedia_defaults_get_noise_supp_level();
+TINYMEDIA_API int tmedia_defaults_set_100rel_enabled(tsk_bool_t _100rel_enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_100rel_enabled();
+TINYMEDIA_API int tmedia_defaults_set_screen_size(int32_t sx, int32_t sy);
+TINYMEDIA_API int32_t tmedia_defaults_get_screen_x();
+TINYMEDIA_API int32_t tmedia_defaults_get_screen_y();
+TINYMEDIA_API int tmedia_defaults_set_audio_ptime(int32_t audio_ptime);
+TINYMEDIA_API int32_t tmedia_defaults_get_audio_ptime();
+TINYMEDIA_API int tmedia_defaults_set_audio_channels(int32_t channels_playback, int32_t channels_record);
+TINYMEDIA_API int32_t tmedia_defaults_get_audio_channels_playback();
+TINYMEDIA_API int32_t tmedia_defaults_get_audio_channels_record();
+TINYMEDIA_API int tmedia_defaults_set_audio_gain(int32_t audio_producer_gain, int32_t audio_consumer_gain);
+TINYMEDIA_API int32_t tmedia_defaults_get_audio_producer_gain();
+TINYMEDIA_API int32_t tmedia_defaults_get_audio_consumer_gain();
+TINYMEDIA_API uint16_t tmedia_defaults_get_rtp_port_range_start();
+TINYMEDIA_API uint16_t tmedia_defaults_get_rtp_port_range_stop();
+TINYMEDIA_API int tmedia_defaults_set_rtp_port_range(uint16_t start, uint16_t stop);
+TINYMEDIA_API int tmedia_defaults_set_rtp_symetric_enabled(tsk_bool_t enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_rtp_symetric_enabled();
+TINYMEDIA_API tmedia_type_t tmedia_defaults_get_media_type();
+TINYMEDIA_API int tmedia_defaults_set_media_type(tmedia_type_t media_type);
+TINYMEDIA_API int tmedia_defaults_set_volume(int32_t volume);
+TINYMEDIA_API int32_t tmedia_defaults_get_volume();
+TINYMEDIA_API int tmedia_producer_set_friendly_name(tmedia_type_t media_type, const char* friendly_name);
+TINYMEDIA_API const char* tmedia_producer_get_friendly_name(tmedia_type_t media_type);
+TINYMEDIA_API int32_t tmedia_defaults_get_inv_session_expires();
+TINYMEDIA_API int tmedia_defaults_set_inv_session_expires(int32_t timeout);
+TINYMEDIA_API const char* tmedia_defaults_get_inv_session_refresher();
+TINYMEDIA_API int tmedia_defaults_set_inv_session_refresher(const char* refresher);
+TINYMEDIA_API tmedia_srtp_mode_t tmedia_defaults_get_srtp_mode();
+TINYMEDIA_API int tmedia_defaults_set_srtp_mode(tmedia_srtp_mode_t mode);
+TINYMEDIA_API tmedia_srtp_type_t tmedia_defaults_get_srtp_type();
+TINYMEDIA_API int tmedia_defaults_set_srtp_type(tmedia_srtp_type_t srtp_type);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_rtcp_enabled();
+TINYMEDIA_API int tmedia_defaults_set_rtcp_enabled(tsk_bool_t rtcp_enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_rtcpmux_enabled();
+TINYMEDIA_API int tmedia_defaults_set_rtcpmux_enabled(tsk_bool_t rtcpmux_enabled);
+TINYMEDIA_API int tmedia_defaults_set_stun_server(const char* server_ip, uint16_t server_port);
+TINYMEDIA_API int tmedia_defaults_get_stun_server(const char** server_ip, uint16_t*const server_port);
+TINYMEDIA_API int tmedia_defaults_set_stun_cred(const char* usr_name, const char* usr_pwd);
+TINYMEDIA_API int tmedia_defaults_get_stun_cred(const char** usr_name, const char** usr_pwd);
+TINYMEDIA_API int tmedia_defaults_set_stun_enabled(tsk_bool_t stun_enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_stun_enabled();
+TINYMEDIA_API int tmedia_defaults_set_icestun_enabled(tsk_bool_t icestun_enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_icestun_enabled();
+TINYMEDIA_API int tmedia_defaults_set_iceturn_enabled(tsk_bool_t iceturn_enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_iceturn_enabled();
+TINYMEDIA_API int tmedia_defaults_set_ice_enabled(tsk_bool_t ice_enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_ice_enabled();
+TINYMEDIA_API int tmedia_defaults_set_bypass_encoding(tsk_bool_t enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_bypass_encoding();
+TINYMEDIA_API int tmedia_defaults_set_bypass_decoding(tsk_bool_t enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_bypass_decoding();
+TINYMEDIA_API int tmedia_defaults_set_videojb_enabled(tsk_bool_t enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_videojb_enabled();
+TINYMEDIA_API int tmedia_defaults_set_video_zeroartifacts_enabled(tsk_bool_t enabled);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_video_zeroartifacts_enabled();
+TINYMEDIA_API int tmedia_defaults_set_rtpbuff_size(tsk_size_t rtpbuff_size);
+TINYMEDIA_API tsk_size_t tmedia_defaults_get_rtpbuff_size();
+TINYMEDIA_API int tmedia_defaults_set_avpf_tail(tsk_size_t tail_min, tsk_size_t tail_max);
+TINYMEDIA_API int tmedia_defaults_set_avpf_mode(enum tmedia_mode_e mode);
+TINYMEDIA_API enum tmedia_mode_e tmedia_defaults_get_avpf_mode();
+TINYMEDIA_API tsk_size_t tmedia_defaults_get_avpf_tail_min();
+TINYMEDIA_API tsk_size_t tmedia_defaults_get_avpf_tail_max();
+TINYMEDIA_API int tmedia_defaults_set_opus_maxcapturerate(uint32_t opus_maxcapturerate);
+TINYMEDIA_API uint32_t tmedia_defaults_get_opus_maxcapturerate();
+TINYMEDIA_API int tmedia_defaults_set_opus_maxplaybackrate(uint32_t opus_maxplaybackrate);
+TINYMEDIA_API uint32_t tmedia_defaults_get_opus_maxplaybackrate();
+TINYMEDIA_API int tmedia_defaults_set_ssl_certs(const char* priv_path, const char* pub_path, const char* ca_path, tsk_bool_t verify);
+TINYMEDIA_API int tmedia_defaults_get_ssl_certs(const char** priv_path, const char** pub_path, const char** ca_path, tsk_bool_t *verify);
+TINYMEDIA_API int tmedia_defaults_set_max_fds(int32_t max_fds);
+TINYMEDIA_API tsk_size_t tmedia_defaults_get_max_fds();
+TINYMEDIA_API int tmedia_defaults_set_webproxy_auto_detect(tsk_bool_t auto_detect);
+TINYMEDIA_API tsk_bool_t tmedia_defaults_get_webproxy_auto_detect();
+TINYMEDIA_API int tmedia_defaults_set_webproxy_info(const char* type, const char* host, unsigned short port, const char* login, const char* password);
+TINYMEDIA_API int tmedia_defaults_get_webproxy_info(const char** type, const char** host, unsigned short* port, const char** login, const char** password);
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_DEFAULTS_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_denoise.h b/tinyMEDIA/include/tinymedia/tmedia_denoise.h
new file mode 100644
index 0000000..d8818f4
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_denoise.h
@@ -0,0 +1,97 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tmedia_denoise.h
+ * @brief Denoiser (Noise suppression, AGC, AEC, VAD) Plugin
+ */
+#ifndef TINYMEDIA_DENOISE_H
+#define TINYMEDIA_DENOISE_H
+
+#include "tinymedia_config.h"
+#include "tinymedia/tmedia_params.h"
+
+#include "tsk_buffer.h"
+#include "tsk_object.h"
+
+TMEDIA_BEGIN_DECLS
+
+/** cast any pointer to @ref tmedia_denoise_t* object */
+#define TMEDIA_DENOISE(self) ((tmedia_denoise_t*)(self))
+
+/** Base object for all Denoisers */
+typedef struct tmedia_denoise_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_bool_t opened;
+
+ uint32_t echo_tail;
+ uint32_t echo_skew;
+ tsk_bool_t echo_supp_enabled;
+ tsk_bool_t agc_enabled ;
+ float agc_level;
+ tsk_bool_t vad_enabled;
+ tsk_bool_t noise_supp_enabled;
+ int32_t noise_supp_level;
+ tsk_buffer_t *record_frame;
+ tsk_buffer_t *playback_frame;
+ const struct tmedia_denoise_plugin_def_s* plugin;
+}
+tmedia_denoise_t;
+
+#define TMEDIA_DECLARE_DENOISE tmedia_denoise_t __denoise__
+
+/** Virtual table used to define a consumer plugin */
+typedef struct tmedia_denoise_plugin_def_s
+{
+ //! object definition used to create an instance of the denoiser
+ const tsk_object_def_t* objdef;
+
+ //! full description (usefull for debugging)
+ const char* desc;
+
+ int (*set) (tmedia_denoise_t* , const tmedia_param_t*);
+ int (* open) (tmedia_denoise_t*, uint32_t record_frame_size_samples, uint32_t record_sampling_rate, uint32_t record_channels, uint32_t playback_frame_size_samples, uint32_t playback_sampling_rate, uint32_t playback_channels);
+ int (*echo_playback) (tmedia_denoise_t* self, const void* echo_frame, uint32_t echo_frame_size_bytes);
+ //! aec, vad, noise suppression, echo cancellation before sending packet over network
+ int (* process_record) (tmedia_denoise_t*, void* audio_frame, uint32_t audio_frame_size_bytes, tsk_bool_t* silence_or_noise);
+ //! noise suppression before playing sound
+ int (* process_playback) (tmedia_denoise_t*, void* audio_frame, uint32_t audio_frame_size_bytes);
+ int (* close) (tmedia_denoise_t* );
+}
+tmedia_denoise_plugin_def_t;
+
+TINYMEDIA_API int tmedia_denoise_init(tmedia_denoise_t* self);
+TINYMEDIA_API int tmedia_denoise_set(tmedia_denoise_t* self, const tmedia_param_t* param);
+TINYMEDIA_API int tmedia_denoise_open(tmedia_denoise_t* self, uint32_t record_frame_size_samples, uint32_t record_sampling_rate, uint32_t record_channels, uint32_t playback_frame_size_samples, uint32_t playback_sampling_rate, uint32_t playback_channels);
+TINYMEDIA_API int tmedia_denoise_echo_playback(tmedia_denoise_t* self, const void* echo_frame, uint32_t echo_frame_size_bytes);
+TINYMEDIA_API int tmedia_denoise_process_record(tmedia_denoise_t* self, void* audio_frame, uint32_t audio_frame_size_bytes, tsk_bool_t* silence_or_noise);
+TINYMEDIA_API int tmedia_denoise_process_playback(tmedia_denoise_t* self, void* audio_frame, uint32_t audio_frame_size_bytes);
+TINYMEDIA_API int tmedia_denoise_close(tmedia_denoise_t* self);
+TINYMEDIA_API int tmedia_denoise_deinit(tmedia_denoise_t* self);
+
+TINYMEDIA_API int tmedia_denoise_plugin_register(const tmedia_denoise_plugin_def_t* plugin);
+TINYMEDIA_API int tmedia_denoise_plugin_unregister(const tmedia_denoise_plugin_def_t* plugin);
+TINYMEDIA_API tmedia_denoise_t* tmedia_denoise_create();
+
+TMEDIA_END_DECLS
+
+
+#endif /* TINYMEDIA_DENOISE_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_imageattr.h b/tinyMEDIA/include/tinymedia/tmedia_imageattr.h
new file mode 100644
index 0000000..c709a17
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_imageattr.h
@@ -0,0 +1,108 @@
+/*
+* Copyright (C) 2012 Doubango Telecom <http://www.doubango.org>
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_imageattr.h
+ * @brief 'image-attr' parser as per RFC 6236
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+ */
+#ifndef TINYMEDIA_imageattr_H
+#define TINYMEDIA_imageattr_H
+
+#include "tinymedia_config.h"
+
+#include "tmedia_common.h"
+
+TMEDIA_BEGIN_DECLS
+
+#define TMEDIA_imageattr_ARRAY_MAX_SIZE 16
+
+typedef int32_t xyvalue_t;
+typedef double qvalue_t;
+typedef double spvalue_t;
+
+typedef struct tmedia_imageattr_srange_xs
+{
+ unsigned is_range:1;
+ union{
+ struct{
+ spvalue_t start;
+ spvalue_t end;
+ }range;
+ struct{
+ spvalue_t values[TMEDIA_imageattr_ARRAY_MAX_SIZE + 1];
+ tsk_size_t count;
+ }array;
+ };
+}
+tmedia_imageattr_srange_xt;
+
+typedef struct tmedia_imageattr_xyrange_xs
+{
+ unsigned is_range:1;
+ union{
+ struct{
+ xyvalue_t start;
+ xyvalue_t step;
+ xyvalue_t end;
+ }range;
+ struct{
+ xyvalue_t values[TMEDIA_imageattr_ARRAY_MAX_SIZE + 1];
+ tsk_size_t count;
+ }array;
+ };
+}
+tmedia_imageattr_xyrange_xt;
+
+typedef struct tmedia_imageattr_set_xs
+{
+ tmedia_imageattr_xyrange_xt xrange;
+ tmedia_imageattr_xyrange_xt yrange;
+ tmedia_imageattr_srange_xt srange;
+ struct{
+ unsigned is_present:1;
+ spvalue_t start;
+ spvalue_t end;
+ }prange;
+ qvalue_t qvalue;
+}
+tmedia_imageattr_set_xt;
+
+typedef struct tmedia_imageattr_xs
+{
+ struct{
+ tmedia_imageattr_set_xt sets[TMEDIA_imageattr_ARRAY_MAX_SIZE + 1];
+ tsk_size_t count;
+ }send;
+ struct{
+ tmedia_imageattr_set_xt sets[TMEDIA_imageattr_ARRAY_MAX_SIZE + 1];
+ tsk_size_t count;
+ }recv;
+}
+tmedia_imageattr_xt;
+
+TINYMEDIA_API int tmedia_imageattr_parse(tmedia_imageattr_xt* self, const void* in_data, tsk_size_t in_size);
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_imageattr_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_jitterbuffer.h b/tinyMEDIA/include/tinymedia/tmedia_jitterbuffer.h
new file mode 100644
index 0000000..fb0f8ef
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_jitterbuffer.h
@@ -0,0 +1,102 @@
+/*
+* Copyright (C) 2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_jitterbuffer.h
+ * @brief Audio/Video JitterBuffer Plugin
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ */
+#ifndef TINYMEDIA_JITTER_BUFFER_H
+#define TINYMEDIA_JITTER_BUFFER_H
+
+#include "tinymedia_config.h"
+
+#include "tinymedia/tmedia_params.h"
+#include "tmedia_common.h"
+
+
+#include "tsk_object.h"
+
+TMEDIA_BEGIN_DECLS
+
+/** cast any pointer to @ref tmedia_jitterbuffer_t* object */
+#define TMEDIA_JITTER_BUFFER(self) ((tmedia_jitterbuffer_t*)(self))
+
+/**Max number of plugins (jb types) we can create */
+#if !defined(TMED_JITTER_BUFFER_MAX_PLUGINS)
+# define TMED_JITTER_BUFFER_MAX_PLUGINS 0x0F
+#endif
+
+/** Base object for all JitterBuffers */
+typedef struct tmedia_jitterbuffer_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_bool_t opened;
+
+ const struct tmedia_jitterbuffer_plugin_def_s* plugin;
+}
+tmedia_jitterbuffer_t;
+
+#define TMEDIA_DECLARE_JITTER_BUFFER tmedia_jitterbuffer_t __jitterbuffer__
+
+/** Virtual table used to define a consumer plugin */
+typedef struct tmedia_jitterbuffer_plugin_def_s
+{
+ //! object definition used to create an instance of the jitterbufferr
+ const tsk_object_def_t* objdef;
+
+ //! the type of the jitter buffer
+ tmedia_type_t type;
+
+ //! full description (usefull for debugging)
+ const char* desc;
+
+ int (*set) (tmedia_jitterbuffer_t* , const tmedia_param_t*);
+ int (* open) (tmedia_jitterbuffer_t*, uint32_t frame_duration, uint32_t rate, uint32_t channels);
+ int (* tick) (tmedia_jitterbuffer_t*);
+ int (* put) (tmedia_jitterbuffer_t*, void* data, tsk_size_t data_size, const tsk_object_t* proto_hdr);
+ tsk_size_t (* get) (tmedia_jitterbuffer_t*, void* out_data, tsk_size_t out_size);
+ int (* reset) (tmedia_jitterbuffer_t* );
+ int (* close) (tmedia_jitterbuffer_t* );
+}
+tmedia_jitterbuffer_plugin_def_t;
+
+TINYMEDIA_API int tmedia_jitterbuffer_init(tmedia_jitterbuffer_t* self);
+TINYMEDIA_API int tmedia_jitterbuffer_set(tmedia_jitterbuffer_t *self, const tmedia_param_t* param);
+TINYMEDIA_API int tmedia_jitterbuffer_open(tmedia_jitterbuffer_t* self, uint32_t frame_duration, uint32_t rate, uint32_t channels);
+TINYMEDIA_API int tmedia_jitterbuffer_tick(tmedia_jitterbuffer_t* self);
+TINYMEDIA_API int tmedia_jitterbuffer_put(tmedia_jitterbuffer_t* self, void* data, tsk_size_t data_size, const tsk_object_t* proto_hdr);
+TINYMEDIA_API tsk_size_t tmedia_jitterbuffer_get(tmedia_jitterbuffer_t* self, void* out_data, tsk_size_t out_size);
+TINYMEDIA_API int tmedia_jitterbuffer_reset(tmedia_jitterbuffer_t* self);
+TINYMEDIA_API int tmedia_jitterbuffer_close(tmedia_jitterbuffer_t* self);
+TINYMEDIA_API int tmedia_jitterbuffer_deinit(tmedia_jitterbuffer_t* self);
+
+TINYMEDIA_API int tmedia_jitterbuffer_plugin_register(const tmedia_jitterbuffer_plugin_def_t* plugin);
+TINYMEDIA_API int tmedia_jitterbuffer_plugin_unregister();
+TINYMEDIA_API int tmedia_jitter_buffer_plugin_unregister_by_type(tmedia_type_t type);
+TINYMEDIA_API tmedia_jitterbuffer_t* tmedia_jitterbuffer_create(tmedia_type_t type);
+
+TMEDIA_END_DECLS
+
+
+#endif /* TINYMEDIA_JITTER_BUFFER_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_params.h b/tinyMEDIA/include/tinymedia/tmedia_params.h
new file mode 100644
index 0000000..549552c
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_params.h
@@ -0,0 +1,119 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_params.h
+ * @brief Media parameters used to configure any session or plugin.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TINYMEDIA_PARAMS_H
+#define TINYMEDIA_PARAMS_H
+
+#include "tinymedia_config.h"
+
+#include "tinymedia/tmedia_common.h"
+
+#include "tsk_list.h"
+
+TMEDIA_BEGIN_DECLS
+
+#define TMEDIA_PARAM(self) ((tmedia_param_t*)(self))
+
+typedef enum tmedia_param_access_type_e
+{
+ tmedia_pat_get,
+ tmedia_pat_set
+}
+tmedia_param_access_type_t;
+
+typedef enum tmedia_param_plugin_type_e
+{
+ tmedia_ppt_consumer,
+ tmedia_ppt_producer,
+ tmedia_ppt_codec,
+ tmedia_ppt_session,
+ tmedia_ppt_manager
+}
+tmedia_param_plugin_type_t;
+
+typedef enum tmedia_param_value_type_e
+{
+ tmedia_pvt_int32,
+ tmedia_pvt_bool = tmedia_pvt_int32,
+ tmedia_pvt_pobject,
+ tmedia_pvt_pchar,
+ tmedia_pvt_int64,
+}
+tmedia_param_value_type_t;
+
+#define TMEDIA_PARAM_VALUE_TYPE_IS_PTR(self) ((self) == tmedia_pvt_pobject || (self) == tmedia_pvt_pchar)
+
+typedef struct tmedia_param_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tmedia_param_access_type_t access_type;
+ tmedia_type_t media_type;
+ tmedia_param_plugin_type_t plugin_type;
+ tmedia_param_value_type_t value_type;
+
+ char* key;
+ /* Because setting parameters could be deferred
+ * ==> MUST copy the value for later use.
+ * e.g. TMEDIA_SESSION_MANAGER_SET_INT32("width", 1234); 1234 will be lost when we exit the block code
+ */
+ void* value;
+}
+tmedia_param_t;
+
+typedef tsk_list_t tmedia_params_L_t; /**< List of @ref tsk_param_t elements. */
+
+#define tmedia_params_create() tsk_list_create()
+
+TINYMEDIA_API tmedia_param_t* tmedia_param_create(tmedia_param_access_type_t access_type,
+ tmedia_type_t media_type,
+ tmedia_param_plugin_type_t plugin_type,
+ tmedia_param_value_type_t value_type,
+ const char* key,
+ void* value);
+#define tmedia_param_create_get(media_type, plugin_type, value_type, key, value) tmedia_param_create(tmedia_pat_get, (media_type), (plugin_type), (value_type), (key), (value))
+#define tmedia_param_create_get_session(media_type, value_type, key, value) tmedia_param_create_get((media_type), tmedia_ppt_session, (value_type), (key), (value))
+#define tmedia_param_create_get_codec(media_type, value_type, key, value) tmedia_param_create_get((media_type), tmedia_ppt_codec, (value_type), (key), (value))
+#define tmedia_param_create_set(media_type, plugin_type, value_type, key, value) tmedia_param_create(tmedia_pat_set, (media_type), (plugin_type), (value_type), (value))
+
+TINYMEDIA_API tmedia_params_L_t* tmedia_params_create_2(va_list *app);
+
+TINYMEDIA_API int tmedia_params_add_param(tmedia_params_L_t **self,
+ tmedia_param_access_type_t access_type,
+ tmedia_type_t media_type,
+ tmedia_param_plugin_type_t plugin_type,
+ tmedia_param_value_type_t value_type,
+ const char* key,
+ void* value);
+
+TINYMEDIA_GEXTERN const tsk_object_def_t *tmedia_param_def_t;
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_PARAMS_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_producer.h b/tinyMEDIA/include/tinymedia/tmedia_producer.h
new file mode 100644
index 0000000..0817821
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_producer.h
@@ -0,0 +1,144 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_producer.h
+ * @brief Base producer object.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TINYMEDIA_PRODUCER_H
+#define TINYMEDIA_PRODUCER_H
+
+#include "tinymedia_config.h"
+
+#include "tinymedia/tmedia_codec.h"
+#include "tinymedia/tmedia_params.h"
+#include "tmedia_common.h"
+
+TMEDIA_BEGIN_DECLS
+
+#define TMEDIA_PRODUCER_BITS_PER_SAMPLE_DEFAULT 16
+#define TMEDIA_PRODUCER_CHANNELS_DEFAULT 2
+#define TMEDIA_PRODUCER_RATE_DEFAULT 8000
+
+/**Max number of plugins (producer types) we can create */
+#define TMED_PRODUCER_MAX_PLUGINS 0x0F
+
+/** cast any pointer to @ref tmedia_producer_t* object */
+#define TMEDIA_PRODUCER(self) ((tmedia_producer_t*)(self))
+
+typedef int (*tmedia_producer_enc_cb_f)(const void* callback_data, const void* buffer, tsk_size_t size);
+typedef int (*tmedia_producer_raw_cb_f)(const tmedia_video_encode_result_xt* chunck);
+
+/** Default Video chroma */
+#define TMEDIA_PRODUCER_CHROMA_DEFAULT tmedia_chroma_yuv420p
+
+/** Base object for all Producers */
+typedef struct tmedia_producer_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tmedia_type_t type;
+ const char* desc;
+
+ struct{
+ tmedia_chroma_t chroma;
+ int fps;
+ int rotation;
+ tsk_bool_t mirror;
+ tsk_size_t width;
+ tsk_size_t height;
+ } video;
+
+ struct{
+ uint8_t bits_per_sample;
+ uint8_t channels;
+ uint32_t rate;
+ uint8_t ptime;
+ uint8_t gain;
+ int32_t volume;
+ } audio;
+
+ const struct tmedia_producer_plugin_def_s* plugin;
+
+ tsk_bool_t is_prepared;
+ tsk_bool_t is_started;
+ uint64_t session_id;
+
+ struct{
+ enum tmedia_codec_id_e codec_id;
+ // other options to be added
+ } encoder;
+
+ struct{
+ tmedia_producer_enc_cb_f callback;
+ const void* callback_data;
+ } enc_cb;
+
+ struct{
+ tmedia_producer_raw_cb_f callback;
+ tmedia_video_encode_result_xt chunck_curr;
+ } raw_cb;
+}
+tmedia_producer_t;
+
+/** Virtual table used to define a producer plugin */
+typedef struct tmedia_producer_plugin_def_s
+{
+ //! object definition used to create an instance of the producer
+ const tsk_object_def_t* objdef;
+
+ //! the type of the producer
+ tmedia_type_t type;
+ //! full description (usefull for debugging)
+ const char* desc;
+
+ int (*set) (tmedia_producer_t* , const tmedia_param_t*);
+ int (* prepare) (tmedia_producer_t* , const tmedia_codec_t*);
+ int (* start) (tmedia_producer_t* );
+ int (* pause) (tmedia_producer_t* );
+ int (* stop) (tmedia_producer_t* );
+}
+tmedia_producer_plugin_def_t;
+
+#define TMEDIA_DECLARE_PRODUCER tmedia_producer_t __producer__
+
+TINYMEDIA_API tmedia_producer_t* tmedia_producer_create(tmedia_type_t type, uint64_t session_id);
+TINYMEDIA_API int tmedia_producer_init(tmedia_producer_t* self);
+TINYMEDIA_API int tmedia_producer_set_enc_callback(tmedia_producer_t *self, tmedia_producer_enc_cb_f callback, const void* callback_data);
+TINYMEDIA_API int tmedia_producer_set_raw_callback(tmedia_producer_t *self, tmedia_producer_raw_cb_f callback, const void* callback_data);
+TINYMEDIA_API int tmedia_producer_set(tmedia_producer_t* self, const tmedia_param_t* param);
+TINYMEDIA_API int tmedia_producer_prepare(tmedia_producer_t *self, const tmedia_codec_t* codec);
+TINYMEDIA_API int tmedia_producer_start(tmedia_producer_t *self);
+TINYMEDIA_API int tmedia_producer_pause(tmedia_producer_t *self);
+TINYMEDIA_API int tmedia_producer_stop(tmedia_producer_t *self);
+TINYMEDIA_API int tmedia_producer_deinit(tmedia_producer_t* self);
+
+TINYMEDIA_API int tmedia_producer_plugin_register(const tmedia_producer_plugin_def_t* plugin);
+TINYMEDIA_API int tmedia_producer_plugin_unregister(const tmedia_producer_plugin_def_t* plugin);
+TINYMEDIA_API int tmedia_producer_plugin_unregister_by_type(tmedia_type_t type);
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_PRODUCER_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_qos.h b/tinyMEDIA/include/tinymedia/tmedia_qos.h
new file mode 100644
index 0000000..7ff8e97
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_qos.h
@@ -0,0 +1,194 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_qos.h
+ * @brief RFC 3312 (Preconditions) implementation.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TINYMEDIA_QOS_H
+#define TINYMEDIA_QOS_H
+
+#include "tinymedia_config.h"
+
+#include "tinysdp/tsdp_message.h"
+
+#include "tsk_object.h"
+
+TMEDIA_BEGIN_DECLS
+
+#define TMEDIA_QOS_TLINE(self) ((tmedia_qos_tline_t*)(self))
+
+/** List of all supported statues*/
+typedef enum tmedia_qos_status_e
+{
+ //! current-status
+ tmedia_qos_status_curr,
+ //! desired-status
+ tmedia_qos_status_des,
+ //! confirm-status
+ tmedia_qos_status_conf
+}
+tmedia_qos_status_t;
+
+/** List of all supported precondition types */
+typedef enum tmedia_qos_ptype_e
+{
+ tmedia_qos_ptype_qos
+}
+tmedia_qos_ptype_t;
+
+/** List of all supported status types */
+typedef enum tmedia_qos_stype_e
+{
+ tmedia_qos_stype_none,/* not part of the RFC */
+
+ tmedia_qos_stype_segmented,
+ tmedia_qos_stype_e2e,
+}
+tmedia_qos_stype_t;
+
+/** strengths */
+typedef enum tmedia_qos_strength_e
+{
+ /* do no change the order (none -> optional -> manadatory) */
+ tmedia_qos_strength_none,
+ tmedia_qos_strength_failure,
+ tmedia_qos_strength_unknown,
+ tmedia_qos_strength_optional,
+ tmedia_qos_strength_mandatory
+}
+tmedia_qos_strength_t;
+
+/** directions */
+typedef enum tmedia_qos_direction_e
+{
+ tmedia_qos_direction_none = 0x01,
+ tmedia_qos_direction_send = (0x01 << 1),
+ tmedia_qos_direction_recv = (0x01 << 2),
+ tmedia_qos_direction_sendrecv = (tmedia_qos_direction_send | tmedia_qos_direction_recv)
+}
+tmedia_qos_direction_t;
+
+/* QoS table-line */
+typedef struct tmedia_qos_tline_s
+{
+ TSK_DECLARE_OBJECT;
+ tmedia_qos_stype_t type;
+}
+tmedia_qos_tline_t;
+#define TMEDIA_DECLARE_QOS_TLINE tmedia_qos_tline_t __tline__
+
+TINYMEDIA_API tmedia_qos_tline_t* tmedia_qos_tline_create(tmedia_qos_stype_t type, tmedia_qos_strength_t strength);
+TINYMEDIA_API tmedia_qos_stype_t tmedia_qos_get_type(const tsdp_header_M_t* m);
+TINYMEDIA_API tmedia_qos_tline_t* tmedia_qos_tline_from_sdp(const tsdp_header_M_t* m);
+TINYMEDIA_API int tmedia_qos_tline_to_sdp(const tmedia_qos_tline_t* self, tsdp_header_M_t* m);
+TINYMEDIA_API int tmedia_qos_tline_set_ro(tmedia_qos_tline_t* self, const tmedia_qos_tline_t* ro);
+TINYMEDIA_API tsk_bool_t tmedia_qos_tline_canresume(const tmedia_qos_tline_t* self);
+
+/* QoS table-line for E2E type*/
+typedef struct tmedia_qos_tline_e2e_s
+{
+ TMEDIA_DECLARE_QOS_TLINE;
+
+ /* RFC 3312 - 5.1 Generating an offer
+
+ Direction Current Desired Strength
+ ____________________________________
+ send no mandatory
+ recv no mandatory
+ */
+ struct{
+ unsigned current:1;
+ unsigned confirm:1;
+ tmedia_qos_strength_t strength;
+ } send;
+
+ struct{
+ unsigned current:1;
+ unsigned confirm:1;
+ tmedia_qos_strength_t strength;
+ } recv;
+}
+tmedia_qos_tline_e2e_t;
+
+TINYMEDIA_API tmedia_qos_tline_e2e_t* tmedia_qos_tline_e2e_create(tmedia_qos_strength_t strength);
+TINYMEDIA_API tmedia_qos_tline_e2e_t* tmedia_qos_tline_e2e_from_sdp(const tsdp_header_M_t* m);
+TINYMEDIA_API int tmedia_qos_tline_e2e_to_sdp(const tmedia_qos_tline_e2e_t* self, tsdp_header_M_t* m);
+TINYMEDIA_API int tmedia_qos_tline_e2e_set_ro(tmedia_qos_tline_e2e_t* self, const tmedia_qos_tline_e2e_t* ro);
+TINYMEDIA_API tsk_bool_t tmedia_qos_tline_e2e_canresume(const tmedia_qos_tline_e2e_t* self);
+
+/* QoS table-line for Segented type*/
+typedef struct tmedia_qos_tline_segmented_s
+{
+ TMEDIA_DECLARE_QOS_TLINE;
+
+ /* RFC 3312 - 5.1 Generating an offer
+ Direction Current Desired Strength
+ ______________________________________
+ local send no none
+ local recv no none
+ remote send no optional
+ remote recv no none
+ */
+ /* can be done in two lines but I prefer doing it like this (easier) */
+ struct{
+ unsigned current:1;
+ unsigned confirm:1;
+ tmedia_qos_strength_t strength;
+ } local_send;
+
+ struct{
+ unsigned current:1;
+ unsigned confirm:1;
+ tmedia_qos_strength_t strength;
+ } local_recv;
+
+ struct{
+ unsigned current:1;
+ unsigned confirm:1;
+ tmedia_qos_strength_t strength;
+ } remote_send;
+
+ struct{
+ unsigned current:1;
+ unsigned confirm:1;
+ tmedia_qos_strength_t strength;
+ } remote_recv;
+}
+tmedia_qos_tline_segmented_t;
+
+
+TINYMEDIA_API tmedia_qos_tline_segmented_t* tmedia_qos_tline_segmented_create(tmedia_qos_strength_t strength);
+TINYMEDIA_API tmedia_qos_tline_segmented_t* tmedia_qos_tline_segmented_from_sdp(const tsdp_header_M_t* m);
+TINYMEDIA_API int tmedia_qos_tline_segmented_to_sdp(const tmedia_qos_tline_segmented_t* self, tsdp_header_M_t* m);
+TINYMEDIA_API int tmedia_qos_tline_segmented_set_ro(tmedia_qos_tline_segmented_t* self, const tmedia_qos_tline_segmented_t* ro);
+TINYMEDIA_API tsk_bool_t tmedia_qos_tline_segmented_canresume(const tmedia_qos_tline_segmented_t* self);
+
+TINYMEDIA_GEXTERN const tsk_object_def_t *tmedia_qos_tline_segmented_def_t;
+TINYMEDIA_GEXTERN const tsk_object_def_t *tmedia_qos_tline_e2e_def_t;
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_QOS_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_resampler.h b/tinyMEDIA/include/tinymedia/tmedia_resampler.h
new file mode 100644
index 0000000..5093bc6
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_resampler.h
@@ -0,0 +1,86 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_resampler.h
+ * @brief Audio Resampler Plugin
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ */
+#ifndef TINYMEDIA_RESAMPLER_H
+#define TINYMEDIA_RESAMPLER_H
+
+#include "tinymedia_config.h"
+
+#include "tsk_object.h"
+
+#ifndef TMEDIA_RESAMPLER_QUALITY
+# define TMEDIA_RESAMPLER_QUALITY 5
+#endif
+
+TMEDIA_BEGIN_DECLS
+
+/** cast any pointer to @ref tmedia_resampler_t* object */
+#define TMEDIA_RESAMPLER(self) ((tmedia_resampler_t*)(self))
+
+/** Base object for all resamplers */
+typedef struct tmedia_resampler_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_bool_t opened;
+
+ const struct tmedia_resampler_plugin_def_s* plugin;
+}
+tmedia_resampler_t;
+
+#define TMEDIA_DECLARE_RESAMPLER tmedia_resampler_t __resampler__
+
+/** Virtual table used to define a consumer plugin */
+typedef struct tmedia_resampler_plugin_def_s
+{
+ //! object definition used to create an instance of the resamplerr
+ const tsk_object_def_t* objdef;
+
+ //! full description (usefull for debugging)
+ const char* desc;
+
+ // ! quality is from 0-10
+ int (* open) (tmedia_resampler_t* self, uint32_t in_freq, uint32_t out_freq, uint32_t frame_duration, uint32_t in_channels, uint32_t out_channels, uint32_t quality, uint32_t bits_per_sample);
+ tsk_size_t (* process) (tmedia_resampler_t*, const void* in_data, tsk_size_t in_size_in_sample, void* out_data, tsk_size_t out_size_in_sample);
+ int (* close) (tmedia_resampler_t* );
+}
+tmedia_resampler_plugin_def_t;
+
+TINYMEDIA_API int tmedia_resampler_init(tmedia_resampler_t* self);
+TINYMEDIA_API int tmedia_resampler_open(tmedia_resampler_t* self, uint32_t in_freq, uint32_t out_freq, uint32_t frame_duration, uint32_t in_channels, uint32_t out_channels, uint32_t quality, uint32_t bits_per_sample);
+TINYMEDIA_API tsk_size_t tmedia_resampler_process(tmedia_resampler_t* self, const void* in_data, tsk_size_t in_size_in_sample, void* out_data, tsk_size_t out_size_in_sample);
+TINYMEDIA_API int tmedia_resampler_close(tmedia_resampler_t* self);
+TINYMEDIA_API int tmedia_resampler_deinit(tmedia_resampler_t* self);
+
+TINYMEDIA_API int tmedia_resampler_plugin_register(const tmedia_resampler_plugin_def_t* plugin);
+TINYMEDIA_API int tmedia_resampler_plugin_unregister(const tmedia_resampler_plugin_def_t* plugin);
+TINYMEDIA_API tmedia_resampler_t* tmedia_resampler_create();
+
+TMEDIA_END_DECLS
+
+
+#endif /* TINYMEDIA_RESAMPLER_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_session.h b/tinyMEDIA/include/tinymedia/tmedia_session.h
new file mode 100644
index 0000000..743a7a5
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_session.h
@@ -0,0 +1,578 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_session.h
+ * @brief Base session object.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TINYMEDIA_SESSION_H
+#define TINYMEDIA_SESSION_H
+
+#include "tinymedia_config.h"
+
+#include "tinymedia/tmedia_codec.h"
+#include "tinymedia/tmedia_qos.h"
+#include "tinymedia/tmedia_params.h"
+
+#include "tinysdp/tsdp_message.h"
+
+#include "tnet_nat.h"
+#include "tnet_types.h"
+
+#include "tsk_list.h"
+#include "tsk_debug.h"
+#include "tsk_safeobj.h"
+
+TMEDIA_BEGIN_DECLS
+
+struct tmedia_session_s;
+
+// rfc5168 (XML Schema for Media Control) commands
+typedef enum tmedia_session_rfc5168_cmd_e
+{
+ tmedia_session_rfc5168_cmd_picture_fast_update,
+}
+tmedia_session_rfc5168_cmd_t;
+// BFCP (rfc4582) events
+typedef enum tmedia_session_bfcp_evt_type_e
+{
+ tmedia_session_bfcp_evt_type_err, // Global error
+ tmedia_session_bfcp_evt_type_flreq_status, // FloorRequestStatus
+}
+tmedia_session_bfcp_evt_type_t;
+
+typedef struct tmedia_session_bfcp_evt_xs {
+ tmedia_session_bfcp_evt_type_t type;
+ const char* reason;
+ union {
+ struct {
+ int code;
+ } err;
+ struct {
+ uint16_t status;
+ } flreq;
+ };
+} tmedia_session_bfcp_evt_xt;
+
+#define TMEDIA_SESSION(self) ((tmedia_session_t*)(self))
+#define TMEDIA_SESSION_AUDIO(self) ((tmedia_session_audio_t*)(self))
+#define TMEDIA_SESSION_VIDEO(self) ((tmedia_session_video_t*)(self))
+#define TMEDIA_SESSION_MSRP(self) ((tmedia_session_msrp_t*)(self))
+
+typedef int (*tmedia_session_t140_ondata_cb_f)(const void* usrdata, tmedia_t140_data_type_t data_type, const void* data_ptr, unsigned data_size);
+typedef int (*tmedia_session_rtcp_onevent_cb_f)(const void* usrdata, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media);
+typedef int (*tmedia_session_onerror_cb_f)(const void* usrdata, const struct tmedia_session_s* session, const char* reason, tsk_bool_t is_fatal);
+typedef int (*tmedia_session_rfc5168_cb_f)(const void* usrdata, const struct tmedia_session_s* session, const char* reason, enum tmedia_session_rfc5168_cmd_e command);
+typedef int (*tmedia_session_bfcp_cb_f)(const void* usrdata, const struct tmedia_session_s* session, const tmedia_session_bfcp_evt_xt* evt);
+
+/**Max number of plugins (session types) we can create */
+#define TMED_SESSION_MAX_PLUGINS 0x0F
+
+/** Base objct used for all media sessions */
+typedef struct tmedia_session_s
+{
+ TSK_DECLARE_OBJECT;
+
+ //! unique id. If you want to modifiy this field then you must use @ref tmedia_session_get_unique_id()
+ uint64_t id;
+ //! session type
+ tmedia_type_t type;
+ //! list of codec ids used as filter on the enabled codecs
+ tmedia_codec_id_t codecs_allowed;
+ //! list of codecs managed by this session (enabled)
+ tmedia_codecs_L_t* codecs;
+ //! negociated codec
+ tmedia_codecs_L_t* neg_codecs;
+ //! whether the ro have been prepared (up to the manager to update the value)
+ tsk_bool_t ro_changed;
+ //! whether the session have been initialized (up to the manager to update the value)
+ tsk_bool_t initialized;
+ //! whether the session have been prepared (up to the manager to update the value)
+ tsk_bool_t prepared;
+ //! whether the session is localy held
+ tsk_bool_t lo_held;
+ //! whether the session is remotely held
+ tsk_bool_t ro_held;
+ //! QoS
+ tmedia_qos_tline_t* qos;
+ //! bandwidth level
+ tmedia_bandwidth_level_t bl;
+ //! error callback function: not part of the plugin (likes .t140 or .rtcp) because it's not part of the API
+ struct{
+ tmedia_session_onerror_cb_f fun;
+ const void* usrdata;
+ } onerror_cb;
+ //! rfc5168 (XML Schema for Media Control) callback function: not part of the plugin (likes .t140 or .rtcp) because it's not part of the API.
+ struct {
+ tmedia_session_rfc5168_cb_f fun;
+ const void* usrdata;
+ } rfc5168_cb;
+ //! BFCP (rfc4582)
+ struct {
+ tmedia_session_bfcp_cb_f fun;
+ const void* usrdata;
+ } bfcp_cb;
+
+ tsk_bool_t bypass_encoding;
+ tsk_bool_t bypass_decoding;
+
+ struct{
+ char* file_ca;
+ char* file_pbk;
+ char* file_pvk;
+ tsk_bool_t verify;
+ } dtls;
+
+ struct{
+ tsdp_header_M_t* lo;
+ tsdp_header_M_t* ro;
+ } M;
+
+ //! plugin used to create the session
+ const struct tmedia_session_plugin_def_s* plugin;
+}
+tmedia_session_t;
+
+/** Virtual table used to define a session plugin */
+typedef struct tmedia_session_plugin_def_s
+{
+ //! object definition used to create an instance of the session
+ const tsk_object_def_t* objdef;
+
+ //! the type of the session
+ tmedia_type_t type;
+ //! the media name. e.g. "audio", "video", "message", "image" etc.
+ const char* media;
+
+ int (*set) (tmedia_session_t* , const tmedia_param_t*);
+ int (*get) (tmedia_session_t* , tmedia_param_t*);
+ int (* prepare) (tmedia_session_t* );
+ int (* start) (tmedia_session_t* );
+ int (* pause) (tmedia_session_t* );
+ int (* stop) (tmedia_session_t* );
+
+ struct{ /* Special case */
+ int (* send_dtmf) (tmedia_session_t*, uint8_t );
+ } audio;
+
+ const tsdp_header_M_t* (* get_local_offer) (tmedia_session_t* );
+ /* return zero if can handle the ro and non-zero otherwise */
+ int (* set_remote_offer) (tmedia_session_t* , const tsdp_header_M_t* );
+
+ struct{ /* Special case */
+ int (* set_ondata_cbfn) (tmedia_session_t*, const void* usrdata, tmedia_session_t140_ondata_cb_f func);
+ int (* send_data) (tmedia_session_t*, enum tmedia_t140_data_type_e data_type, const void* data_ptr, unsigned data_size);
+ } t140;
+
+ struct{ /* Handles both SIP INFO and RTCP-FB: should be called by end-user only when transcoding is disabled */
+ int (* set_onevent_cbfn) (tmedia_session_t*, const void* usrdata, tmedia_session_rtcp_onevent_cb_f func);
+ int (* send_event) (tmedia_session_t*, enum tmedia_rtcp_event_type_e event_type, uint32_t ssrc_media);
+ int (* recv_event) (tmedia_session_t*, enum tmedia_rtcp_event_type_e event_type, uint32_t ssrc_media);
+ } rtcp;
+}
+tmedia_session_plugin_def_t;
+
+TINYMEDIA_API uint64_t tmedia_session_get_unique_id();
+TINYMEDIA_API int tmedia_session_init(tmedia_session_t* self, tmedia_type_t type);
+TINYMEDIA_API int tmedia_session_set(tmedia_session_t* self, ...);
+TINYMEDIA_API tsk_bool_t tmedia_session_set_2(tmedia_session_t* self, const tmedia_param_t* param);
+TINYMEDIA_API int tmedia_session_get(tmedia_session_t* self, tmedia_param_t* param);
+TINYMEDIA_API int tmedia_session_cmp(const tsk_object_t* sess1, const tsk_object_t* sess2);
+TINYMEDIA_API int tmedia_session_plugin_register(const tmedia_session_plugin_def_t* plugin);
+TINYMEDIA_API const tmedia_session_plugin_def_t* tmedia_session_plugin_find_by_media(const char* media);
+TINYMEDIA_API int tmedia_session_plugin_unregister(const tmedia_session_plugin_def_t* plugin);
+TINYMEDIA_API tmedia_session_t* tmedia_session_create(tmedia_type_t type);
+TINYMEDIA_API tmedia_codecs_L_t* tmedia_session_match_codec(tmedia_session_t* self, const tsdp_header_M_t* M);
+TINYMEDIA_API int tmedia_session_set_onrtcp_cbfn(tmedia_session_t* self, const void* usrdata, tmedia_session_rtcp_onevent_cb_f fun);
+TINYMEDIA_API int tmedia_session_send_rtcp_event(tmedia_session_t* self, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media);
+TINYMEDIA_API int tmedia_session_recv_rtcp_event(tmedia_session_t* self, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media);
+TINYMEDIA_API int tmedia_session_set_onerror_cbfn(tmedia_session_t* self, const void* usrdata, tmedia_session_onerror_cb_f fun);
+TINYMEDIA_API int tmedia_session_set_rfc5168_cbfn(tmedia_session_t* self, const void* usrdata, tmedia_session_rfc5168_cb_f fun);
+TINYMEDIA_API int tmedia_session_set_bfcp_cbfn(tmedia_session_t* self, const void* usrdata, tmedia_session_bfcp_cb_f fun);
+TINYMEDIA_API int tmedia_session_deinit(tmedia_session_t* self);
+typedef tsk_list_t tmedia_sessions_L_t; /**< List of @ref tmedia_session_t objects */
+#define TMEDIA_DECLARE_SESSION tmedia_session_t __session__
+
+/** Audio Session */
+typedef struct tmedia_session_audio_s
+{
+ TMEDIA_DECLARE_SESSION;
+}
+tmedia_session_audio_t;
+#define tmedia_session_audio_init(self) tmedia_session_init(TMEDIA_SESSION(self), tmedia_audio)
+TINYMEDIA_API int tmedia_session_audio_send_dtmf(tmedia_session_audio_t* self, uint8_t event);
+#define tmedia_session_audio_deinit(self) tmedia_session_deinit(TMEDIA_SESSION(self))
+#define tmedia_session_audio_create() tmedia_session_create(tmedia_audio)
+#define TMEDIA_DECLARE_SESSION_AUDIO tmedia_session_audio_t __session_audio__
+
+/** Video Session */
+typedef struct tmedia_session_video_s
+{
+ TMEDIA_DECLARE_SESSION;
+}
+tmedia_session_video_t;
+#define tmedia_session_video_init(self) tmedia_session_init(TMEDIA_SESSION(self), tmedia_video)
+#define tmedia_session_video_deinit(self) tmedia_session_deinit(TMEDIA_SESSION(self))
+#define tmedia_session_video_create() tmedia_session_create(tmedia_video)
+#define TMEDIA_DECLARE_SESSION_VIDEO tmedia_session_video_t __session_video__
+
+/** MSRP Session */
+struct tmedia_session_msrp_s;
+struct tmsrp_event_s;
+// use "struct tmsrp_event_s" instead of "tmsrp_event_t" to avoid linking aginst tinyMSRP
+typedef int (*tmedia_session_msrp_cb_f)(const struct tmsrp_event_s* event);
+typedef struct tmedia_session_msrp_s
+{
+ TMEDIA_DECLARE_SESSION;
+
+ struct {
+ tmedia_session_msrp_cb_f func;
+ const void* data;
+ } callback;
+
+ int (* send_file) (struct tmedia_session_msrp_s*, const char* path, va_list *app);
+ int (* send_message) (struct tmedia_session_msrp_s*, const void* data, tsk_size_t size, const tmedia_params_L_t *params);
+}
+tmedia_session_msrp_t;
+#define tmedia_session_msrp_init(self) tmedia_session_init(TMEDIA_SESSION(self), tmedia_msrp)
+#define tmedia_session_msrp_deinit(self) tmedia_session_deinit(TMEDIA_SESSION(self))
+#define tmedia_session_msrp_create() tmedia_session_create(tmedia_msrp)
+#define TMEDIA_DECLARE_SESSION_MSRP tmedia_session_msrp_t __session_msrp__
+
+/** BFCP Session */
+struct tmedia_session_bfcp_s;
+struct tbfcp_event_s;
+typedef struct tmedia_session_bfcp_s
+{
+ TMEDIA_DECLARE_SESSION;
+
+ struct {
+ // use "struct tbfcp_event_s" instead of "tbfcp_event_t" to avoid linking aginst tinyBFCP
+ int (*fun)(const struct tbfcp_event_s* event);
+ const void* data;
+ } callback;
+
+ // int (* share_file) (struct tmedia_session_bfcp_s*, const char* path, va_list *app);
+ // int (* share_screen) (struct tmedia_session_bfcp_s*, const tmedia_params_L_t *params);
+}
+tmedia_session_bfcp_t;
+#define tmedia_session_bfcp_init(self) tmedia_session_init(TMEDIA_SESSION(self), tmedia_bfcp)
+#define tmedia_session_bfcp_deinit(self) tmedia_session_deinit(TMEDIA_SESSION(self))
+#define tmedia_session_bfcp_create() tmedia_session_create(tmedia_bfcp)
+#define TMEDIA_DECLARE_SESSION_BFCP tmedia_session_bfcp_t __session_bfcp__
+
+/** T.140 session */
+int tmedia_session_t140_set_ondata_cbfn(tmedia_session_t* self, const void* context, tmedia_session_t140_ondata_cb_f func);
+int tmedia_session_t140_send_data(tmedia_session_t* self, enum tmedia_t140_data_type_e data_type, const void* data_ptr, unsigned data_size);
+
+/** Session manager */
+typedef struct tmedia_session_mgr_s
+{
+ TSK_DECLARE_OBJECT;
+
+ //! whether we are the offerer or not
+ tsk_bool_t offerer;
+ //! local IP address or FQDN
+ char* addr;
+ //! public IP address or FQDN
+ char* public_addr;
+ //! whether the @a addr is IPv6 or not (useful when @addr is a FQDN)
+ tsk_bool_t ipv6;
+
+ struct{
+ uint32_t lo_ver;
+ tsdp_message_t* lo;
+
+ int32_t ro_ver;
+ tsdp_message_t* ro;
+ } sdp;
+
+ tsk_bool_t started;
+ tsk_bool_t ro_changed;
+ tsk_bool_t ro_provisional;
+ tsk_bool_t state_changed;
+ tsk_bool_t mediaType_changed;
+
+ //! session type
+ tmedia_type_t type;
+ //! QoS type
+ struct {
+ tmedia_qos_stype_t type;
+ tmedia_qos_strength_t strength;
+ } qos;
+
+ //! bandwidth level
+ tmedia_bandwidth_level_t bl;
+
+ /* NAT Traversal context */
+ struct tnet_nat_ctx_s* natt_ctx;
+ struct {
+ struct tnet_ice_ctx_s *ctx_audio;
+ struct tnet_ice_ctx_s *ctx_video;
+ struct tnet_ice_ctx_s *ctx_bfcpvid;
+ } ice;
+
+ /* session error callback */
+ struct{
+ tmedia_session_onerror_cb_f fun;
+ const void* usrdata;
+ } onerror_cb;
+
+ /* rfc5168 callback */
+ struct {
+ tmedia_session_rfc5168_cb_f fun;
+ const void* usrdata;
+ } rfc5168_cb;
+
+ //! List of all sessions
+ tmedia_sessions_L_t* sessions;
+
+ //! User's parameters used to confugure plugins
+ tmedia_params_L_t* params;
+
+ TSK_DECLARE_SAFEOBJ;
+}
+tmedia_session_mgr_t;
+
+typedef enum tmedia_session_param_type_e
+{
+ tmedia_sptype_null = 0,
+
+ tmedia_sptype_set,
+ tmedia_sptype_get
+}
+tmedia_session_param_type_t;
+
+#define TMEDIA_SESSION_SET_PARAM(MEDIA_TYPE_ENUM, PLUGIN_TYPE_ENUM, VALUE_TYPE_ENUM, KEY_STR, VALUE) \
+ tmedia_sptype_set, (tmedia_type_t)MEDIA_TYPE_ENUM, (tmedia_param_plugin_type_t)PLUGIN_TYPE_ENUM, (tmedia_param_value_type_t)VALUE_TYPE_ENUM, \
+ (const char*)KEY_STR, TMEDIA_PARAM_VALUE_TYPE_IS_PTR(VALUE_TYPE_ENUM) ? (void*)VALUE : (void*)&VALUE
+#define TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, PLUGIN_TYPE_ENUM, VALUE_TYPE_ENUM, KEY_STR, VALUE_PTR) \
+ tmedia_sptype_get, (tmedia_type_t)MEDIA_TYPE_ENUM, (tmedia_param_plugin_type_t)PLUGIN_TYPE_ENUM, (tmedia_param_value_type_t)VALUE_TYPE_ENUM, \
+ (const char*)KEY_STR, (void*)VALUE_PTR
+/* Manager */
+#define TMEDIA_SESSION_MANAGER_SET_INT32(KEY_STR, VALUE_INT32) TMEDIA_SESSION_SET_PARAM(tmedia_none, tmedia_ppt_manager, tmedia_pvt_int32, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_MANAGER_SET_POBJECT(KEY_STR, VALUE_PTR) TMEDIA_SESSION_SET_PARAM(tmedia_none, tmedia_ppt_manager, tmedia_pvt_pobject, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_MANAGER_SET_STR(KEY_STR, VALUE_STR) TMEDIA_SESSION_SET_PARAM(tmedia_none, tmedia_ppt_manager, tmedia_pvt_pchar, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_MANAGER_SET_INT64(KEY_STR, VALUE_INT64) TMEDIA_SESSION_SET_PARAM(tmedia_none, tmedia_ppt_manager, tmedia_pvt_int64, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_MANAGER_GET_INT32(KEY_STR, VALUE_PINT32) TMEDIA_SESSION_GET_PARAM(tmedia_none, tmedia_ppt_manager, tmedia_pvt_int32, KEY_STR, VALUE_PINT32)
+//#define TMEDIA_SESSION_MANAGER_GET_PVOID(KEY_STR, VALUE_PPTR) TMEDIA_SESSION_GET_PARAM(tmedia_none, tmedia_ppt_manager, tmedia_pvt_pobject, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_MANAGER_GET_STR(KEY_STR, VALUE_PSTR) TMEDIA_SESSION_GET_PARAM(tmedia_none, tmedia_ppt_manager, tmedia_pvt_pchar, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_MANAGER_GET_INT64(KEY_STR, VALUE_PINT64) TMEDIA_SESSION_GET_PARAM(tmedia_none, tmedia_ppt_manager, tmedia_pvt_int64, KEY_STR, VALUE_PINT64)
+/* ANY Session */
+#define TMEDIA_SESSION_SET_INT32(MEDIA_TYPE_ENUM, KEY_STR, VALUE_INT32) TMEDIA_SESSION_SET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_session, tmedia_pvt_int32, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_SET_POBJECT(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PTR) TMEDIA_SESSION_SET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_session, tmedia_pvt_pobject, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_SET_STR(MEDIA_TYPE_ENUM, KEY_STR, VALUE_STR) TMEDIA_SESSION_SET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_session, tmedia_pvt_pchar, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_SET_INT64(MEDIA_TYPE_ENUM, KEY_STR, VALUE_INT64) TMEDIA_SESSION_SET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_session, tmedia_pvt_int64, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_GET_INT32(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PINT32) TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_session, tmedia_pvt_int32, KEY_STR, VALUE_PINT32)
+#define TMEDIA_SESSION_GET_POBJECT(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PPOBJECT) TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_session, tmedia_pvt_pobject, KEY_STR, VALUE_PPOBJECT)
+//#define TMEDIA_SESSION_GET_PVOID(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PPTR) TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_session, tmedia_pvt_pobject, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_GET_STR(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PSTR) TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_session, tmedia_pvt_pchar, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_GET_INT64(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PINT64) TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_session, tmedia_pvt_int64, KEY_STR, VALUE_PINT64)
+/* AUDIO Session */
+#define TMEDIA_SESSION_AUDIO_SET_INT32(KEY_STR, VALUE_INT32) TMEDIA_SESSION_SET_INT32(tmedia_audio, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_AUDIO_SET_POBJECT(KEY_STR, VALUE_PTR) TMEDIA_SESSION_SET_POBJECT(tmedia_audio, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_AUDIO_SET_STR(KEY_STR, VALUE_STR) TMEDIA_SESSION_SET_STR(tmedia_audio, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_AUDIO_SET_INT64(KEY_STR, VALUE_INT64) TMEDIA_SESSION_SET_INT64(tmedia_audio, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_AUDIO_GET_INT32(KEY_STR, VALUE_PINT32) TMEDIA_SESSION_GET_INT32(tmedia_audio, KEY_STR, VALUE_PINT32)
+//#define TMEDIA_SESSION_AUDIO_GET_PVOID(KEY_STR, VALUE_PPTR) TMEDIA_SESSION_GET_PVOID(tmedia_audio, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_AUDIO_GET_STR(KEY_STR, VALUE_PSTR) TMEDIA_SESSION_GET_STR(tmedia_audio, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_AUDIO_GET_INT64(KEY_STR, VALUE_PINT64) TMEDIA_SESSION_GET_INT64(tmedia_audio, KEY_STR, VALUE_PINT64)
+/* VIDEO Session */
+#define TMEDIA_SESSION_VIDEO_SET_INT32(KEY_STR, VALUE_INT32) TMEDIA_SESSION_SET_INT32(tmedia_video, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_VIDEO_SET_POBJECT(KEY_STR, VALUE_PTR) TMEDIA_SESSION_SET_POBJECT(tmedia_video, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_VIDEO_SET_STR(KEY_STR, VALUE_STR) TMEDIA_SESSION_SET_STR(tmedia_video, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_VIDEO_SET_INT64(KEY_STR, VALUE_INT64) TMEDIA_SESSION_SET_INT64(tmedia_video, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_VIDEO_GET_INT32(KEY_STR, VALUE_PINT32) TMEDIA_SESSION_GET_INT32(tmedia_video, KEY_STR, VALUE_PINT32)
+//#define TMEDIA_SESSION_VIDEO_GET_PVOID(KEY_STR, VALUE_PPTR) TMEDIA_SESSION_GET_PVOID(tmedia_video, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_VIDEO_GET_STR(KEY_STR, VALUE_PSTR) TMEDIA_SESSION_GET_STR(tmedia_video, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_VIDEO_GET_INT64(KEY_STR, VALUE_PINT64) TMEDIA_SESSION_GET_INT64(tmedia_video, KEY_STR, VALUE_PINT64)
+/* MSRP Session */
+#define TMEDIA_SESSION_MSRP_SET_INT32(KEY_STR, VALUE_INT32) TMEDIA_SESSION_SET_INT32(tmedia_msrp, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_MSRP_SET_POBJECT(KEY_STR, VALUE_PTR) TMEDIA_SESSION_SET_POBJECT(tmedia_msrp, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_MSRP_SET_STR(KEY_STR, VALUE_STR) TMEDIA_SESSION_SET_STR(tmedia_msrp, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_MSRP_SET_INT64(KEY_STR, VALUE_INT64) TMEDIA_SESSION_SET_INT64(tmedia_msrp, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_MSRP_GET_INT32(KEY_STR, VALUE_PINT32) TMEDIA_SESSION_GET_INT32(tmedia_msrp, KEY_STR, VALUE_PINT32)
+//#define TMEDIA_SESSION_MSRP_GET_PVOID(KEY_STR, VALUE_PPTR) TMEDIA_SESSION_GET_PVOID(tmedia_msrp, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_MSRP_GET_STR(KEY_STR, VALUE_PSTR) TMEDIA_SESSION_GET_STR(tmedia_msrp, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_MSRP_GET_INT64(KEY_STR, VALUE_PINT64) TMEDIA_SESSION_GET_INT64(tmedia_msrp, KEY_STR, VALUE_PINT64)
+/* BFCP Session */
+#define TMEDIA_SESSION_BFCP_SET_INT32(KEY_STR, VALUE_INT32) TMEDIA_SESSION_SET_INT32(tmedia_bfcp, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_BFCP_SET_POBJECT(KEY_STR, VALUE_PTR) TMEDIA_SESSION_SET_POBJECT(tmedia_bfcp, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_BFCP_SET_STR(KEY_STR, VALUE_STR) TMEDIA_SESSION_SET_STR(tmedia_bfcp, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_BFCP_SET_INT64(KEY_STR, VALUE_INT64) TMEDIA_SESSION_SET_INT64(tmedia_bfcp, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_BFCP_GET_INT32(KEY_STR, VALUE_PINT32) TMEDIA_SESSION_GET_INT32(tmedia_bfcp, KEY_STR, VALUE_PINT32)
+//#define TMEDIA_SESSION_BFCP_GET_PVOID(KEY_STR, VALUE_PPTR) TMEDIA_SESSION_GET_PVOID(tmedia_bfcp, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_BFCP_GET_STR(KEY_STR, VALUE_PSTR) TMEDIA_SESSION_GET_STR(tmedia_bfcp, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_BFCP_GET_INT64(KEY_STR, VALUE_PINT64) TMEDIA_SESSION_GET_INT64(tmedia_bfcp, KEY_STR, VALUE_PINT64)
+/* ANY Consumer */
+#define TMEDIA_SESSION_CONSUMER_SET_INT32(MEDIA_TYPE_ENUM, KEY_STR, VALUE_INT32) TMEDIA_SESSION_SET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_consumer, tmedia_pvt_int32, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_CONSUMER_SET_POBJECT(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PTR) TMEDIA_SESSION_SET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_consumer, tmedia_pvt_pobject, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_CONSUMER_SET_STR(MEDIA_TYPE_ENUM, KEY_STR, VALUE_STR) TMEDIA_SESSION_SET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_consumer, tmedia_pvt_pchar, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_CONSUMER_SET_INT64(MEDIA_TYPE_ENUM, KEY_STR, VALUE_INT64) TMEDIA_SESSION_SET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_consumer, tmedia_pvt_int64, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_CONSUMER_GET_INT32(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PINT32) TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_consumer, tmedia_pvt_int32, KEY_STR, VALUE_PINT32)
+//#define TMEDIA_SESSION_CONSUMER_GET_PVOID(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PPTR) TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_consumer, tmedia_pvt_pobject, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_CONSUMER_GET_STR(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PSTR) TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_consumer, tmedia_pvt_pchar, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_CONSUMER_GET_INT64(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PINT64) TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_consumer, tmedia_pvt_int64, KEY_STR, VALUE_PINT64)
+/* AUDIO Consumer */
+#define TMEDIA_SESSION_AUDIO_CONSUMER_SET_INT32(KEY_STR, VALUE_INT32) TMEDIA_SESSION_CONSUMER_SET_INT32(tmedia_audio, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_AUDIO_CONSUMER_SET_POBJECT(KEY_STR, VALUE_PTR) TMEDIA_SESSION_CONSUMER_SET_POBJECT(tmedia_audio, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_AUDIO_CONSUMER_SET_STR(KEY_STR, VALUE_STR) TMEDIA_SESSION_CONSUMER_SET_STR(tmedia_audio, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_AUDIO_CONSUMER_SET_INT64(KEY_STR, VALUE_INT64) TMEDIA_SESSION_CONSUMER_SET_INT64(tmedia_audio, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_AUDIO_CONSUMER_GET_INT32(KEY_STR, VALUE_PINT32) TMEDIA_SESSION_CONSUMER_GET_INT32(tmedia_audio, KEY_STR, VALUE_PINT32)
+//#define TMEDIA_SESSION_AUDIO_CONSUMER_GET_PVOID(KEY_STR, VALUE_PPTR) TMEDIA_SESSION_CONSUMER_GET_PVOID(tmedia_audio, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_AUDIO_CONSUMER_GET_STR(KEY_STR, VALUE_PSTR) TMEDIA_SESSION_CONSUMER_GET_STR(tmedia_audio, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_AUDIO_CONSUMER_GET_INT64(KEY_STR, VALUE_PINT64) TMEDIA_SESSION_CONSUMER_GET_INT64(tmedia_audio, KEY_STR, VALUE_PINT64)
+/* VIDEO Consumer */
+#define TMEDIA_SESSION_VIDEO_CONSUMER_SET_INT32(KEY_STR, VALUE_INT32) TMEDIA_SESSION_CONSUMER_SET_INT32(tmedia_video, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_VIDEO_CONSUMER_SET_POBJECT(KEY_STR, VALUE_PTR) TMEDIA_SESSION_CONSUMER_SET_POBJECT(tmedia_video, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_VIDEO_CONSUMER_SET_STR(KEY_STR, VALUE_STR) TMEDIA_SESSION_CONSUMER_SET_STR(tmedia_video, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_VIDEO_CONSUMER_SET_INT64(KEY_STR, VALUE_INT64) TMEDIA_SESSION_CONSUMER_SET_INT64(tmedia_video, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_VIDEO_CONSUMER_GET_INT32(KEY_STR, VALUE_PINT32) TMEDIA_SESSION_CONSUMER_GET_INT32(tmedia_video, KEY_STR, VALUE_PINT32)
+//#define TMEDIA_SESSION_VIDEO_CONSUMER_GET_PVOID(KEY_STR, VALUE_PPTR) TMEDIA_SESSION_CONSUMER_GET_PVOID(tmedia_video, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_VIDEO_CONSUMER_GET_STR(KEY_STR, VALUE_PSTR) TMEDIA_SESSION_CONSUMER_GET_STR(tmedia_video, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_VIDEO_CONSUMER_GET_INT64(KEY_STR, VALUE_PINT64) TMEDIA_SESSION_CONSUMER_GET_INT64(tmedia_video, KEY_STR, VALUE_PINT64)
+/* MSRP Consumer */
+#define TMEDIA_SESSION_MSRP_CONSUMER_SET_INT32(KEY_STR, VALUE_INT32) TMEDIA_SESSION_CONSUMER_SET_INT32(tmedia_msrp, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_MSRP_CONSUMER_SET_POBJECT(KEY_STR, VALUE_PTR) TMEDIA_SESSION_CONSUMER_SET_POBJECT(tmedia_msrp, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_MSRP_CONSUMER_SET_STR(KEY_STR, VALUE_STR) TMEDIA_SESSION_CONSUMER_SET_STR(tmedia_msrp, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_MSRP_CONSUMER_SET_INT64(KEY_STR, VALUE_INT64) TMEDIA_SESSION_CONSUMER_SET_INT64(tmedia_msrp, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_MSRP_CONSUMER_GET_INT32(KEY_STR, VALUE_PINT32) TMEDIA_SESSION_CONSUMER_GET_INT32(tmedia_msrp, KEY_STR, VALUE_PINT32)
+//#define TMEDIA_SESSION_MSRP_CONSUMER_GET_PVOID(KEY_STR, VALUE_PPTR) TMEDIA_SESSION_CONSUMER_GET_PVOID(tmedia_msrp, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_MSRP_CONSUMER_GET_STR(KEY_STR, VALUE_PSTR) TMEDIA_SESSION_CONSUMER_GET_STR(tmedia_msrp, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_MSRP_CONSUMER_GET_INT64(KEY_STR, VALUE_PINT64) TMEDIA_SESSION_CONSUMER_GET_INT64(tmedia_msrp, KEY_STR, VALUE_PINT64)
+/* BFCP Consumer */
+#define TMEDIA_SESSION_BFCP_CONSUMER_SET_INT32(KEY_STR, VALUE_INT32) TMEDIA_SESSION_CONSUMER_SET_INT32(tmedia_bfcp, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_BFCP_CONSUMER_SET_POBJECT(KEY_STR, VALUE_PTR) TMEDIA_SESSION_CONSUMER_SET_POBJECT(tmedia_bfcp, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_BFCP_CONSUMER_SET_STR(KEY_STR, VALUE_STR) TMEDIA_SESSION_CONSUMER_SET_STR(tmedia_bfcp, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_BFCP_CONSUMER_SET_INT64(KEY_STR, VALUE_INT64) TMEDIA_SESSION_CONSUMER_SET_INT64(tmedia_bfcp, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_BFCP_CONSUMER_GET_INT32(KEY_STR, VALUE_PINT32) TMEDIA_SESSION_CONSUMER_GET_INT32(tmedia_bfcp, KEY_STR, VALUE_PINT32)
+//#define TMEDIA_SESSION_BFCP_CONSUMER_GET_PVOID(KEY_STR, VALUE_PPTR) TMEDIA_SESSION_CONSUMER_GET_PVOID(tmedia_bfcp, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_BFCP_CONSUMER_GET_STR(KEY_STR, VALUE_PSTR) TMEDIA_SESSION_CONSUMER_GET_STR(tmedia_bfcp, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_BFCP_CONSUMER_GET_INT64(KEY_STR, VALUE_PINT64) TMEDIA_SESSION_CONSUMER_GET_INT64(tmedia_bfcp, KEY_STR, VALUE_PINT64)
+
+/* ANY Producer */
+#define TMEDIA_SESSION_PRODUCER_SET_INT32(MEDIA_TYPE_ENUM, KEY_STR, VALUE_INT32) TMEDIA_SESSION_SET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_producer, tmedia_pvt_int32, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_PRODUCER_SET_POBJECT(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PTR) TMEDIA_SESSION_SET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_producer, tmedia_pvt_pobject, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_PRODUCER_SET_STR(MEDIA_TYPE_ENUM, KEY_STR, VALUE_STR) TMEDIA_SESSION_SET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_producer, tmedia_pvt_pchar, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_PRODUCER_SET_INT64(MEDIA_TYPE_ENUM, KEY_STR, VALUE_INT64) TMEDIA_SESSION_SET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_producer, tmedia_pvt_int64, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_PRODUCER_GET_INT32(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PINT32) TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_producer, tmedia_pvt_int32, KEY_STR, VALUE_PINT32)
+#define TMEDIA_SESSION_PRODUCER_GET_POBJECT(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PTR) TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_producer, tmedia_pvt_pobject, KEY_STR, VALUE_PTR)
+//#define TMEDIA_SESSION_PRODUCER_GET_PVOID(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PPTR) TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_producer, tmedia_pvt_pobject, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_PRODUCER_GET_STR(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PSTR) TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_producer, tmedia_pvt_pchar, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_PRODUCER_GET_INT64(MEDIA_TYPE_ENUM, KEY_STR, VALUE_PINT64) TMEDIA_SESSION_GET_PARAM(MEDIA_TYPE_ENUM, tmedia_ppt_producer, tmedia_pvt_int64, KEY_STR, VALUE_PINT64)
+/* AUDIO Producer */
+#define TMEDIA_SESSION_AUDIO_PRODUCER_SET_INT32(KEY_STR, VALUE_INT32) TMEDIA_SESSION_PRODUCER_SET_INT32(tmedia_audio, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_AUDIO_PRODUCER_SET_POBJECT(KEY_STR, VALUE_PTR) TMEDIA_SESSION_PRODUCER_SET_POBJECT(tmedia_audio, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_AUDIO_PRODUCER_SET_STR(KEY_STR, VALUE_STR) TMEDIA_SESSION_AUDIO_PRODUCER_SET_STR(tmedia_audio, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_AUDIO_PRODUCER_SET_INT64(KEY_STR, VALUE_INT64) TMEDIA_SESSION_PRODUCER_SET_INT64(tmedia_audio, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_AUDIO_PRODUCER_GET_INT32(KEY_STR, VALUE_PINT32) TMEDIA_SESSION_PRODUCER_GET_INT32(tmedia_audio, KEY_STR, VALUE_PINT32)
+//#define TMEDIA_SESSION_AUDIO_PRODUCER_GET_PVOID(KEY_STR, VALUE_PPTR) TMEDIA_SESSION_PRODUCER_GET_PVOID(tmedia_audio, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_AUDIO_PRODUCER_GET_STR(KEY_STR, VALUE_PSTR) TMEDIA_SESSION_AUDIO_PRODUCER_GET_STR(tmedia_audio, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_AUDIO_PRODUCER_GET_INT64(KEY_STR, VALUE_PINT64) TMEDIA_SESSION_PRODUCER_GET_INT64(tmedia_audio, KEY_STR, VALUE_PINT64)
+/* Video Producer */
+#define TMEDIA_SESSION_VIDEO_PRODUCER_SET_INT32(KEY_STR, VALUE_INT32) TMEDIA_SESSION_PRODUCER_SET_INT32(tmedia_video, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_VIDEO_PRODUCER_SET_POBJECT(KEY_STR, VALUE_PTR) TMEDIA_SESSION_PRODUCER_SET_POBJECT(tmedia_video, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_VIDEO_PRODUCER_SET_STR(KEY_STR, VALUE_STR) TMEDIA_SESSION_AUDIO_PRODUCER_SET_STR(tmedia_video, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_VIDEO_PRODUCER_SET_INT64(KEY_STR, VALUE_INT64) TMEDIA_SESSION_PRODUCER_SET_INT64(tmedia_video, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_VIDEO_PRODUCER_GET_INT32(KEY_STR, VALUE_PINT32) TMEDIA_SESSION_PRODUCER_GET_INT32(tmedia_video, KEY_STR, VALUE_PINT32)
+//#define TMEDIA_SESSION_VIDEO_PRODUCER_GET_PVOID(KEY_STR, VALUE_PPTR) TMEDIA_SESSION_PRODUCER_GET_PVOID(tmedia_video, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_VIDEO_PRODUCER_GET_STR(KEY_STR, VALUE_PSTR) TMEDIA_SESSION_AUDIO_PRODUCER_GET_STR(tmedia_video, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_VIDEO_PRODUCER_GET_INT64(KEY_STR, VALUE_PINT64) TMEDIA_SESSION_PRODUCER_GET_INT64(tmedia_video, KEY_STR, VALUE_PINT64)
+/* MSRP Producer */
+#define TMEDIA_SESSION_MSRP_PRODUCER_SET_INT32(KEY_STR, VALUE_INT32) TMEDIA_SESSION_PRODUCER_SET_INT32(tmedia_msrp, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_MSRP_PRODUCER_SET_POBJECT(KEY_STR, VALUE_PTR) TMEDIA_SESSION_PRODUCER_SET_POBJECT(tmedia_msrp, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_MSRP_PRODUCER_SET_STR(KEY_STR, VALUE_STR) TMEDIA_SESSION_AUDIO_PRODUCER_SET_STR(tmedia_msrp, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_MSRP_PRODUCER_SET_INT64(KEY_STR, VALUE_INT64) TMEDIA_SESSION_PRODUCER_SET_INT64(tmedia_msrp, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_MSRP_PRODUCER_GET_INT32(KEY_STR, VALUE_PINT32) TMEDIA_SESSION_PRODUCER_GET_INT32(tmedia_msrp, KEY_STR, VALUE_PINT32)
+//#define TMEDIA_SESSION_MSRP_PRODUCER_GET_PVOID(KEY_STR, VALUE_PPTR) TMEDIA_SESSION_PRODUCER_GET_PVOID(tmedia_msrp, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_MSRP_PRODUCER_GET_STR(KEY_STR, VALUE_PSTR) TMEDIA_SESSION_AUDIO_PRODUCER_GET_STR(tmedia_msrp, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_MSRP_PRODUCER_GET_INT64(KEY_STR, VALUE_PINT64) TMEDIA_SESSION_PRODUCER_GET_INT64(tmedia_msrp, KEY_STR, VALUE_PINT64)
+/* BFCP Producer */
+#define TMEDIA_SESSION_BFCP_PRODUCER_SET_INT32(KEY_STR, VALUE_INT32) TMEDIA_SESSION_PRODUCER_SET_INT32(tmedia_bfcp, KEY_STR, VALUE_INT32)
+#define TMEDIA_SESSION_BFCP_PRODUCER_SET_POBJECT(KEY_STR, VALUE_PTR) TMEDIA_SESSION_PRODUCER_SET_POBJECT(tmedia_bfcp, KEY_STR, VALUE_PTR)
+#define TMEDIA_SESSION_BFCP_PRODUCER_SET_STR(KEY_STR, VALUE_STR) TMEDIA_SESSION_AUDIO_PRODUCER_SET_STR(tmedia_bfcp, KEY_STR, VALUE_STR)
+#define TMEDIA_SESSION_BFCP_PRODUCER_SET_INT64(KEY_STR, VALUE_INT64) TMEDIA_SESSION_PRODUCER_SET_INT64(tmedia_bfcp, KEY_STR, VALUE_INT64)
+#define TMEDIA_SESSION_BFCP_PRODUCER_GET_INT32(KEY_STR, VALUE_PINT32) TMEDIA_SESSION_PRODUCER_GET_INT32(tmedia_bfcp, KEY_STR, VALUE_PINT32)
+//#define TMEDIA_SESSION_MSRP_PRODUCER_GET_PVOID(KEY_STR, VALUE_PPTR) TMEDIA_SESSION_PRODUCER_GET_PVOID(tmedia_bfcp, KEY_STR, VALUE_PPTR)
+//#define TMEDIA_SESSION_MSRP_PRODUCER_GET_STR(KEY_STR, VALUE_PSTR) TMEDIA_SESSION_AUDIO_PRODUCER_GET_STR(tmedia_bfcp, KEY_STR, VALUE_PSTR)
+//#define TMEDIA_SESSION_MSRP_PRODUCER_GET_INT64(KEY_STR, VALUE_PINT64) TMEDIA_SESSION_PRODUCER_GET_INT64(tmedia_bfcp, KEY_STR, VALUE_PINT64)
+
+
+#define TMEDIA_SESSION_SET_NULL() tmedia_sptype_null
+#define TMEDIA_SESSION_GET_NULL() tmedia_sptype_null
+
+//#define TMEDIA_SESSION_SET_REMOTE_IP(IP_STR) tmedia_sptype_remote_ip, (const char*) IP_STR
+//#define TMEDIA_SESSION_SET_LOCAL_IP(IP_STR, IPv6_BOOL) tmedia_sptype_local_ip, (const char*) IP_STR, (tsk_bool_t)IPv6_BOOL
+//#define TMEDIA_SESSION_SET_RTCP(ENABLED_BOOL) tmedia_sptype_set_rtcp, (tsk_bool_t)ENABLED_BOOL
+//#define TMEDIA_SESSION_SET_QOS(TYPE_ENUM, STRENGTH_ENUM) tmedia_sptype_qos, (tmedia_qos_stype_t)TYPE_ENUM, (tmedia_qos_strength_t)STRENGTH_ENUM
+
+
+TINYMEDIA_API tmedia_session_mgr_t* tmedia_session_mgr_create(tmedia_type_t type, const char* addr, tsk_bool_t ipv6, tsk_bool_t offerer);
+TINYMEDIA_API int tmedia_session_mgr_set_media_type(tmedia_session_mgr_t* self, tmedia_type_t type);
+TINYMEDIA_API int tmedia_session_mgr_set_media_type_2(tmedia_session_mgr_t* self, tmedia_type_t type, tsk_bool_t force);
+TINYMEDIA_API int tmedia_session_mgr_set_codecs_supported(tmedia_session_mgr_t* self, tmedia_codec_id_t codecs_supported);
+TINYMEDIA_API tmedia_session_t* tmedia_session_mgr_find(tmedia_session_mgr_t* self, tmedia_type_t type);
+TINYMEDIA_API int tmedia_session_mgr_set_natt_ctx(tmedia_session_mgr_t* self, struct tnet_nat_ctx_s* natt_ctx, const char* public_addr);
+TINYMEDIA_API int tmedia_session_mgr_set_ice_ctx(tmedia_session_mgr_t* self, struct tnet_ice_ctx_s* ctx_audio, struct tnet_ice_ctx_s* ctx_video);
+TINYMEDIA_API int tmedia_session_mgr_set_ice_ctx_2(tmedia_session_mgr_t* self, tmedia_type_t type, struct tnet_ice_ctx_s* ctx);
+TINYMEDIA_API int tmedia_session_mgr_start(tmedia_session_mgr_t* self);
+TINYMEDIA_API int tmedia_session_mgr_set(tmedia_session_mgr_t* self, ...);
+TINYMEDIA_API int tmedia_session_mgr_set_2(tmedia_session_mgr_t* self, va_list *app);
+TINYMEDIA_API int tmedia_session_mgr_set_3(tmedia_session_mgr_t* self, const tmedia_params_L_t* params);
+TINYMEDIA_API int tmedia_session_mgr_get(tmedia_session_mgr_t* self, ...);
+TINYMEDIA_API int tmedia_session_mgr_stop(tmedia_session_mgr_t* self);
+TINYMEDIA_API const tsdp_message_t* tmedia_session_mgr_get_lo(tmedia_session_mgr_t* self);
+TINYMEDIA_API int tmedia_session_mgr_set_ro(tmedia_session_mgr_t* self, const tsdp_message_t* sdp, tmedia_ro_type_t ro_type);
+TINYMEDIA_API const tsdp_message_t* tmedia_session_mgr_get_ro(tmedia_session_mgr_t* self);
+TINYMEDIA_API tsk_bool_t tmedia_session_mgr_is_new_ro(tmedia_session_mgr_t* self, const tsdp_message_t* sdp);
+TINYMEDIA_API int tmedia_session_mgr_hold(tmedia_session_mgr_t* self, tmedia_type_t type);
+TINYMEDIA_API tsk_bool_t tmedia_session_mgr_is_held(tmedia_session_mgr_t* self, tmedia_type_t type, tsk_bool_t local);
+TINYMEDIA_API int tmedia_session_mgr_resume(tmedia_session_mgr_t* self, tmedia_type_t type, tsk_bool_t local);
+TINYMEDIA_API int tmedia_session_mgr_add_media(tmedia_session_mgr_t* self, tmedia_type_t type);
+TINYMEDIA_API int tmedia_session_mgr_remove_media(tmedia_session_mgr_t* self, tmedia_type_t type);
+TINYMEDIA_API int tmedia_session_mgr_set_qos(tmedia_session_mgr_t* self, tmedia_qos_stype_t qos_type, tmedia_qos_strength_t qos_strength);
+TINYMEDIA_API tsk_bool_t tmedia_session_mgr_canresume(tmedia_session_mgr_t* self);
+TINYMEDIA_API tsk_bool_t tmedia_session_mgr_has_active_session(tmedia_session_mgr_t* self);
+TINYMEDIA_API int tmedia_session_mgr_send_dtmf(tmedia_session_mgr_t* self, uint8_t event);
+TINYMEDIA_API int tmedia_session_mgr_set_t140_ondata_cbfn(tmedia_session_mgr_t* self, const void* context, tmedia_session_t140_ondata_cb_f fun);
+TINYMEDIA_API int tmedia_session_mgr_send_t140_data(tmedia_session_mgr_t* self, enum tmedia_t140_data_type_e data_type, const void* data_ptr, unsigned data_size);
+TINYMEDIA_API int tmedia_session_mgr_set_onrtcp_cbfn(tmedia_session_mgr_t* self, tmedia_type_t media_type, const void* context, tmedia_session_rtcp_onevent_cb_f fun);
+TINYMEDIA_API int tmedia_session_mgr_send_rtcp_event(tmedia_session_mgr_t* self, tmedia_type_t media_type, enum tmedia_rtcp_event_type_e event_type, uint32_t ssrc_media);
+TINYMEDIA_API int tmedia_session_mgr_recv_rtcp_event(tmedia_session_mgr_t* self, tmedia_type_t media_type, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media);
+TINYMEDIA_API int tmedia_session_mgr_recv_rtcp_event_2(tmedia_session_mgr_t* self, tmedia_rtcp_event_type_t event_type, uint64_t session_id);
+TINYMEDIA_API int tmedia_session_mgr_send_file(tmedia_session_mgr_t* self, const char* path, ...);
+TINYMEDIA_API int tmedia_session_mgr_send_message(tmedia_session_mgr_t* self, const void* data, tsk_size_t size, const tmedia_params_L_t *params);
+TINYMEDIA_API int tmedia_session_mgr_set_msrp_cb(tmedia_session_mgr_t* self, const void* usrdata, tmedia_session_msrp_cb_f func);
+TINYMEDIA_API int tmedia_session_mgr_set_onerror_cbfn(tmedia_session_mgr_t* self, const void* usrdata, tmedia_session_onerror_cb_f fun);
+TINYMEDIA_API int tmedia_session_mgr_set_rfc5168_cbfn(tmedia_session_mgr_t* self, const void* usrdata, tmedia_session_rfc5168_cb_f fun);
+TINYMEDIA_API int tmedia_session_mgr_set_bfcp_cbfn(tmedia_session_mgr_t* self, const void* usrdata, tmedia_session_bfcp_cb_f fun);
+TINYMEDIA_API int tmedia_session_mgr_lo_apply_changes(tmedia_session_mgr_t* self);
+
+
+TINYMEDIA_GEXTERN const tsk_object_def_t *tmedia_session_mgr_def_t;
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_SESSION_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_session_dummy.h b/tinyMEDIA/include/tinymedia/tmedia_session_dummy.h
new file mode 100644
index 0000000..a795677
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_session_dummy.h
@@ -0,0 +1,76 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_session_dummy.h
+ * @brief Dummy sessions used for test only.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TINYMEDIA_SESSION_DUMMY_H
+#define TINYMEDIA_SESSION_DUMMY_H
+
+#include "tinymedia_config.h"
+
+#include "tmedia_session.h"
+
+#include "tsk_object.h"
+
+TMEDIA_BEGIN_DECLS
+
+/** Dummy Audio session */
+typedef struct tmedia_session_daudio_s
+{
+ TMEDIA_DECLARE_SESSION_AUDIO;
+ uint16_t local_port;
+ uint16_t remote_port;
+}
+tmedia_session_daudio_t;
+
+/** Dummy Video session */
+typedef struct tmedia_session_dvideo_s
+{
+ TMEDIA_DECLARE_SESSION_VIDEO;
+ uint16_t local_port;
+ uint16_t remote_port;
+}
+tmedia_session_dvideo_t;
+
+/** Dummy Msrp session */
+typedef struct tmedia_session_dmsrp_s
+{
+ TMEDIA_DECLARE_SESSION_MSRP;
+ uint16_t local_port;
+ uint16_t remote_port;
+}
+tmedia_session_dmsrp_t;
+
+
+TINYMEDIA_GEXTERN const tmedia_session_plugin_def_t *tmedia_session_daudio_plugin_def_t;
+TINYMEDIA_GEXTERN const tmedia_session_plugin_def_t *tmedia_session_dvideo_plugin_def_t;
+TINYMEDIA_GEXTERN const tmedia_session_plugin_def_t *tmedia_session_dmsrp_plugin_def_t;
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_SESSION_DUMMY_H */
+
diff --git a/tinyMEDIA/include/tinymedia/tmedia_session_ghost.h b/tinyMEDIA/include/tinymedia/tmedia_session_ghost.h
new file mode 100644
index 0000000..e4b0ac8
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_session_ghost.h
@@ -0,0 +1,55 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_session_ghost.h
+ * @brief Ghost session.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#ifndef TINYMEDIA_SESSION_GHOST_H
+#define TINYMEDIA_SESSION_GHOST_H
+
+#include "tinymedia_config.h"
+
+#include "tmedia_session.h"
+
+#include "tsk_object.h"
+
+TMEDIA_BEGIN_DECLS
+
+/** Ghost session */
+typedef struct tmedia_session_ghost_s
+{
+ TMEDIA_DECLARE_SESSION;
+ char* media;
+ char* proto;
+ char* first_format;
+}
+tmedia_session_ghost_t;
+
+TINYMEDIA_GEXTERN const tmedia_session_plugin_def_t *tmedia_session_ghost_plugin_def_t;
+
+TMEDIA_END_DECLS
+
+#endif /* TINYMEDIA_SESSION_GHOST_H */
diff --git a/tinyMEDIA/include/tinymedia/tmedia_vad.h b/tinyMEDIA/include/tinymedia/tmedia_vad.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia/tmedia_vad.h
diff --git a/tinyMEDIA/include/tinymedia_config.h b/tinyMEDIA/include/tinymedia_config.h
new file mode 100644
index 0000000..7416017
--- /dev/null
+++ b/tinyMEDIA/include/tinymedia_config.h
@@ -0,0 +1,98 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 TINYMEDIA_CONFIG_H
+#define TINYMEDIA_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 TMEDIA_UNDER_WINDOWS 1
+# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP)
+# define TMEDIA_UNDER_WINDOWS_RT 1
+# endif
+#endif
+
+// OS X or iOS
+#if defined(__APPLE__)
+# define TMEDIA_UNDER_APPLE 1
+# include <TargetConditionals.h>
+# include <Availability.h>
+#endif
+#if TARGET_OS_MAC
+# define TMEDIA_UNDER_MAC 1
+#endif
+#if TARGET_OS_IPHONE
+# define TMEDIA_UNDER_IPHONE 1
+#endif
+#if TARGET_IPHONE_SIMULATOR
+# define TMEDIA_UNDER_IPHONE_SIMULATOR 1
+#endif
+
+#if (TMEDIA_UNDER_WINDOWS || defined(__SYMBIAN32__)) && defined(TINYMEDIA_EXPORTS)
+# define TINYMEDIA_API __declspec(dllexport)
+# define TINYMEDIA_GEXTERN extern __declspec(dllexport)
+#elif (TMEDIA_UNDER_WINDOWS || defined(__SYMBIAN32__)) && !defined(TINYMEDIA_IMPORTS_IGNORE)
+# define TINYMEDIA_API __declspec(dllimport)
+# define TINYMEDIA_GEXTERN __declspec(dllimport)
+#else
+# define TINYMEDIA_API
+# define TINYMEDIA_GEXTERN extern
+#endif
+
+/* Guards against C++ name mangling
+*/
+#ifdef __cplusplus
+# define TMEDIA_BEGIN_DECLS extern "C" {
+# define TMEDIA_END_DECLS }
+#else
+# define TMEDIA_BEGIN_DECLS
+# define TMEDIA_END_DECLS
+#endif
+
+/* Disable some well-known warnings
+*/
+#ifdef _MSC_VER
+# if !defined(_CRT_SECURE_NO_WARNINGS)
+# define _CRT_SECURE_NO_WARNINGS
+# endif /* _CRT_SECURE_NO_WARNINGS */
+#endif
+
+/* Detecting C99 compilers
+ */
+#if (__STDC_VERSION__ == 199901L) && !defined(__C99__)
+# define __C99__
+#endif
+
+#include <stdint.h>
+#ifdef __SYMBIAN32__
+#include <stdlib.h>
+#endif
+
+#if HAVE_CONFIG_H
+ #include <config.h>
+#endif
+
+#endif // TINYMEDIA_CONFIG_H
diff --git a/tinyMEDIA/ragel.sh b/tinyMEDIA/ragel.sh
new file mode 100644
index 0000000..f376146
--- /dev/null
+++ b/tinyMEDIA/ragel.sh
@@ -0,0 +1,11 @@
+# Ragel generator
+# For more information about Ragel: http://www.complang.org/ragel/
+
+export OPTIONS="-C -L -T0"
+#export OPTIONS="-C -L -G2"
+
+# SDP Message parser
+ragel.exe $OPTIONS -o ./src/content/tmedia_content_cpim.c ./ragel/tmedia_content_cpim.rl
+
+# 'image-attr' (RFC 6236)
+ragel.exe $OPTIONS -o ./src/tmedia_imageattr.c ./ragel/tmedia_imageattr.rl \ No newline at end of file
diff --git a/tinyMEDIA/ragel/tmedia_content_cpim.rl b/tinyMEDIA/ragel/tmedia_content_cpim.rl
new file mode 100644
index 0000000..eeecbd3
--- /dev/null
+++ b/tinyMEDIA/ragel/tmedia_content_cpim.rl
@@ -0,0 +1,244 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tmedia_content_cpim.c
+ * @brief Common Presence and Instant Messaging (CPIM): Message Format (RFC 3862)
+ */
+#include "tinymedia/content/tmedia_content_cpim.h"
+
+#include "tsk_debug.h"
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_ragel_state.h"
+
+#include <string.h>
+
+/* RFC 3862 - 2. Overall Message Structure
+A complete message looks something like this:
+
+ m: Content-type: Message/CPIM
+ s:
+ h: (message-metadata-headers)
+ s:
+ e: (encapsulated MIME message-body)
+
+ The end of the message body is defined by the framing mechanism of
+ the protocol used. The tags 'm:', 's:', 'h:', 'e:', and 'x:' are not
+ part of the message format and are used here to indicate the
+ different parts of the message, thus:
+
+ m: MIME headers for the overall message
+ s: a blank separator line
+ h: message headers
+ e: encapsulated MIME object containing the message content
+ x: MIME security multipart message wrapper
+*/
+
+
+
+
+
+/***********************************
+* Ragel state machine.
+*/
+%%{
+ machine tmedia_machine_content_cpim;
+
+ # Includes
+ include tmedia_machine_utils "./ragel/tmedia_machine_utils.rl";
+
+ action tag{
+ tag_start = p;
+ }
+
+ action is_parsing_mime_headers{
+ parsing_mime_headers = tsk_true;
+ }
+
+ action is_parsing_message_headers{
+ parsing_mime_headers = tsk_false;
+ }
+
+ action parse_hname{
+ TSK_PARSER_SET_STRING(hname);
+ }
+
+ action parse_hvalue{
+ tmedia_content_header_t* header;
+ TSK_PARSER_SET_STRING(hvalue);
+ header = tmedia_content_header_create(hname, hvalue);
+ TSK_FREE(hname); TSK_FREE(hvalue);
+
+ if(parsing_mime_headers){
+ if(!TMEDIA_CONTENT_CPIM(self)->m_headers){
+ TMEDIA_CONTENT_CPIM(self)->m_headers = tsk_list_create();
+ }
+ tsk_list_push_back_data(TMEDIA_CONTENT_CPIM(self)->m_headers, (void**)&header);
+ }
+ else{
+ if(!TMEDIA_CONTENT_CPIM(self)->h_headers){
+ TMEDIA_CONTENT_CPIM(self)->h_headers = tsk_list_create();
+ }
+ tsk_list_push_back_data(TMEDIA_CONTENT_CPIM(self)->h_headers, (void**)&header);
+ }
+ }
+
+ action parse_e{
+ int len = (int)(p - tag_start);
+ if(len && tag_start){
+ if(TMEDIA_CONTENT_CPIM(self)->e){
+ TSK_OBJECT_SAFE_FREE(TMEDIA_CONTENT_CPIM(self)->e); \
+ }
+ TMEDIA_CONTENT_CPIM(self)->e = tsk_buffer_create(tag_start, len);
+ }
+ }
+
+ hname = token>tag %parse_hname;
+ hvalue = any*>tag %parse_hvalue;
+
+ Header = hname :>SP*:> ":" SP*<: hvalue :> CRLF;
+ m = Header+ >is_parsing_mime_headers;
+ s = CRLF;
+ h = Header+ >is_parsing_message_headers;
+ e = any*>tag %parse_e;
+
+ # Entry point
+ main := m s h s e;
+}%%
+
+
+static int tmedia_content_cpim_parse(tmedia_content_t* self, const void* in_data, tsk_size_t in_size)
+{
+ int cs = 0;
+ const char *p = in_data;
+ const char *pe = p + in_size;
+ const char *eof = pe;
+
+ const char *tag_start = tsk_null;
+
+ char* hname = tsk_null;
+ char* hvalue = tsk_null;
+ tsk_bool_t parsing_mime_headers = tsk_true;
+
+ TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
+ %%write data;
+ (void)(eof);
+ (void)(tmedia_machine_content_cpim_first_final);
+ (void)(tmedia_machine_content_cpim_error);
+ (void)(tmedia_machine_content_cpim_en_main);
+ %%write init;
+ %%write exec;
+ TSK_RAGEL_DISABLE_WARNINGS_END()
+
+ TSK_FREE(hname);
+ TSK_FREE(hvalue);
+
+ if( cs < %%{ write first_final; }%% ){
+ TSK_DEBUG_ERROR("Failed to parse CPIM content");
+ return -1;
+ }
+
+ return 0;
+}
+
+static tsk_buffer_t* tmedia_content_cpim_get_data(tmedia_content_t* self)
+{
+ tsk_buffer_t* data = tsk_buffer_create_null();
+ tmedia_content_cpim_t *cpim = TMEDIA_CONTENT_CPIM(self);
+ const tsk_list_item_t* item;
+ /*
+ m: Content-type: Message/CPIM
+ s:
+ h: (message-metadata-headers)
+ s:
+ e: (encapsulated MIME message-body)
+ x: MIME security multipart message wrapper
+ */
+ if(cpim->m_headers){
+ tsk_list_foreach(item, cpim->m_headers){
+ char* hstring = tmedia_content_header_tostring(TMEDIA_CONTENT_HEADER(item->data));
+ tsk_buffer_append_2(data, TSK_LIST_IS_LAST(cpim->m_headers, item) ? "%s\r\n\r\n" : "%s\r\n", hstring);
+ TSK_FREE(hstring);
+ }
+ }
+ if(cpim->h_headers){
+ tsk_list_foreach(item, cpim->h_headers){
+ char* hstring = tmedia_content_header_tostring(TMEDIA_CONTENT_HEADER(item->data));
+ tsk_buffer_append_2(data, TSK_LIST_IS_LAST(cpim->h_headers, item) ? "%s\r\n\r\n" : "%s\r\n", hstring);
+ TSK_FREE(hstring);
+ }
+ }
+ if(cpim->e){
+ tsk_buffer_append(data, TSK_BUFFER_DATA(cpim->e), TSK_BUFFER_SIZE(cpim->e));
+ }
+ if(cpim->x){
+ tsk_buffer_append(data, TSK_BUFFER_DATA(cpim->x), TSK_BUFFER_SIZE(cpim->x));
+ }
+
+ return data;
+}
+
+//=================================================================================================
+// object/plugin definitions
+//
+/* constructor */
+static tsk_object_t* tmedia_content_cpim_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_content_cpim_t *cpim = self;
+ if(cpim){
+ /* init base: called by tmedia_content_create() */
+ /* init self */
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* tmedia_content_cpim_dtor(tsk_object_t * self)
+{
+ tmedia_content_cpim_t *cpim = self;
+ if(cpim){
+ /* deinit base */
+ tmedia_content_deinit(TMEDIA_CONTENT(cpim));
+ /* deinit self */
+ TSK_OBJECT_SAFE_FREE(cpim->m_headers);
+ TSK_OBJECT_SAFE_FREE(cpim->h_headers);
+ TSK_OBJECT_SAFE_FREE(cpim->e);
+ TSK_OBJECT_SAFE_FREE(cpim->x);
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t tmedia_content_cpim_def_s =
+{
+ sizeof(tmedia_content_cpim_t),
+ tmedia_content_cpim_ctor,
+ tmedia_content_cpim_dtor,
+ tsk_null,
+};
+/* plugin definition*/
+static const tmedia_content_plugin_def_t tmedia_content_cpim_plugin_def_s =
+{
+ &tmedia_content_cpim_def_s,
+
+ TMEDIA_CONTENT_CPIM_TYPE,
+ tmedia_content_cpim_parse,
+ tmedia_content_cpim_get_data
+};
+const tmedia_content_plugin_def_t *tmedia_content_cpim_plugin_def_t = &tmedia_content_cpim_plugin_def_s; \ No newline at end of file
diff --git a/tinyMEDIA/ragel/tmedia_imageattr.rl b/tinyMEDIA/ragel/tmedia_imageattr.rl
new file mode 100644
index 0000000..40ad8c8
--- /dev/null
+++ b/tinyMEDIA/ragel/tmedia_imageattr.rl
@@ -0,0 +1,183 @@
+/*
+* Copyright (C) 2012-2015 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 tmedia_imageattr.c
+ * @brief 'image-attr' parser as per RFC 6236
+ */
+#include "tinymedia/tmedia_imageattr.h"
+
+#include "tsk_ragel_state.h"
+#include "tsk_debug.h"
+
+#include <stdlib.h>
+
+/***********************************
+* Ragel state machine.
+*/
+%%{
+ machine tmedia_machine_imageattr;
+
+ # Includes
+ include tmedia_machine_utils "./ragel/tmedia_machine_utils.rl";
+
+ action tag{
+ tag_start = p;
+ }
+
+ action is_send{
+ sets = &self->send.sets[0];
+ sets_count = &self->send.count;
+ *sets_count = 0;
+ }
+
+ action is_recv{
+ sets = &self->recv.sets[0];
+ sets_count = &self->recv.count;
+ *sets_count = 0;
+ }
+
+ action is_xrange{
+ xyrange = (*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE) ? &sets[*sets_count].xrange : tsk_null;
+ }
+ action is_yrange{
+ xyrange = (*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE) ? &sets[*sets_count].yrange : tsk_null;
+ }
+ action set_parsed{
+ if(*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE) (*sets_count)++;
+ }
+ action set_is_not_range{
+ if(xyrange) xyrange->is_range = 0;
+ }
+ action set_is_range{
+ if(xyrange) xyrange->is_range = 1;
+ }
+ action parse_xyvalue_range_start{
+ if(xyrange)xyrange->range.start = atoi(tag_start);
+ }
+ action parse_xyvalue_range_step{
+ if(xyrange)xyrange->range.step = atoi(tag_start);
+ }
+ action parse_xyvalue_range_end{
+ if(xyrange)xyrange->range.end = atoi(tag_start);
+ }
+ action parse_xyvalue_array_value{
+ if(xyrange && xyrange->array.count < TMEDIA_imageattr_ARRAY_MAX_SIZE){
+ xyrange->array.values[xyrange->array.count++] = atoi(tag_start);
+ }
+ }
+ action set_parse_qvalue{
+ if(*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE){
+ sets[*sets_count].qvalue = atof(tag_start);
+ }
+ }
+
+ action srange_is_array{
+ if(srange) srange->is_range = 0;
+ }
+ action srange_is_not_array{
+ if(srange) srange->is_range = 1;
+ }
+ action start_srange{
+ srange = (*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE) ? &sets[*sets_count].srange : tsk_null;
+ }
+ action parse_srange_array_value{
+ if(srange && srange->array.count < TMEDIA_imageattr_ARRAY_MAX_SIZE){
+ srange->array.values[srange->array.count++] = atof(tag_start);
+ }
+ }
+ action parse_srange_range_start{
+ if(srange) srange->range.start = atof(tag_start);
+ }
+ action parse_srange_range_end{
+ if(srange) srange->range.end = atof(tag_start);
+ }
+
+ action parse_prange_start{
+ if(*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE) sets[*sets_count].prange.start = atof(tag_start);
+ }
+ action parse_prange_end{
+ if(*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE) sets[*sets_count].prange.end = atof(tag_start), sets[*sets_count].prange.is_present = 1;
+ }
+
+ PT = DIGIT+ | "*";
+ onetonine = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
+ xyvalue = (onetonine DIGIT{,5});
+ step = xyvalue;
+ xyrange = ( "[" xyvalue>tag %parse_xyvalue_range_start ":" ( step>tag %parse_xyvalue_range_step ":" )? xyvalue>tag %parse_xyvalue_range_end "]" )%set_is_range | ( "[" xyvalue>tag %parse_xyvalue_array_value ( "," xyvalue>tag %parse_xyvalue_array_value )+ "]" )%set_is_not_range | xyvalue%set_is_not_range>tag %parse_xyvalue_array_value;
+ spvalue = ( "0" "." onetonine DIGIT{,3} ) | ( onetonine "." DIGIT{1,4} );
+ srange = (( "[" spvalue>tag %parse_srange_array_value ( "," spvalue>tag %parse_srange_array_value )+ "]" )%srange_is_array | ( "[" spvalue>tag %parse_srange_range_start "-" spvalue>tag %parse_srange_range_end "]" )%srange_is_not_array | spvalue>tag %parse_srange_array_value %srange_is_array)>start_srange;
+ prange = ( "[" spvalue>tag %parse_prange_start "-" spvalue>tag %parse_prange_end "]" );
+ _qvalue = (( "0" "." DIGIT{1,2} ) | ( "1" "." "0"{1,2} ))>tag %set_parse_qvalue; #qvalue collision
+ key_value = ( "sar="i srange ) | ( "par="i prange ) | ( "q="i _qvalue );
+ set = ("[" "x="i xyrange>is_xrange "," "y="i xyrange>is_yrange ( "," key_value )* "]")%set_parsed;
+ attr_list = ( set ( WSP+ set )* ) | "*";
+ imageattr = ( WSP* ( "send"i%is_send | "recv"i%is_recv ) WSP+ attr_list ){1,2};
+
+ # Entry point
+ main:= imageattr;
+}%%
+
+static int tmedia_imageattr_reset(tmedia_imageattr_xt* self)
+{
+ if(self){
+ tsk_size_t i;
+ memset(self, 0, sizeof(*self));
+ for(i = 0; i < TMEDIA_imageattr_ARRAY_MAX_SIZE; ++i){
+ self->send.sets[i].qvalue = 0.5;
+ self->recv.sets[i].qvalue = 0.5;
+ }
+ return 0;
+ }
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+}
+
+int tmedia_imageattr_parse(tmedia_imageattr_xt* self, const void* in_data, tsk_size_t in_size)
+{
+ int cs = 0;
+ const char *p = in_data;
+ const char *pe = p + in_size;
+ const char *eof = pe;
+
+ const char *tag_start = tsk_null;
+
+ tmedia_imageattr_set_xt* sets = tsk_null;
+ tsk_size_t* sets_count = tsk_null;
+ tmedia_imageattr_xyrange_xt* xyrange = tsk_null;
+ tmedia_imageattr_srange_xt* srange = tsk_null;
+
+ TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
+ %%write data;
+ (void)(eof);
+ (void)(tmedia_machine_imageattr_first_final);
+ (void)(tmedia_machine_imageattr_error);
+ (void)(tmedia_machine_imageattr_en_main);
+ %%write init;
+ tmedia_imageattr_reset(self);
+ %%write exec;
+ TSK_RAGEL_DISABLE_WARNINGS_END()
+
+ if( cs < %%{ write first_final; }%% ){
+ TSK_DEBUG_ERROR("Parsing failed to parse image-attr=%s", (char*)in_data);
+ return -1;
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/tinyMEDIA/ragel/tmedia_machine_utils.rl b/tinyMEDIA/ragel/tmedia_machine_utils.rl
new file mode 100644
index 0000000..2dbabad
--- /dev/null
+++ b/tinyMEDIA/ragel/tmedia_machine_utils.rl
@@ -0,0 +1,78 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_machine_utils.rl
+ * @brief Ragel file.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+%%{
+
+ machine tmedia_machine_utils;
+
+ OCTET = "0x"[0-9A-Fa-f]+;
+ CHAR = 0x01..0x7f;
+ VCHAR = 0x21..0x7e;
+ ALPHA = 0x41..0x5a | 0x61..0x7a;
+ DIGIT = 0x30..0x39;
+ CTL = 0x00..0x1f | 0x7f;
+ HTAB = "\t";
+ LF = "\n";
+ CR = "\r";
+ SP = " ";
+ DQUOTE = "\"";
+ BIT = "0" | "1";
+ HEXDIG = DIGIT | "A"i | "B"i | "C"i | "D"i | "E"i | "F"i;
+ CRLF = CR LF;
+ WSP = SP | HTAB;
+ LWSP = ( WSP | ( CRLF WSP ) )*;
+ LWS = ( WSP* CRLF )? WSP+;
+ SWS = LWS?;
+ EQUAL = SWS "=" SWS;
+ LHEX = DIGIT | 0x61..0x66;
+ HCOLON = ( SP | HTAB )* ":" SWS;
+ separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | DQUOTE | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HTAB;
+ STAR = SWS "*" SWS;
+ SLASH = SWS "/" SWS;
+ LPAREN = SWS "(" SWS;
+ RPAREN = SWS ")" SWS;
+ COMMA = SWS "," SWS;
+ SEMI = SWS ";" SWS;
+ COLON = SWS ":" SWS;
+ LAQUOT = SWS "<";
+ LDQUOT = SWS DQUOTE;
+ RAQUOT = ">" SWS;
+ RDQUOT = DQUOTE SWS;
+ UTF8_CONT = 0x80..0xbf;
+ ##### FIXME: UTF8_NONASCII up to 2bytes will fail on Android
+ UTF8_NONASCII = ( 0x80..0xff );
+ #UTF8_NONASCII = ( 0xc0..0xdf UTF8_CONT ) | ( 0xe0..0xef UTF8_CONT{2} ) | ( 0xf0..0xf7 UTF8_CONT{3} ) | ( 0xf8..0xfb UTF8_CONT{4} ) | ( 0xfc..0xfd UTF8_CONT{5} ); ctext = 0x21..0x27 | 0x2a..0x5b | 0x5d..0x7e | UTF8_NONASCII | LWS;
+ qvalue = ( "0" ( "." DIGIT{,3} )? ) | ( "1" ( "." "0"{,3} )? );
+ alphanum = ALPHA | DIGIT;
+ token = ( alphanum | "-" | "." | "!" | "%" | "*" | "_" | "+" | "`" | "'" | "~" )+;
+ ietf_token = token;
+ x_token = "x-"i token;
+ iana_token = token;
+ token_nodot = ( alphanum | "-" | "!" | "%" | "*" | "_" | "+" | "`" | "'" | "~" )+;
+ word = ( alphanum | "-" | "." | "!" | "%" | "*" | "_" | "+" | "`" | "'" | "~" | "(" | ")" | "<" | ">" | ":" | "\\" | DQUOTE | "/" | "[" | "]" | "?" | "{" | "}" )+;
+}%%
diff --git a/tinyMEDIA/src/content/tmedia_content.c b/tinyMEDIA/src/content/tmedia_content.c
new file mode 100644
index 0000000..bcdf275
--- /dev/null
+++ b/tinyMEDIA/src/content/tmedia_content.c
@@ -0,0 +1,357 @@
+/*
+* Copyright (C) 2010-2015 Mamadou Diop.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tmedia_content.c
+ * @brief Base content object.
+ */
+#include "tinymedia/content/tmedia_content.h"
+
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+/**@defgroup tmedia_content_group Contents
+*/
+
+typedef struct tmedia_content_plugin_entry_s
+{
+ const char* type;
+ const tmedia_content_plugin_def_t* plugin;
+}
+tmedia_content_plugin_entry_t;
+
+/* pointer to all registered contents */
+tmedia_content_plugin_entry_t __tmedia_content_plugin_entries[TMEDIA_CONTENT_MAX_PLUGINS][1] = { tsk_null };
+
+
+int tmedia_content_plugin_register(const char* type, const tmedia_content_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ //-- int a = sizeof(__tmedia_content_plugin_entries);
+ if (!plugin || !plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* add or replace the plugin */
+ for (i = 0; i < TMEDIA_CONTENT_MAX_PLUGINS; i++){
+ if (!__tmedia_content_plugin_entries[i]->plugin || (__tmedia_content_plugin_entries[i]->plugin == plugin && tsk_striequals(type, __tmedia_content_plugin_entries[i]->type))){
+ __tmedia_content_plugin_entries[i]->type = type;
+ __tmedia_content_plugin_entries[i]->plugin = plugin;
+ return 0;
+ }
+ }
+
+
+ TSK_DEBUG_ERROR("There are already %d plugins.", TMEDIA_CONTENT_MAX_PLUGINS);
+ return -2;
+}
+
+int tmedia_content_plugin_unregister(const char* type, const tmedia_content_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+ if (!plugin){
+ TSK_DEBUG_ERROR("Invalid Parameter");
+ return -1;
+ }
+
+ /* find the plugin to unregister */
+ for (i = 0; i < TMEDIA_CONTENT_MAX_PLUGINS && __tmedia_content_plugin_entries[i]->plugin; i++){
+ if (__tmedia_content_plugin_entries[i]->plugin == plugin && tsk_striequals(type, __tmedia_content_plugin_entries[i]->type)){
+ __tmedia_content_plugin_entries[i]->type = tsk_null,
+ __tmedia_content_plugin_entries[i]->plugin = tsk_null;
+ found = tsk_true;
+ break;
+ }
+ }
+
+ /* compact */
+ if (found){
+ for (; i < (TMEDIA_CONTENT_MAX_PLUGINS - 1); i++){
+ if (__tmedia_content_plugin_entries[i + 1]->plugin){
+ __tmedia_content_plugin_entries[i]->type = __tmedia_content_plugin_entries[i + 1]->type,
+ __tmedia_content_plugin_entries[i]->plugin = __tmedia_content_plugin_entries[i + 1]->plugin;
+ }
+ else{
+ break;
+ }
+ }
+ __tmedia_content_plugin_entries[i]->type = tsk_null,
+ __tmedia_content_plugin_entries[i]->plugin = tsk_null;
+ }
+ return (found ? 0 : -2);
+}
+
+int tmedia_content_plugin_unregister_all()
+{
+ tsk_size_t i;
+ for (i = 0; i < TMEDIA_CONTENT_MAX_PLUGINS && __tmedia_content_plugin_entries[i]->plugin; i++){
+ __tmedia_content_plugin_entries[i]->type = tsk_null,
+ __tmedia_content_plugin_entries[i]->plugin = tsk_null;
+ }
+ return 0;
+}
+
+tmedia_content_t* tmedia_content_create(const char* type)
+{
+ tmedia_content_t* content = tsk_null;
+ const tmedia_content_plugin_entry_t* entry;
+ tsk_size_t i = 0;
+
+ while (i < TMEDIA_CONTENT_MAX_PLUGINS){
+ entry = __tmedia_content_plugin_entries[i];
+ if (!entry->plugin || !entry->type){
+ break;
+ }
+ if (entry->plugin->objdef && tsk_striequals(entry->type, type)){
+ if ((content = tsk_object_new(entry->plugin->objdef))){
+ content->plugin = entry->plugin;
+ content->type = entry->type;
+ return content;
+ }
+ }
+ ++i;
+ }
+
+ TSK_DEBUG_WARN("Failed to find content type (%s) will be added as dummy", type);
+ if (tmedia_content_dummy_plugin_def_t){
+ content = tsk_object_new(tmedia_content_dummy_plugin_def_t->objdef);
+ content->plugin = tmedia_content_dummy_plugin_def_t;
+ content->type = type;
+ }
+
+ return content;
+}
+
+tmedia_content_t* tmedia_content_parse(const void* data, tsk_size_t size, const char* type)
+{
+ tmedia_content_t* content = tmedia_content_create(type);
+ if (content){
+ if (content->plugin->parse){
+ int ret;
+ if ((ret = content->plugin->parse(content, data, size))){
+ TSK_DEBUG_ERROR("Failed to parse the content(%d)", ret);
+ TSK_OBJECT_SAFE_FREE(content);
+ return tsk_null;
+ }
+ return content;
+ }
+ else{
+ TSK_DEBUG_ERROR("No parser function for this content (%s)", type);
+ TSK_OBJECT_SAFE_FREE(content);
+ return tsk_null;
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to to find content(%s)", type);
+ return tsk_null;
+ }
+}
+
+int tmedia_content_init(tmedia_content_t* self)
+{
+ if (!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ return 0;
+}
+
+int tmedia_content_deinit(tmedia_content_t* self)
+{
+ if (!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ return 0;
+}
+
+tsk_buffer_t* tmedia_content_get_data(tmedia_content_t* self)
+{
+ if (!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+ return self->plugin->get_data(self);
+}
+
+
+
+
+static int tmedia_content_dummy_parse(tmedia_content_t* self, const void* in_data, tsk_size_t in_size)
+{
+ tmedia_content_dummy_t *dummy = TMEDIA_CONTENT_DUMMY(self);
+ if (!dummy || dummy->data){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ dummy->data = tsk_buffer_create(in_data, in_size);
+ return 0;
+}
+
+static tsk_buffer_t* tmedia_content_dummy_get_data(tmedia_content_t* self)
+{
+ return tsk_object_ref(TMEDIA_CONTENT_DUMMY(self)->data);
+}
+
+
+
+
+
+
+//=================================================================================================
+// object/plugin definitions
+//
+/* constructor */
+static tsk_object_t* tmedia_content_dummy_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_content_dummy_t *dummy = self;
+ if (dummy){
+ /* init base: called by tmedia_content_create() */
+ /* init self */
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* tmedia_content_dummy_dtor(tsk_object_t * self)
+{
+ tmedia_content_dummy_t *dummy = self;
+ if (dummy){
+ /* deinit base */
+ tmedia_content_deinit(TMEDIA_CONTENT(dummy));
+ /* deinit self */
+ TSK_OBJECT_SAFE_FREE(dummy->data);
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t tmedia_content_dummy_def_s =
+{
+ sizeof(tmedia_content_dummy_t),
+ tmedia_content_dummy_ctor,
+ tmedia_content_dummy_dtor,
+ tsk_null,
+};
+/* plugin definition*/
+static const tmedia_content_plugin_def_t tmedia_content_dummy_plugin_def_s =
+{
+ &tmedia_content_dummy_def_s,
+
+ "dummy",
+ tmedia_content_dummy_parse,
+ tmedia_content_dummy_get_data
+};
+const tmedia_content_plugin_def_t *tmedia_content_dummy_plugin_def_t = &tmedia_content_dummy_plugin_def_s;
+
+
+
+//=================================================================================================
+// media content header
+//
+
+tmedia_content_header_t* tmedia_content_header_create(const char* name, const char* value)
+{
+ tmedia_content_header_t* header = tsk_object_new(tmedia_content_header_def_t);
+ const char* str;
+
+ if (!header){
+ TSK_DEBUG_ERROR("Failed to create new header object");
+ return tsk_null;
+ }
+ header->name = tsk_strdup(name);
+ if (value && (str = strstr(value, ";"))){
+ header->value = tsk_strndup(value, (tsk_size_t)(str - value));
+ header->params = tsk_params_fromstring((str + 1), ";", tsk_true);
+ }
+ else{
+ header->value = tsk_strdup(value);
+ }
+
+ return header;
+}
+
+int tmedia_content_header_deinit(tmedia_content_header_t* self)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ TSK_FREE(self->name);
+ TSK_FREE(self->value);
+ TSK_OBJECT_SAFE_FREE(self->params);
+
+ return 0;
+}
+
+char* tmedia_content_header_tostring(const tmedia_content_header_t* self)
+{
+ char* string = tsk_null;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ tsk_sprintf(&string, "%s: %s", self->name, self->value);
+ if (self->params){
+ const tsk_list_item_t* item;
+ tsk_list_foreach(item, self->params){
+ tsk_strcat_2(&string, ";%s=%s", TSK_PARAM(item->data)->name, TSK_PARAM(item->data)->value);
+ }
+ }
+
+ return string;
+}
+
+/* constructor */
+static tsk_object_t* tmedia_content_header_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_content_header_t *header = self;
+ if (header){
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* tmedia_content_header_dtor(tsk_object_t * self)
+{
+ tmedia_content_header_t *header = self;
+ if (header){
+ tmedia_content_header_deinit(header);
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t tmedia_content_header_def_s =
+{
+ sizeof(tmedia_content_header_t),
+ tmedia_content_header_ctor,
+ tmedia_content_header_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tmedia_content_header_def_t = &tmedia_content_header_def_s;
diff --git a/tinyMEDIA/src/content/tmedia_content_cpim.c b/tinyMEDIA/src/content/tmedia_content_cpim.c
new file mode 100644
index 0000000..8b36727
--- /dev/null
+++ b/tinyMEDIA/src/content/tmedia_content_cpim.c
@@ -0,0 +1,449 @@
+
+/* #line 1 "./ragel/tmedia_content_cpim.rl" */
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tmedia_content_cpim.c
+ * @brief Common Presence and Instant Messaging (CPIM): Message Format (RFC 3862)
+ */
+#include "tinymedia/content/tmedia_content_cpim.h"
+
+#include "tsk_debug.h"
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_ragel_state.h"
+
+#include <string.h>
+
+/* RFC 3862 - 2. Overall Message Structure
+A complete message looks something like this:
+
+ m: Content-type: Message/CPIM
+ s:
+ h: (message-metadata-headers)
+ s:
+ e: (encapsulated MIME message-body)
+
+ The end of the message body is defined by the framing mechanism of
+ the protocol used. The tags 'm:', 's:', 'h:', 'e:', and 'x:' are not
+ part of the message format and are used here to indicate the
+ different parts of the message, thus:
+
+ m: MIME headers for the overall message
+ s: a blank separator line
+ h: message headers
+ e: encapsulated MIME object containing the message content
+ x: MIME security multipart message wrapper
+*/
+
+
+
+
+
+/***********************************
+* Ragel state machine.
+*/
+
+/* #line 124 "./ragel/tmedia_content_cpim.rl" */
+
+
+
+static int tmedia_content_cpim_parse(tmedia_content_t* self, const void* in_data, tsk_size_t in_size)
+{
+ int cs = 0;
+ const char *p = in_data;
+ const char *pe = p + in_size;
+ const char *eof = pe;
+
+ const char *tag_start = tsk_null;
+
+ char* hname = tsk_null;
+ char* hvalue = tsk_null;
+ tsk_bool_t parsing_mime_headers = tsk_true;
+
+ TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
+
+/* #line 84 "./src/content/tmedia_content_cpim.c" */
+static const char _tmedia_machine_content_cpim_actions[] = {
+ 0, 1, 0, 1, 3, 1, 4, 1,
+ 5, 2, 0, 4, 2, 0, 5, 2,
+ 1, 0, 2, 2, 0
+};
+
+static const char _tmedia_machine_content_cpim_key_offsets[] = {
+ 0, 0, 14, 30, 32, 34, 35, 36,
+ 51, 52, 66, 82, 84, 86, 87, 88,
+ 103, 104, 104
+};
+
+static const char _tmedia_machine_content_cpim_trans_keys[] = {
+ 33, 37, 39, 126, 42, 43, 45, 46,
+ 48, 57, 65, 90, 95, 122, 32, 33,
+ 37, 39, 58, 126, 42, 43, 45, 46,
+ 48, 57, 65, 90, 95, 122, 32, 58,
+ 13, 32, 13, 10, 13, 33, 37, 39,
+ 126, 42, 43, 45, 46, 48, 57, 65,
+ 90, 95, 122, 10, 33, 37, 39, 126,
+ 42, 43, 45, 46, 48, 57, 65, 90,
+ 95, 122, 32, 33, 37, 39, 58, 126,
+ 42, 43, 45, 46, 48, 57, 65, 90,
+ 95, 122, 32, 58, 13, 32, 13, 10,
+ 13, 33, 37, 39, 126, 42, 43, 45,
+ 46, 48, 57, 65, 90, 95, 122, 10,
+ 0
+};
+
+static const char _tmedia_machine_content_cpim_single_lengths[] = {
+ 0, 4, 6, 2, 2, 1, 1, 5,
+ 1, 4, 6, 2, 2, 1, 1, 5,
+ 1, 0, 0
+};
+
+static const char _tmedia_machine_content_cpim_range_lengths[] = {
+ 0, 5, 5, 0, 0, 0, 0, 5,
+ 0, 5, 5, 0, 0, 0, 0, 5,
+ 0, 0, 0
+};
+
+static const char _tmedia_machine_content_cpim_index_offsets[] = {
+ 0, 0, 10, 22, 25, 28, 30, 32,
+ 43, 45, 55, 67, 70, 73, 75, 77,
+ 88, 90, 91
+};
+
+static const char _tmedia_machine_content_cpim_indicies[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 2, 3, 3, 3, 4, 3,
+ 3, 3, 3, 3, 3, 1, 5, 6,
+ 1, 8, 6, 7, 10, 9, 11, 1,
+ 12, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 1, 14, 1, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 1, 16,
+ 17, 17, 17, 18, 17, 17, 17, 17,
+ 17, 17, 1, 19, 20, 1, 22, 20,
+ 21, 24, 23, 25, 1, 26, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 1,
+ 28, 1, 29, 30, 0
+};
+
+static const char _tmedia_machine_content_cpim_trans_targs[] = {
+ 2, 0, 3, 2, 4, 3, 4, 5,
+ 6, 5, 6, 7, 8, 2, 9, 10,
+ 11, 10, 12, 11, 12, 13, 14, 13,
+ 14, 15, 16, 10, 17, 18, 18
+};
+
+static const char _tmedia_machine_content_cpim_trans_actions[] = {
+ 15, 0, 3, 0, 3, 0, 0, 1,
+ 9, 0, 5, 0, 0, 1, 0, 18,
+ 3, 0, 3, 0, 0, 1, 9, 0,
+ 5, 0, 0, 1, 0, 1, 0
+};
+
+static const char _tmedia_machine_content_cpim_eof_actions[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 12, 7
+};
+
+static const int tmedia_machine_content_cpim_start = 1;
+static const int tmedia_machine_content_cpim_first_final = 17;
+static const int tmedia_machine_content_cpim_error = 0;
+
+static const int tmedia_machine_content_cpim_en_main = 1;
+
+
+/* #line 142 "./ragel/tmedia_content_cpim.rl" */
+ (void)(eof);
+ (void)(tmedia_machine_content_cpim_first_final);
+ (void)(tmedia_machine_content_cpim_error);
+ (void)(tmedia_machine_content_cpim_en_main);
+
+/* #line 180 "./src/content/tmedia_content_cpim.c" */
+ {
+ cs = tmedia_machine_content_cpim_start;
+ }
+
+/* #line 147 "./ragel/tmedia_content_cpim.rl" */
+
+/* #line 187 "./src/content/tmedia_content_cpim.c" */
+ {
+ int _klen;
+ unsigned int _trans;
+ const char *_acts;
+ unsigned int _nacts;
+ const char *_keys;
+
+ if ( p == pe )
+ goto _test_eof;
+ if ( cs == 0 )
+ goto _out;
+_resume:
+ _keys = _tmedia_machine_content_cpim_trans_keys + _tmedia_machine_content_cpim_key_offsets[cs];
+ _trans = _tmedia_machine_content_cpim_index_offsets[cs];
+
+ _klen = _tmedia_machine_content_cpim_single_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + _klen - 1;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( (*p) < *_mid )
+ _upper = _mid - 1;
+ else if ( (*p) > *_mid )
+ _lower = _mid + 1;
+ else {
+ _trans += (_mid - _keys);
+ goto _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _tmedia_machine_content_cpim_range_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( (*p) < _mid[0] )
+ _upper = _mid - 2;
+ else if ( (*p) > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ _trans += ((_mid - _keys)>>1);
+ goto _match;
+ }
+ }
+ _trans += _klen;
+ }
+
+_match:
+ _trans = _tmedia_machine_content_cpim_indicies[_trans];
+ cs = _tmedia_machine_content_cpim_trans_targs[_trans];
+
+ if ( _tmedia_machine_content_cpim_trans_actions[_trans] == 0 )
+ goto _again;
+
+ _acts = _tmedia_machine_content_cpim_actions + _tmedia_machine_content_cpim_trans_actions[_trans];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 )
+ {
+ switch ( *_acts++ )
+ {
+ case 0:
+/* #line 67 "./ragel/tmedia_content_cpim.rl" */
+ {
+ tag_start = p;
+ }
+ break;
+ case 1:
+/* #line 71 "./ragel/tmedia_content_cpim.rl" */
+ {
+ parsing_mime_headers = tsk_true;
+ }
+ break;
+ case 2:
+/* #line 75 "./ragel/tmedia_content_cpim.rl" */
+ {
+ parsing_mime_headers = tsk_false;
+ }
+ break;
+ case 3:
+/* #line 79 "./ragel/tmedia_content_cpim.rl" */
+ {
+ TSK_PARSER_SET_STRING(hname);
+ }
+ break;
+ case 4:
+/* #line 83 "./ragel/tmedia_content_cpim.rl" */
+ {
+ tmedia_content_header_t* header;
+ TSK_PARSER_SET_STRING(hvalue);
+ header = tmedia_content_header_create(hname, hvalue);
+ TSK_FREE(hname); TSK_FREE(hvalue);
+
+ if(parsing_mime_headers){
+ if(!TMEDIA_CONTENT_CPIM(self)->m_headers){
+ TMEDIA_CONTENT_CPIM(self)->m_headers = tsk_list_create();
+ }
+ tsk_list_push_back_data(TMEDIA_CONTENT_CPIM(self)->m_headers, (void**)&header);
+ }
+ else{
+ if(!TMEDIA_CONTENT_CPIM(self)->h_headers){
+ TMEDIA_CONTENT_CPIM(self)->h_headers = tsk_list_create();
+ }
+ tsk_list_push_back_data(TMEDIA_CONTENT_CPIM(self)->h_headers, (void**)&header);
+ }
+ }
+ break;
+/* #line 307 "./src/content/tmedia_content_cpim.c" */
+ }
+ }
+
+_again:
+ if ( cs == 0 )
+ goto _out;
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ if ( p == eof )
+ {
+ const char *__acts = _tmedia_machine_content_cpim_actions + _tmedia_machine_content_cpim_eof_actions[cs];
+ unsigned int __nacts = (unsigned int) *__acts++;
+ while ( __nacts-- > 0 ) {
+ switch ( *__acts++ ) {
+ case 0:
+/* #line 67 "./ragel/tmedia_content_cpim.rl" */
+ {
+ tag_start = p;
+ }
+ break;
+ case 5:
+/* #line 103 "./ragel/tmedia_content_cpim.rl" */
+ {
+ int len = (int)(p - tag_start);
+ if(len && tag_start){
+ if(TMEDIA_CONTENT_CPIM(self)->e){
+ TSK_OBJECT_SAFE_FREE(TMEDIA_CONTENT_CPIM(self)->e); \
+ }
+ TMEDIA_CONTENT_CPIM(self)->e = tsk_buffer_create(tag_start, len);
+ }
+ }
+ break;
+/* #line 341 "./src/content/tmedia_content_cpim.c" */
+ }
+ }
+ }
+
+ _out: {}
+ }
+
+/* #line 148 "./ragel/tmedia_content_cpim.rl" */
+ TSK_RAGEL_DISABLE_WARNINGS_END()
+
+ TSK_FREE(hname);
+ TSK_FREE(hvalue);
+
+ if( cs <
+/* #line 356 "./src/content/tmedia_content_cpim.c" */
+17
+/* #line 153 "./ragel/tmedia_content_cpim.rl" */
+ ){
+ TSK_DEBUG_ERROR("Failed to parse CPIM content");
+ return -1;
+ }
+
+ return 0;
+}
+
+static tsk_buffer_t* tmedia_content_cpim_get_data(tmedia_content_t* self)
+{
+ tsk_buffer_t* data = tsk_buffer_create_null();
+ tmedia_content_cpim_t *cpim = TMEDIA_CONTENT_CPIM(self);
+ const tsk_list_item_t* item;
+ /*
+ m: Content-type: Message/CPIM
+ s:
+ h: (message-metadata-headers)
+ s:
+ e: (encapsulated MIME message-body)
+ x: MIME security multipart message wrapper
+ */
+ if(cpim->m_headers){
+ tsk_list_foreach(item, cpim->m_headers){
+ char* hstring = tmedia_content_header_tostring(TMEDIA_CONTENT_HEADER(item->data));
+ tsk_buffer_append_2(data, TSK_LIST_IS_LAST(cpim->m_headers, item) ? "%s\r\n\r\n" : "%s\r\n", hstring);
+ TSK_FREE(hstring);
+ }
+ }
+ if(cpim->h_headers){
+ tsk_list_foreach(item, cpim->h_headers){
+ char* hstring = tmedia_content_header_tostring(TMEDIA_CONTENT_HEADER(item->data));
+ tsk_buffer_append_2(data, TSK_LIST_IS_LAST(cpim->h_headers, item) ? "%s\r\n\r\n" : "%s\r\n", hstring);
+ TSK_FREE(hstring);
+ }
+ }
+ if(cpim->e){
+ tsk_buffer_append(data, TSK_BUFFER_DATA(cpim->e), TSK_BUFFER_SIZE(cpim->e));
+ }
+ if(cpim->x){
+ tsk_buffer_append(data, TSK_BUFFER_DATA(cpim->x), TSK_BUFFER_SIZE(cpim->x));
+ }
+
+ return data;
+}
+
+//=================================================================================================
+// object/plugin definitions
+//
+/* constructor */
+static tsk_object_t* tmedia_content_cpim_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_content_cpim_t *cpim = self;
+ if(cpim){
+ /* init base: called by tmedia_content_create() */
+ /* init self */
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* tmedia_content_cpim_dtor(tsk_object_t * self)
+{
+ tmedia_content_cpim_t *cpim = self;
+ if(cpim){
+ /* deinit base */
+ tmedia_content_deinit(TMEDIA_CONTENT(cpim));
+ /* deinit self */
+ TSK_OBJECT_SAFE_FREE(cpim->m_headers);
+ TSK_OBJECT_SAFE_FREE(cpim->h_headers);
+ TSK_OBJECT_SAFE_FREE(cpim->e);
+ TSK_OBJECT_SAFE_FREE(cpim->x);
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t tmedia_content_cpim_def_s =
+{
+ sizeof(tmedia_content_cpim_t),
+ tmedia_content_cpim_ctor,
+ tmedia_content_cpim_dtor,
+ tsk_null,
+};
+/* plugin definition*/
+static const tmedia_content_plugin_def_t tmedia_content_cpim_plugin_def_s =
+{
+ &tmedia_content_cpim_def_s,
+
+ TMEDIA_CONTENT_CPIM_TYPE,
+ tmedia_content_cpim_parse,
+ tmedia_content_cpim_get_data
+};
+const tmedia_content_plugin_def_t *tmedia_content_cpim_plugin_def_t = &tmedia_content_cpim_plugin_def_s; \ No newline at end of file
diff --git a/tinyMEDIA/src/content/tmedia_content_multipart.c b/tinyMEDIA/src/content/tmedia_content_multipart.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tinyMEDIA/src/content/tmedia_content_multipart.c
diff --git a/tinyMEDIA/src/content/tmedia_content_sip_frag.c b/tinyMEDIA/src/content/tmedia_content_sip_frag.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tinyMEDIA/src/content/tmedia_content_sip_frag.c
diff --git a/tinyMEDIA/src/tmedia.c b/tinyMEDIA/src/tmedia.c
new file mode 100644
index 0000000..f43b4fa
--- /dev/null
+++ b/tinyMEDIA/src/tmedia.c
@@ -0,0 +1,289 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia.c
+ * @brief Media.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+ */
+#include "tinymedia/tmedia.h"
+
+#if 0
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+#define TMED_MAX_PLUGINS 10
+const tmedia_plugin_def_t* __tmedia_plugins[TMED_MAX_PLUGINS] = {0};
+
+
+tmedia_t* tmedia_create(const char* name, const char* host, tnet_socket_type_t socket_type)
+{
+ return tsk_object_new(TMEDIA_VA_ARGS(name, host, socket_type));
+}
+
+tmedia_t* tmedia_create_null()
+{
+ return tmedia_create(tsk_null, TNET_SOCKET_HOST_ANY, tnet_socket_type_invalid);
+}
+
+int tmedia_init(tmedia_t* self, const char* name)
+{
+ if(!self){
+ return -1;
+ }
+
+ tsk_strupdate(&self->name, name);
+
+ return 0;
+}
+
+int tmedia_deinit(tmedia_t* self)
+{
+ if(!self){
+ return -1;
+ }
+
+ TSK_FREE(self->name);
+ TSK_FREE(self->protocol);
+
+ return 0;
+}
+
+
+int tmedia_plugin_register(const tmedia_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ if(!plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ for(i=0; i<TMED_MAX_PLUGINS; i++){
+ if(!__tmedia_plugins[i] || __tmedia_plugins[i] == plugin){
+ __tmedia_plugins[i] = plugin;
+ return 0;
+ }
+ }
+
+ TSK_DEBUG_ERROR("There are already %d plugins.", TMED_MAX_PLUGINS);
+ return -2;
+}
+
+tmedia_t* tmedia_factory_create(const char* name, const char* host, tnet_socket_type_t socket_type)
+{
+ tmedia_t* ret = tsk_null;
+ const tmedia_plugin_def_t* plugin;
+ tsk_size_t i = 0;
+
+ while((i < TMED_MAX_PLUGINS) && (plugin = __tmedia_plugins[i++])){
+ if(plugin->objdef && tsk_strequals(plugin->name, name)){
+ if((ret = tsk_object_new(plugin->objdef, name, host, socket_type))){
+ ret->plugin = plugin;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+int tmedia_start(tmedia_t* self)
+{
+ if(!self || !self->plugin){
+ return -1;
+ }
+
+ if(!self->plugin->start){
+ return -2;
+ }
+ else{
+ return self->plugin->start(self);
+ }
+}
+int tmedia_pause(tmedia_t*self )
+{
+ if(!self || !self->plugin){
+ return -1;
+ }
+
+ if(!self->plugin->pause){
+ return -2;
+ }
+ else{
+ return self->plugin->pause(self);
+ }
+}
+int tmedia_stop(tmedia_t* self)
+{
+ if(!self || !self->plugin){
+ return -1;
+ }
+
+ if(!self->plugin->stop){
+ return -2;
+ }
+ else{
+ return self->plugin->stop(self);
+ }
+}
+
+// Only SDP headers
+const tsdp_header_M_t* tmedia_get_local_offer(tmedia_t* self, ...)
+{
+
+ if(!self || !self->plugin){
+ return tsk_null;
+ }
+
+ if(!self->plugin->get_local_offer){
+ return tsk_null;
+ }
+ else{
+ va_list ap;
+ const tsdp_header_M_t* M;
+ va_start(ap, self);
+ M = self->plugin->get_local_offer(self, &ap);
+ va_end(ap);
+ return M;
+ }
+}
+
+const tsdp_header_M_t* tmedia_get_negotiated_offer(tmedia_t* self)
+{
+ if(!self || !self->plugin){
+ return tsk_null;
+ }
+
+ if(!self->plugin->get_negotiated_offer){
+ return tsk_null;
+ }
+ else{
+ return self->plugin->get_negotiated_offer(self);
+ }
+}
+
+int tmedia_set_remote_offer(tmedia_t* self, const tsdp_message_t* offer)
+{
+ if(!self || !self->plugin){
+ return -1;
+ }
+
+ if(!self->plugin->set_remote_offer){
+ return -2;
+ }
+ else{
+ return self->plugin->set_remote_offer(self, offer);
+ }
+}
+
+int tmedia_perform(tmedia_t* self, tmedia_action_t action, ... )
+{
+ int ret = -1;
+
+ if(!self || !self->plugin){
+ return -1;
+ }
+
+ if(!self->plugin->perform){
+ return -2;
+ }
+ else{
+ const tsk_object_def_t* objdef;
+ tsk_param_t *param;
+ tsk_params_L_t* params;
+ va_list ap;
+
+ va_start(ap, action);
+ params = tsk_list_create();
+ while((objdef = va_arg(ap, const tsk_object_def_t*))){
+ if(objdef != tsk_param_def_t){ // sanity check
+ break;
+ }
+ if((param = tsk_object_new_2(objdef, &ap))){
+ tsk_params_add_param_2(&params, param);
+ TSK_OBJECT_SAFE_FREE(param);
+ }
+ }
+
+ // Perform
+ ret = self->plugin->perform(self, action, params);
+
+ TSK_OBJECT_SAFE_FREE(params);
+ va_end(ap);
+
+ return ret;
+ }
+}
+
+//========================================================
+// Media object definition
+//
+
+static void* tmedia_ctor(tsk_object_t *self, va_list * app)
+{
+ tmedia_t *media = self;
+ if(media){
+ const char* name = va_arg(*app, const char*);
+ const char* host = va_arg(*app, const char*);
+ tnet_socket_type_t socket_type = va_arg(*app, tnet_socket_type_t);
+
+ tmedia_init(media, name);
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to create new media.");
+ }
+ return self;
+}
+
+static void* tmedia_dtor(tsk_object_t *self)
+{
+ tmedia_t *media = self;
+ if(media){
+ tmedia_deinit(media);
+ }
+ else{
+ TSK_DEBUG_ERROR("Null media.");
+ }
+
+ return self;
+}
+
+static int tmedia_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2)
+{
+ return -1;
+}
+
+static const tsk_object_def_t tmedia_def_s =
+{
+ sizeof(tmedia_t),
+ tmedia_ctor,
+ tmedia_dtor,
+ tmedia_cmp
+};
+
+const void *tmedia_def_t = &tmedia_def_s;
+
+#endif /* if 0 => FIXME: Remove this file */
+
diff --git a/tinyMEDIA/src/tmedia_codec.c b/tinyMEDIA/src/tmedia_codec.c
new file mode 100644
index 0000000..2b2b140
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_codec.c
@@ -0,0 +1,833 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_codec.c
+ * @brief Base codec object.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tinymedia/tmedia_codec.h"
+#include "tinymedia/tmedia_defaults.h"
+
+#include "tinysdp/headers/tsdp_header_M.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+#include <limits.h> /* INT_MAX */
+
+/**@defgroup tmedia_codec_group Codecs
+*/
+
+/* pointer to all registered codecs */
+const tmedia_codec_plugin_def_t* __tmedia_codec_plugins[TMED_CODEC_MAX_PLUGINS] = {0};
+
+
+/*== Predicate function to find a codec object by format */
+static int __pred_find_codec_by_format(const tsk_list_item_t *item, const void *format)
+{
+ if(item && item->data){
+ return tsk_strcmp(((tmedia_codec_t *)item->data)->format, format);
+ }
+ return -1;
+}
+
+/*== Predicate function to find a codec object by negociated format */
+static int __pred_find_codec_by_neg_format(const tsk_list_item_t *item, const void *format)
+{
+ if(item && item->data){
+ return tsk_strcmp(((tmedia_codec_t *)item->data)->neg_format, format);
+ }
+ return -1;
+}
+
+/**@ingroup tmedia_codec_group
+* Initialize a Codec
+* @param self The codec to initialize. Could be any type of codec (e.g. @ref tmedia_codec_audio_t or @ref tmedia_codec_video_t).
+* @param type
+* @param name the name of the codec. e.g. "G.711u" or "G.711a" etc used in the sdp.
+* @param desc full description.
+* @param format the format. e.g. "0" for G.711.u or "8" for G.711a or "*" for MSRP.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tmedia_codec_init(tmedia_codec_t* self, tmedia_type_t type, const char* name, const char* desc, const char* format)
+{
+ if(!self || tsk_strnullORempty(name)){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->type = type;
+ tsk_strupdate(&self->name, name);
+ tsk_strupdate(&self->desc,desc);
+ tsk_strupdate(&self->format, format);
+ if(!self->bandwidth_max_upload) self->bandwidth_max_upload = (type == tmedia_video ? tmedia_defaults_get_bandwidth_video_upload_max() : INT_MAX); // INT_MAX or <=0 means undefined
+ if(!self->bandwidth_max_download) self->bandwidth_max_download = (type == tmedia_video ? tmedia_defaults_get_bandwidth_video_download_max() : INT_MAX); // INT_MAX or <=0 means undefined
+ if(!self->in.rate) self->in.rate = self->plugin->rate;
+ if(!self->out.rate) self->out.rate = self->plugin->rate;
+
+ if(type & tmedia_audio){
+ tmedia_codec_audio_t* audio = TMEDIA_CODEC_AUDIO(self);
+ if(!audio->in.ptime) audio->in.ptime = (self->plugin->audio.ptime ? self->plugin->audio.ptime : tmedia_defaults_get_audio_ptime());
+ if(!audio->out.ptime) audio->out.ptime = (self->plugin->audio.ptime ? self->plugin->audio.ptime : tmedia_defaults_get_audio_ptime());
+ if(!audio->in.channels) audio->in.channels = self->plugin->audio.channels;
+ if(!audio->out.channels) audio->out.channels = self->plugin->audio.channels;
+ if(!audio->in.timestamp_multiplier) audio->in.timestamp_multiplier = tmedia_codec_audio_get_timestamp_multiplier(self->id, self->in.rate);
+ if(!audio->out.timestamp_multiplier) audio->out.timestamp_multiplier = tmedia_codec_audio_get_timestamp_multiplier(self->id, self->out.rate);
+ }
+ // Video flipping: For backward compatibility we have to initialize the default values
+ // according to the CFLAGS: 'FLIP_ENCODED_PICT' and 'FLIP_DECODED_PICT'. At any time you
+ // can update thse values (e.g. when the device switch from landscape to portrait) using video_session->set();
+ else if(type & tmedia_video){
+ tmedia_codec_video_t* video = TMEDIA_CODEC_VIDEO(self);
+#if FLIP_ENCODED_PICT
+ video->out.flip = tsk_true;
+#endif
+#if FLIP_DECODED_PICT
+ video->in.flip = tsk_true;
+#endif
+ if(!video->in.fps) video->in.fps = self->plugin->video.fps ? self->plugin->video.fps : tmedia_defaults_get_video_fps();
+ if(!video->out.fps) video->out.fps = self->plugin->video.fps ? self->plugin->video.fps : tmedia_defaults_get_video_fps();
+ if(video->in.chroma == tmedia_chroma_none) video->in.chroma = tmedia_chroma_yuv420p;
+ if(video->out.chroma == tmedia_chroma_none) video->out.chroma = tmedia_chroma_yuv420p;
+
+ if(0){ // @deprecated
+ if(!video->in.width) video->in.width = video->out.width = self->plugin->video.width;
+ if(!video->in.height) video->in.height = video->out.height = self->plugin->video.height;
+ }
+ else{
+ int ret;
+ unsigned width, height;
+ video->pref_size = tmedia_defaults_get_pref_video_size();
+ if((ret = tmedia_video_get_size(video->pref_size, &width, &height)) != 0){
+ width = self->plugin->video.width;
+ height = self->plugin->video.height;
+ }
+ if(!video->in.width) video->in.width = video->out.width = width;
+ if(!video->in.height) video->in.height = video->out.height = height;
+ }
+
+ }
+
+ return 0;
+}
+
+int tmedia_codec_set(tmedia_codec_t* self, const struct tmedia_param_s* param)
+{
+ if(self && self->plugin && self->plugin->set && param){
+ return self->plugin->set(self, param);
+ }
+ return 0;
+}
+
+/**@ingroup tmedia_codec_group
+* Prepares a codec by opening it.
+* @param self The codec to open.
+* @retval Zero if succeed and non-zero error code otherwise.
+* @sa @ref tmedia_codec_close()
+*/
+int tmedia_codec_open(tmedia_codec_t* self)
+{
+ if(!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if(self->opened){
+ TSK_DEBUG_WARN("Codec already opened");
+ return 0;
+ }
+
+ if(self->plugin->open){
+ int ret;
+ if((ret = self->plugin->open(self))){
+ TSK_DEBUG_ERROR("Failed to open [%s] codec", self->plugin->desc);
+ return ret;
+ }
+ else{
+ self->opened = tsk_true;
+ return 0;
+ }
+ }
+ else{
+ self->opened = tsk_true;
+ return 0;
+ }
+}
+
+/**@ingroup tmedia_codec_group
+* UnPrepares a codec by closing it.
+* @param self The codec to close.
+* @retval Zero if succeed and non-zero error code otherwise.
+* @sa @ref tmedia_codec_open()
+*/
+int tmedia_codec_close(tmedia_codec_t* self)
+{
+ if(!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if(!self->opened){
+ return 0;
+ }
+
+ if(self->plugin->close){
+ int ret;
+
+ if((ret = self->plugin->close(self))){
+ TSK_DEBUG_ERROR("Failed to close [%s] codec", self->plugin->desc);
+ return ret;
+ }
+ else{
+ self->opened = tsk_false;
+ return 0;
+ }
+ }
+ else{
+ self->opened = tsk_false;
+ return 0;
+ }
+}
+
+/**@ingroup tmedia_codec_group
+* Generic function to compare two codecs.
+* @param codec1 The first codec to compare.
+* @param codec2 The second codec to compare.
+* @retval Returns an integral value indicating the relationship between the two codecs:
+* <0 : @a codec1 less than @a codec2.<br>
+* 0 : @a codec1 identical to @a codec2.<br>
+* >0 : @a codec1 greater than @a codec2.<br>
+*/
+int tmedia_codec_cmp(const tsk_object_t* codec1, const tsk_object_t* codec2)
+{
+ const tmedia_codec_t* _c1 = codec1;
+ const tmedia_codec_t* _c2 = codec2;
+
+ if((_c1 && _c2) && (_c1->type == _c2->type)){
+ /* Do not compare names. For example, H264 base profile 1.0 will have the
+ * same name than H264 base profile 3.0. */
+ return tsk_stricmp(_c1->format, _c2->format);
+ }
+ else{
+ return -1;
+ }
+}
+
+/**@ingroup tmedia_codec_group
+* Registers a codec plugin.
+* @param plugin the definition of the plugin.
+* @retval Zero if succeed and non-zero error code otherwise.
+* @sa @ref tmedia_codec_create()
+*/
+int tmedia_codec_plugin_register(const tmedia_codec_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ if(!plugin || tsk_strnullORempty(plugin->name) || tsk_strnullORempty(plugin->format)){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* add or replace the plugin */
+ for(i = 0; i<TMED_CODEC_MAX_PLUGINS; i++){
+ if(!__tmedia_codec_plugins[i] || (__tmedia_codec_plugins[i] == plugin)){
+ __tmedia_codec_plugins[i] = plugin;
+ TSK_DEBUG_INFO("Register codec: %s, %s", plugin->name, plugin->desc);
+ return 0;
+ }
+ if(__tmedia_codec_plugins[i]->codec_id == plugin->codec_id && plugin->codec_id != tmedia_codec_id_none){ // 'tmedia_codec_id_none' is used for fake codecs
+ TSK_DEBUG_INFO("Codec Registration: '%s' ignored because '%s' already registered", plugin->desc, __tmedia_codec_plugins[i]->desc);
+ return -3;
+ }
+ }
+
+ TSK_DEBUG_ERROR("There are already %d plugins.", TMED_CODEC_MAX_PLUGINS);
+ return -2;
+}
+
+int tmedia_codec_plugin_register_2(const tmedia_codec_plugin_def_t* plugin, int prio)
+{
+ tsk_size_t count = 0;
+ tsk_bool_t already_registered = tsk_false;
+ const tmedia_codec_plugin_def_t* tmp;
+ if(!plugin || tsk_strnullORempty(plugin->name) || tsk_strnullORempty(plugin->format) || (prio + 1) >= TMED_CODEC_MAX_PLUGINS){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ // count codecs and found if already registered
+ while(__tmedia_codec_plugins[count]){
+ if(__tmedia_codec_plugins[count] == plugin){
+ already_registered = tsk_true;
+ }
+ ++count;
+ }
+
+ if(count >= TMED_CODEC_MAX_PLUGINS){
+ TSK_DEBUG_ERROR("No room");
+ return -1;
+ }
+
+ // unregister and compact
+ if(already_registered){
+ if(tmedia_codec_plugin_unregister(plugin) == 0){
+ --count;
+ }
+ }
+
+ // put current plugin at prio and old (which was at prio) at the end
+ tmp = __tmedia_codec_plugins[prio];
+ __tmedia_codec_plugins[count] = tmp;// put old codec add prio to the end of the list
+ __tmedia_codec_plugins[prio] = plugin;
+
+ return 0;
+}
+
+/**@ingroup tmedia_codec_group
+ * Checks whether a codec plugin is registered or not.
+ * @param plugin the definition of the plugin to check for availability.
+ * @retval 1 (tsk_true) if registered and 0 (tsk_false) otherwise.
+ * @sa @ref tmedia_codec_plugin_is_registered_2() @ref tmedia_codec_plugin_register() and @ref tmedia_codec_plugin_unregister()
+ */
+tsk_bool_t tmedia_codec_plugin_is_registered(const tmedia_codec_plugin_def_t* plugin)
+{
+ if(plugin){
+ tsk_size_t i;
+ for(i = 0; i < TMED_CODEC_MAX_PLUGINS && __tmedia_codec_plugins[i]; i++){
+ if(__tmedia_codec_plugins[i] == plugin){
+ return tsk_true;
+ }
+ }
+ }
+ return tsk_false;
+}
+
+/**@ingroup tmedia_codec_group
+ * Checks whether a codec is registered or not.
+ * @param codec_id The code id to check.
+ * @return 1 @ref tsk_true if registered and tsk_false otherwise.
+ * @sa @ref tmedia_codec_plugin_is_registered() @ref tmedia_codec_plugin_register() and @ref tmedia_codec_plugin_unregister()
+ */
+tsk_bool_t tmedia_codec_plugin_is_registered_2(tmedia_codec_id_t codec_id)
+{
+ return (tmedia_codec_plugin_registered_get_const(codec_id) != tsk_null);
+}
+
+/**@ingroup tmedia_codec_group
+ * Gets the list of all registered plugins.
+ * @param plugins List of the registered plugins.
+ * @param count Number of plugins in the list.
+ * @return 0 if succeed and non-zero error code otherwise.
+ */
+int tmedia_codec_plugin_registered_get_all(const struct tmedia_codec_plugin_def_s*(** plugins)[TMED_CODEC_MAX_PLUGINS], tsk_size_t* count)
+{
+ if(!plugins || !count) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ *plugins = &__tmedia_codec_plugins;
+ *count = sizeof(__tmedia_codec_plugins)/sizeof(__tmedia_codec_plugins[0]);
+ return 0;
+}
+
+/**@ingroup tmedia_codec_group
+*/
+const struct tmedia_codec_plugin_def_s* tmedia_codec_plugin_registered_get_const(tmedia_codec_id_t codec_id)
+{
+ tsk_size_t i;
+ for(i = 0; i < TMED_CODEC_MAX_PLUGINS && __tmedia_codec_plugins[i]; i++){
+ if(__tmedia_codec_plugins[i]->codec_id == codec_id){
+ return __tmedia_codec_plugins[i];
+ }
+ }
+ return tsk_null;
+}
+
+/**@ingroup tmedia_codec_group
+* UnRegisters a codec plugin.
+* @param plugin the definition of the plugin.
+* @retval 0 if succeed and non-zero error code otherwise.
+*/
+int tmedia_codec_plugin_unregister(const tmedia_codec_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+ if(!plugin){
+ TSK_DEBUG_ERROR("Invalid Parameter");
+ return -1;
+ }
+
+ /* find the plugin to unregister */
+ for(i = 0; i<TMED_CODEC_MAX_PLUGINS && __tmedia_codec_plugins[i]; i++){
+ if(__tmedia_codec_plugins[i] == plugin){
+ TSK_DEBUG_INFO("UnRegister codec: %s, %s", plugin->name, plugin->desc);
+ __tmedia_codec_plugins[i] = tsk_null;
+ found = tsk_true;
+ break;
+ }
+ }
+
+ /* compact */
+ if(found){
+ for(; i<(TMED_CODEC_MAX_PLUGINS - 1); i++){
+ if(__tmedia_codec_plugins[i+1]){
+ __tmedia_codec_plugins[i] = __tmedia_codec_plugins[i+1];
+ }
+ else{
+ break;
+ }
+ }
+ __tmedia_codec_plugins[i] = tsk_null;
+ }
+ return (found ? 0 : -2);
+}
+
+/**@ingroup tmedia_codec_group
+* Unregister all codecs
+* @retval 0 if succeed and non-zero error code otherwise.
+*/
+int tmedia_codec_plugin_unregister_all()
+{
+ memset((void*)__tmedia_codec_plugins, 0, sizeof(__tmedia_codec_plugins));
+ return 0;
+}
+
+/**@ingroup tmedia_codec_group
+* Creates a new codec using an already registered plugin.
+* @param format The format of the codec to create (e.g. "0" for PCMU or "8" for PCMA or "*" for MSRP)
+* @sa @ref tmedia_codec_plugin_register()
+*/
+tmedia_codec_t* tmedia_codec_create(const char* format)
+{
+ tmedia_codec_t* codec = tsk_null;
+ const tmedia_codec_plugin_def_t* plugin;
+ tsk_size_t i = 0;
+
+ while((i < TMED_CODEC_MAX_PLUGINS) && (plugin = __tmedia_codec_plugins[i++])){
+ if(plugin->objdef && tsk_striequals(plugin->format, format)){
+ if((codec = tsk_object_new(plugin->objdef))){
+ /* initialize the newly created codec */
+ codec->id = plugin->codec_id;
+ codec->dyn = plugin->dyn;
+ codec->plugin = plugin;
+ codec->bl = tmedia_bl_medium;
+ switch(plugin->type){
+ case tmedia_audio:
+ { /* Audio codec */
+ tmedia_codec_audio_t* audio = TMEDIA_CODEC_AUDIO(codec);
+ tmedia_codec_audio_init(TMEDIA_CODEC(audio), plugin->name, plugin->desc, plugin->format);
+ break;
+ }
+ case tmedia_video:
+ { /* Video codec */
+ tmedia_codec_video_t* video = TMEDIA_CODEC_VIDEO(codec);
+ tmedia_codec_video_init(TMEDIA_CODEC(video), plugin->name, plugin->desc, plugin->format);
+ break;
+ }
+ case tmedia_msrp:
+ { /* Msrp codec */
+ tmedia_codec_msrp_init(codec, plugin->name, plugin->desc);
+ break;
+ }
+ default:
+ { /* Any other codec */
+ tmedia_codec_init(codec, plugin->type, plugin->name, plugin->desc, plugin->format);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ return codec;
+}
+
+/**@ingroup tmedia_codec_group
+* Gets the rtpmap attribute associated to this code.
+* @param self the codec for which to get the rtpmap attribute. Should be created using @ref tmedia_codec_create().
+* @retval rtpmap string (e.g. "AMR-WB/16000/2" or "H261/90000") if succeed and Null otherwise. It's up to the caller to free the
+* returned string.
+*/
+char* tmedia_codec_get_rtpmap(const tmedia_codec_t* self)
+{
+ char* rtpmap = tsk_null;
+
+ if(!self || !self->plugin){
+ TSK_DEBUG_ERROR("invalid parameter");
+ return tsk_null;
+ }
+ if(self->type & tmedia_video){
+ /* const tmedia_codec_video_t* videoCodec = (const tmedia_codec_video_t*)self; */
+ tsk_sprintf(&rtpmap, "%s %s", self->neg_format? self->neg_format : self->format, self->name);
+ if(self->plugin->rate){
+ tsk_strcat_2(&rtpmap, "/%d", self->plugin->rate);
+ }
+ }
+ else if(self->type & tmedia_audio){
+ /* const tmedia_codec_audio_t* audioCodec = (const tmedia_codec_audio_t*)self; */
+
+ // special case for G.722 which has fake rate
+ if(tsk_strequals(self->plugin->format,TMEDIA_CODEC_FORMAT_G722)){
+ tsk_sprintf(&rtpmap, "%s %s/8000/%d", self->neg_format? self->neg_format : self->format, self->name, self->plugin->audio.channels);
+ }
+ else{
+ tsk_sprintf(&rtpmap, "%s %s", self->neg_format? self->neg_format : self->format, self->name);
+ if(self->plugin->rate){
+ tsk_strcat_2(&rtpmap, "/%d", self->plugin->rate);
+ }
+ if(self->plugin->audio.channels > 0){
+ tsk_strcat_2(&rtpmap, "/%d", self->plugin->audio.channels);
+ }
+ }
+ }
+ else if(self->type & tmedia_t140){
+ tsk_sprintf(&rtpmap, "%s %s", self->neg_format? self->neg_format : self->format, self->name);
+ if(self->plugin->rate){
+ tsk_strcat_2(&rtpmap, "/%d", self->plugin->rate);
+ }
+ }
+ else{
+ }
+
+ return rtpmap;
+}
+
+/**@ingroup tmedia_codec_group
+* Indicates whether the codec can handle this sdp attribute.
+* @param self the codec to match aginst to.
+* @param att_name the name of the sdp attribute to match e.g. 'fmtp' or 'imageattr'
+* @retval @a tsk_true if the codec can handle this fmtp and @a tsk_false otherwise
+*/
+tsk_bool_t tmedia_codec_sdp_att_match(const tmedia_codec_t* self, const char* att_name, const char* att_value)
+{
+ /* checks */
+ if(!self || !self->plugin || !self->plugin->sdp_att_match || !att_name){
+ TSK_DEBUG_ERROR("invalid parameter");
+ return tsk_false;
+ }
+
+ /* if attribute value is null or empty -> always match */
+ if(tsk_strnullORempty(att_value)){
+ return tsk_true;
+ }
+ else{
+ return self->plugin->sdp_att_match(self, att_name, att_value);
+ }
+}
+
+/**@ingroup tmedia_codec_group
+* Gets the codec's sdp attribute value
+* @att_name the name of the attribute to get e.g. 'fmtp' or 'imageattr'
+* @param self the codec for which to get the fmtp attribute. Should be created using @ref tmedia_codec_create().
+* @retval sdp attribute attribute string (e.g. "mode-set=0,2,5,7; mode-change-period=2; mode-change-neighbor=1"). It's up to the caller to free the
+* returned string.
+*/
+char* tmedia_codec_sdp_att_get(const tmedia_codec_t* self, const char* att_name)
+{
+ if(!self || !self->plugin || !att_name){
+ TSK_DEBUG_ERROR("invalid parameter");
+ return tsk_null;
+ }
+ if(self->plugin->sdp_att_get){ /* some codecs, like G711, won't produce fmtp */
+ return self->plugin->sdp_att_get(self, att_name);
+ }
+ return tsk_null;
+}
+
+
+/**@ingroup tmedia_codec_group
+* Remove all codecs except the specified ones.
+* @param codecs the list of codecs from which to remove codecs.
+* @param codecs2keep the codecs which shall not be removed.
+* @retval zero if succeed (or nothing to do) and non-zero error code otherwise.
+*/
+int tmedia_codec_removeAll_exceptThese(tmedia_codecs_L_t* codecs, const tmedia_codecs_L_t * codecs2keep)
+{
+ tsk_list_item_t* item;
+ if(!codecs || !codecs2keep){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+again:
+ tsk_list_foreach(item, codecs){
+ if(!tsk_list_find_item_by_pred(codecs2keep, __pred_find_codec_by_format, ((tmedia_codec_t*)item->data)->format)){
+ tsk_list_remove_item(codecs, item);
+ goto again;
+ }
+ }
+ return 0;
+}
+
+/**@ingroup tmedia_codec_group
+* Serialize a list of codecs to sdp (m= line) message.<br>
+* Will add: fmt, rtpmap and fmtp.
+* @param codecs The list of codecs to convert
+* @param m The destination
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_codec_to_sdp(const tmedia_codecs_L_t* codecs, tsdp_header_M_t* m)
+{
+ const tsk_list_item_t* item;
+ const tmedia_codec_t* codec;
+ char *fmtp, *rtpmap, *imageattr;
+ tsk_bool_t is_audio, is_video, is_text;
+ int ret;
+
+ if(!m){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ is_audio = tsk_striequals(m->media, "audio");
+ is_video = tsk_striequals(m->media, "video");
+ is_text = tsk_striequals(m->media, "text");
+
+ tsk_list_foreach(item, codecs){
+ const char *neg_format;
+ codec = item->data;
+ /* add fmt */
+ neg_format = codec->neg_format? codec->neg_format : codec->format;
+ if((ret = tsdp_header_M_add_fmt(m, neg_format))){
+ TSK_DEBUG_ERROR("Failed to add format");
+ return ret;
+ }
+
+ if(is_audio || is_video || is_text){
+ char* temp = tsk_null;
+ /* add rtpmap attributes */
+ if((rtpmap = tmedia_codec_get_rtpmap(codec))){
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("rtpmap", rtpmap),
+ tsk_null);
+ TSK_FREE(rtpmap);
+ }
+ /* add 'imageattr' attributes */
+ if((imageattr = tmedia_codec_sdp_att_get(codec, "imageattr"))){
+ tsk_sprintf(&temp, "%s %s", neg_format, imageattr);
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("imageattr", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ TSK_FREE(imageattr);
+ }
+ /* add fmtp attributes */
+ if((fmtp = tmedia_codec_sdp_att_get(codec, "fmtp"))){
+ if(is_video && tmedia_defaults_get_screen_x() > 0 && tmedia_defaults_get_screen_y() > 0){
+ tsk_sprintf(&temp, "%s %s;sx=%d;sy=%d", neg_format, fmtp, tmedia_defaults_get_screen_x(), tmedia_defaults_get_screen_y());//doubango clients
+ }
+ else{
+ tsk_sprintf(&temp, "%s %s", neg_format, fmtp);
+ }
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("fmtp", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ TSK_FREE(fmtp);
+ }
+ /* special case for T.140 + red */
+ if(is_text && tsk_striequals(codec->format, TMEDIA_CODEC_FORMAT_RED)){
+ const tmedia_codec_t* codec_t140 = tsk_list_find_object_by_pred(codecs, __pred_find_codec_by_format, TMEDIA_CODEC_FORMAT_T140);
+ if(codec_t140){
+ const char* neg_format_t140 = codec_t140->neg_format? codec_t140->neg_format : codec_t140->format;
+ tsk_sprintf(&temp, "%s %s/%s/%s/%s", neg_format, neg_format_t140, neg_format_t140, neg_format_t140, neg_format_t140);
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("fmtp", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/**@ingroup tmedia_codec_group
+* Finds a codec by format. If the codec has a dyn. payload type, then this function will also compare negociate formats.
+* @param codecs List of codecs from which to retrieve the matching codec.
+* @param format the format of the codec to find.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+tmedia_codec_t* tmedia_codec_find_by_format(tmedia_codecs_L_t* codecs, const char* format)
+{
+ const tmedia_codec_t* codec = tsk_null;
+
+ if(!codecs || !format){
+ TSK_DEBUG_ERROR("Inalid parameter");
+ return tsk_null;
+ }
+
+ if((codec = tsk_list_find_object_by_pred(codecs, __pred_find_codec_by_format, format)) ||
+ (codec = tsk_list_find_object_by_pred(codecs, __pred_find_codec_by_neg_format, format))){
+ return tsk_object_ref((void*)codec);
+ }
+ else{
+ return tsk_null;
+ }
+}
+
+/**@ingroup tmedia_codec_group
+*/
+int tmedia_codec_parse_fmtp(const char* fmtp, unsigned* maxbr, unsigned* fps, unsigned *width, unsigned *height)
+{
+ char *copy, *pch, *saveptr;
+ tsk_bool_t found = tsk_false;
+
+ if(tsk_strnullORempty(fmtp)){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ copy = tsk_strdup(fmtp);
+ pch = tsk_strtok_r(copy, "; /", &saveptr);
+
+ while(pch){
+ unsigned div = 0;
+
+ if(sscanf(pch, "QCIF=%u", &div) == 1 && div){
+ *fps = 30/div;
+ *width = 176;
+ *height = 144;
+ found = tsk_true;
+ }
+ else if(sscanf(pch, "CIF=%u", &div) == 1 && div){
+ *fps = 30/div;
+ *width = 352;
+ *height = 288;
+ found = tsk_true;
+ }
+ else if(sscanf(pch, "SQCIF=%u", &div) == 1 && div){
+ *fps = 30/div;
+ *width = 128;
+ *height = 96;
+ found = tsk_true;
+ }
+ else if(sscanf(pch, "QVGA=%u", &div) == 1 && div){
+ *fps = 30/div;
+ *width = 320;
+ *height = 240;
+ found = tsk_true;
+ }
+ // to be continued
+
+ if(found){
+ //found = tsk_false;
+ pch = tsk_strtok_r(tsk_null, "; ", &saveptr);
+ while(pch){
+ if(sscanf(pch, "MaxBR=%u", maxbr) == 1){
+ //found = tsk_true;
+ break;
+ }
+ pch = tsk_strtok_r(tsk_null, "; /", &saveptr);
+ }
+ }
+
+ if(found){
+ break;
+ }
+
+ pch = tsk_strtok_r(tsk_null, "; /", &saveptr);
+ }
+
+ TSK_FREE(copy);
+
+ return found ? 0 : -2;
+}
+
+/**@ingroup tmedia_codec_group
+* DeInitialize a Codec.
+* @param self The codec to deinitialize. Could be any type of codec (e.g. @ref tmedia_codec_audio_t or @ref tmedia_codec_video_t).
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tmedia_codec_deinit(tmedia_codec_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(self->opened){
+ tmedia_codec_close(self);
+ }
+
+ TSK_FREE(self->name);
+ TSK_FREE(self->desc);
+ TSK_FREE(self->format);
+ TSK_FREE(self->neg_format);
+
+ return 0;
+}
+
+int tmedia_codec_video_set_enc_callback(tmedia_codec_video_t *self, tmedia_codec_video_enc_cb_f callback, const void* callback_data)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->out.callback = callback;
+ self->out.result.usr_data = callback_data;
+ return 0;
+}
+
+int tmedia_codec_video_set_dec_callback(tmedia_codec_video_t *self, tmedia_codec_video_dec_cb_f callback, const void* callback_data)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->in.callback = callback;
+ self->in.result.usr_data = callback_data;
+ return 0;
+}
+
+float tmedia_codec_audio_get_timestamp_multiplier(tmedia_codec_id_t id, uint32_t sample_rate)
+{
+ switch(id){
+ case tmedia_codec_id_opus:
+ {
+ // draft-spittka-payload-rtp-opus-03 - 4.1. RTP Header Usage
+ switch(sample_rate){
+ case 8000: return 6.f;
+ case 12000: return 4.f;
+ case 16000: return 3.f;
+ case 24000: return 2.f;
+ default: case 48000: return 1.f;
+ }
+ break;
+ }
+ case tmedia_codec_id_g722:
+ {
+ /* http://www.ietf.org/rfc/rfc3551.txt
+ Even though the actual sampling rate for G.722 audio is 16,000 Hz,
+ the RTP clock rate for the G722 payload format is 8,000 Hz because
+ that value was erroneously assigned in RFC 1890 and must remain
+ unchanged for backward compatibility. The octet rate or sample-pair
+ rate is 8,000 Hz.
+ */
+ return .5f;
+ }
+ default:
+ {
+ return 1;
+ }
+ }
+} \ No newline at end of file
diff --git a/tinyMEDIA/src/tmedia_codec_dummy.c b/tinyMEDIA/src/tmedia_codec_dummy.c
new file mode 100644
index 0000000..377f629
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_codec_dummy.c
@@ -0,0 +1,369 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_codec_dummy.c
+ * @brief Dummy codecs used for test only.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tinymedia/tmedia_codec_dummy.h"
+
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+//=================================================================================================
+// Dummy G.711u object definition
+//
+
+#define tmedia_codec_dpcmu_sdp_att_get tsk_null
+#define tmedia_codec_dpcmu_fmtp_encode tsk_null
+#define tmedia_codec_dpcmu_fmtp_decode tsk_null
+
+tsk_bool_t tmedia_codec_dpcmu_sdp_att_match(const tmedia_codec_t* codec, const char* att_name, const char* att_value)
+{ /* always match */
+ return tsk_true;
+}
+
+/* constructor */
+static tsk_object_t* tmedia_codec_dpcmu_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_codec_dpcmu_t *dpcmu = self;
+ if(dpcmu){
+ /* init base: called by tmedia_codec_create() */
+ /* init self */
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* tmedia_codec_dpcmu_dtor(tsk_object_t * self)
+{
+ tmedia_codec_dpcmu_t *dpcmu = self;
+ if(dpcmu){
+ /* deinit base */
+ tmedia_codec_audio_deinit(dpcmu);
+ /* deinit self */
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t tmedia_codec_dpcmu_def_s =
+{
+ sizeof(tmedia_codec_dpcmu_t),
+ tmedia_codec_dpcmu_ctor,
+ tmedia_codec_dpcmu_dtor,
+ tmedia_codec_cmp,
+};
+/* plugin definition*/
+static const tmedia_codec_plugin_def_t tmedia_codec_dpcmu_plugin_def_s =
+{
+ &tmedia_codec_dpcmu_def_s,
+
+ tmedia_audio,
+ tmedia_codec_id_pcmu,
+ "G.711u",
+ "Dummy G.711u codec",
+ TMEDIA_CODEC_FORMAT_G711u,
+ tsk_false,
+ 8000, // rate
+
+ { /* audio */
+ 1, // channels
+ 20 // ptime
+ },
+
+ /* video */
+ {0},
+
+ tsk_null, // set()
+ tsk_null, // open
+ tsk_null, // close
+ tmedia_codec_dpcmu_fmtp_encode,
+ tmedia_codec_dpcmu_fmtp_decode,
+ tmedia_codec_dpcmu_sdp_att_match,
+ tmedia_codec_dpcmu_sdp_att_get,
+};
+const tmedia_codec_plugin_def_t *tmedia_codec_dpcmu_plugin_def_t = &tmedia_codec_dpcmu_plugin_def_s;
+
+//=================================================================================================
+// Dummy G.711a object definition
+//
+
+#define tmedia_codec_dpcma_sdp_att_get tsk_null
+#define tmedia_codec_dpcma_fmtp_set tsk_null
+#define tmedia_codec_dpcma_fmtp_encode tsk_null
+#define tmedia_codec_dpcma_fmtp_decode tsk_null
+
+tsk_bool_t tmedia_codec_dpcma_sdp_att_match(const tmedia_codec_t* codec, const char* att_name, const char* att_value)
+{ /* always match */
+ return tsk_true;
+}
+
+/* constructor */
+static tsk_object_t* tmedia_codec_dpcma_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_codec_dpcma_t *dpcma = self;
+ if(dpcma){
+ /* init base: called by tmedia_codec_create() */
+ /* init self */
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* tmedia_codec_dpcma_dtor(tsk_object_t * self)
+{
+ tmedia_codec_dpcma_t *dpcma = self;
+ if(dpcma){
+ /* deinit base */
+ tmedia_codec_audio_deinit(dpcma);
+ /* deinit self */
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t tmedia_codec_dpcma_def_s =
+{
+ sizeof(tmedia_codec_dpcma_t),
+ tmedia_codec_dpcma_ctor,
+ tmedia_codec_dpcma_dtor,
+ tmedia_codec_cmp,
+};
+/* plugin definition*/
+static const tmedia_codec_plugin_def_t tmedia_codec_dpcma_plugin_def_s =
+{
+ &tmedia_codec_dpcma_def_s,
+
+ tmedia_audio,
+ tmedia_codec_id_pcma,
+ "G.711a",
+ "Dummy G.711a codec",
+ TMEDIA_CODEC_FORMAT_G711a,
+ tsk_false,
+ 8000, // rate
+
+ { /* audio */
+ 1, // channels
+ 20 // ptime
+ },
+
+ /* video */
+ {0},
+
+ tsk_null, // set()
+ tsk_null, // open
+ tsk_null, // close
+ tmedia_codec_dpcma_fmtp_encode,
+ tmedia_codec_dpcma_fmtp_decode,
+ tmedia_codec_dpcma_sdp_att_match,
+ tmedia_codec_dpcma_sdp_att_get
+};
+const tmedia_codec_plugin_def_t *tmedia_codec_dpcma_plugin_def_t = &tmedia_codec_dpcma_plugin_def_s;
+
+
+
+//=================================================================================================
+// Dummy H.263 object definition
+//
+
+tsk_size_t tmedia_codec_dh263_fmtp_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size)
+{
+ return 0;
+}
+
+tsk_size_t tmedia_codec_dh263_fmtp_decode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size, const tsk_object_t* proto_hdr)
+{
+ return 0;
+}
+
+tsk_bool_t tmedia_codec_dh263_sdp_att_match(const tmedia_codec_t* codec, const char* att_name, const char* att_value)
+{
+ /* check whether we can match this fmtp with our local
+ * check size, maxbr, fps ...*/
+ return tsk_true;
+}
+
+char* tmedia_codec_dh263_sdp_att_get(const tmedia_codec_t* codec, const char* att_name)
+{
+ return tsk_strdup("CIF=2/MaxBR=3840;QCIF=2/MaxBR=1920");
+}
+
+int tmedia_codec_dh263_fmtp_set(tmedia_codec_t* self, const char* fmtp)
+{
+ TSK_DEBUG_INFO("remote fmtp=%s", fmtp);
+ return 0;
+}
+
+/* constructor */
+static tsk_object_t* tmedia_codec_dh263_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_codec_dh263_t *dh263 = self;
+ if(dh263){
+ /* init base: called by tmedia_codec_create() */
+ /* init self */
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* tmedia_codec_dh263_dtor(tsk_object_t * self)
+{
+ tmedia_codec_dh263_t *dh263 = self;
+ if(dh263){
+ /* deinit base */
+ tmedia_codec_video_deinit(dh263);
+ /* deinit self */
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t tmedia_codec_dh263_def_s =
+{
+ sizeof(tmedia_codec_dh263_t),
+ tmedia_codec_dh263_ctor,
+ tmedia_codec_dh263_dtor,
+ tmedia_codec_cmp,
+};
+/* plugin definition*/
+static const tmedia_codec_plugin_def_t tmedia_codec_dh263_plugin_def_s =
+{
+ &tmedia_codec_dh263_def_s,
+
+ tmedia_video,
+ tmedia_codec_id_h263,
+ "H263",
+ "Dummy H.263-1996 codec",
+ TMEDIA_CODEC_FORMAT_H263,
+ tsk_false,
+ 90000, // rate
+
+ /* audio */
+ { 0 },
+
+ /* video */
+ {176, 144},
+
+ tsk_null, // set()
+ tsk_null, // open
+ tsk_null, // close
+ tmedia_codec_dh263_fmtp_encode,
+ tmedia_codec_dh263_fmtp_decode,
+ tmedia_codec_dh263_sdp_att_match,
+ tmedia_codec_dh263_sdp_att_get
+};
+const tmedia_codec_plugin_def_t *tmedia_codec_dh263_plugin_def_t = &tmedia_codec_dh263_plugin_def_s;
+
+
+
+
+//=================================================================================================
+// Dummy H.264 (Base profile 10) object definition
+//
+
+tsk_size_t tmedia_codec_dh264_fmtp_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size)
+{
+ return 0;
+}
+
+tsk_size_t tmedia_codec_dh264_fmtp_decode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size, const tsk_object_t* proto_hdr)
+{
+ return 0;
+}
+
+tsk_bool_t tmedia_codec_dh264_sdp_att_match(const tmedia_codec_t* codec, const char* att_name, const char* att_value)
+{
+ /* check whether we can match this fmtp with our local
+ * check size, maxbr, fps, profile-level-id, packetization-mode ...*/
+ return tsk_true;
+}
+
+char* tmedia_codec_dh264_sdp_att_get(const tmedia_codec_t* codec, const char* att_name)
+{
+ return tsk_strdup("profile-level-id=42A01E;sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==");
+}
+
+int tmedia_codec_dh264_fmtp_set(tmedia_codec_t* self, const char* fmtp)
+{
+ TSK_DEBUG_INFO("remote fmtp=%s", fmtp);
+ return 0;
+}
+
+/* constructor */
+static tsk_object_t* tmedia_codec_dh264_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_codec_dh264_t *dh264 = self;
+ if(dh264){
+ /* init base: called by tmedia_codec_create() */
+ /* init self */
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* tmedia_codec_dh264_dtor(tsk_object_t * self)
+{
+ tmedia_codec_dh264_t *dh264 = self;
+ if(dh264){
+ /* deinit base */
+ tmedia_codec_video_deinit(dh264);
+ /* deinit self */
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t tmedia_codec_dh264_def_s =
+{
+ sizeof(tmedia_codec_dh264_t),
+ tmedia_codec_dh264_ctor,
+ tmedia_codec_dh264_dtor,
+ tmedia_codec_cmp,
+};
+/* plugin definition*/
+static const tmedia_codec_plugin_def_t tmedia_codec_dh264_plugin_def_s =
+{
+ &tmedia_codec_dh264_def_s,
+
+ tmedia_video,
+ tmedia_codec_id_h264_bp,
+ "H264",
+ "Dummy H.264 (base profile 10) codec",
+ TMEDIA_CODEC_FORMAT_H264_BP,
+ tsk_true,
+ 90000, // rate
+
+ /* audio */
+ { 0 },
+
+ /* video */
+ {176, 144},
+
+ tsk_null, // set()
+ tsk_null, // open
+ tsk_null, // close
+ tmedia_codec_dh264_fmtp_encode,
+ tmedia_codec_dh264_fmtp_decode,
+ tmedia_codec_dh264_sdp_att_match,
+ tmedia_codec_dh264_sdp_att_get
+};
+const tmedia_codec_plugin_def_t *tmedia_codec_dh264_plugin_def_t = &tmedia_codec_dh264_plugin_def_s;
diff --git a/tinyMEDIA/src/tmedia_common.c b/tinyMEDIA/src/tmedia_common.c
new file mode 100644
index 0000000..1e9faef
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_common.c
@@ -0,0 +1,442 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_common.c
+ * @brief Common functions and definitions.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tinymedia/tmedia_common.h"
+
+#include "tinymedia/tmedia_consumer.h"
+#include "tinymedia/tmedia_producer.h"
+#include "tinymedia/tmedia_session.h"
+#include "tinymedia/tmedia_converter_video.h"
+#include "tinymedia/tmedia_resampler.h"
+#include "tinymedia/tmedia_denoise.h"
+#include "tinymedia/tmedia_imageattr.h"
+#include "tinymedia/tmedia_defaults.h"
+
+#include "tsk_params.h"
+#include "tsk_debug.h"
+
+#include <stdlib.h> /* atoi() */
+
+typedef struct fmtp_size_s{
+ const char* name;
+ tmedia_pref_video_size_t pref_vs;
+ tsk_bool_t cif_family;
+ unsigned width;
+ unsigned height;
+}fmtp_size_t;
+static const fmtp_size_t fmtp_sizes[] =
+{
+ /* must be sorted like this */
+ {"2160P", tmedia_pref_video_size_2160p, tsk_false, 3840, 2160},
+ {"1080P", tmedia_pref_video_size_1080p, tsk_false, 1920, 1080},
+ {"16CIF", tmedia_pref_video_size_16cif, tsk_true, 1408, 1152},
+ {"720P", tmedia_pref_video_size_720p, tsk_false, 1280, 720},
+ {"XGA", tmedia_pref_video_size_xga, tsk_false, 1024, 768},
+ {"480P", tmedia_pref_video_size_480p, tsk_false, 852, 480},
+ {"WVGA", tmedia_pref_video_size_wvga, tsk_false, 800, 480},
+ {"SVGA", tmedia_pref_video_size_svga, tsk_false, 800, 600},
+ {"4CIF", tmedia_pref_video_size_4cif, tsk_true, 704, 576},
+ {"VGA", tmedia_pref_video_size_vga, tsk_false, 640, 480},
+ {"HVGA", tmedia_pref_video_size_hvga, tsk_false, 480, 320},
+ {"CIF", tmedia_pref_video_size_cif, tsk_true, 352, 288},
+ {"QVGA", tmedia_pref_video_size_qvga, tsk_false, 320, 240},
+ {"QCIF", tmedia_pref_video_size_qcif, tsk_true, 176, 144},
+ {"SQCIF", tmedia_pref_video_size_sqcif, tsk_true, 128, 96}
+};
+
+typedef int (*plugin_register)(const void* plugin_def);
+typedef int (*plugin_unregister)(const void* plugin_def);
+
+typedef struct plugin_decl_s
+{
+ tsk_plugin_def_type_t type;
+ plugin_register fn_register;
+ plugin_unregister fn_unregister;
+}
+plugin_decl_t;
+
+static const struct plugin_decl_s __plugin_def_types[] =
+{
+ {tsk_plugin_def_type_consumer, tmedia_consumer_plugin_register, tmedia_consumer_plugin_unregister },
+ {tsk_plugin_def_type_producer, tmedia_producer_plugin_register, tmedia_producer_plugin_unregister },
+ {tsk_plugin_def_type_session, tmedia_session_plugin_register, tmedia_session_plugin_unregister },
+ {tsk_plugin_def_type_codec, tmedia_codec_plugin_register, tmedia_codec_plugin_unregister },
+ {tsk_plugin_def_type_converter, tmedia_converter_video_plugin_register, tmedia_converter_video_plugin_unregister },
+ {tsk_plugin_def_type_resampler, tmedia_resampler_plugin_register, tmedia_resampler_plugin_unregister },
+ {tsk_plugin_def_type_denoiser, tmedia_denoise_plugin_register, tmedia_denoise_plugin_unregister },
+};
+static const tsk_size_t __plugin_def_types_count = sizeof(__plugin_def_types)/sizeof(__plugin_def_types[0]);
+static const tsk_plugin_def_media_type_t __plugin_def_media_types[] =
+{
+ tsk_plugin_def_media_type_audio,
+ tsk_plugin_def_media_type_video,
+ tsk_plugin_def_media_type_screencast
+};
+static const tsk_size_t __plugin_def_media_types_count = sizeof(__plugin_def_media_types)/sizeof(__plugin_def_media_types[0]);
+
+static tsk_size_t _tmedia_plugin_register_or_unregister(struct tsk_plugin_s* plugin, enum tsk_plugin_def_type_e type, enum tsk_plugin_def_media_type_e media, tsk_bool_t _register)
+{
+ tsk_size_t ret = 0, i, j, index;
+ tsk_plugin_def_ptr_const_t plugin_def_ptr_const;
+ if(!plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return 0;
+ }
+
+ for(i = 0; i < __plugin_def_types_count; ++i){
+ for(j = 0; j < __plugin_def_media_types_count; ++j){
+ if((_register ? __plugin_def_types[i].fn_register : __plugin_def_types[i].fn_unregister) && (type & __plugin_def_types[i].type) == __plugin_def_types[i].type && (media & __plugin_def_media_types[j]) == __plugin_def_media_types[j]){
+ for(index = 0; (plugin_def_ptr_const = tsk_plugin_get_def_2(plugin, __plugin_def_types[i].type, __plugin_def_media_types[j], index)); ++index){
+ if((_register ? __plugin_def_types[i].fn_register : __plugin_def_types[i].fn_unregister)(plugin_def_ptr_const) == 0){
+ ++ret;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+tsk_size_t tmedia_plugin_register(struct tsk_plugin_s* plugin, enum tsk_plugin_def_type_e type, enum tsk_plugin_def_media_type_e media)
+{
+ return _tmedia_plugin_register_or_unregister(plugin, type, media, tsk_true);
+}
+
+tsk_size_t tmedia_plugin_unregister(struct tsk_plugin_s* plugin, enum tsk_plugin_def_type_e type, enum tsk_plugin_def_media_type_e media)
+{
+ return _tmedia_plugin_register_or_unregister(plugin, type, media, tsk_false);
+}
+
+tmedia_type_t tmedia_type_from_sdp(const tsdp_message_t* sdp)
+{
+ tmedia_type_t type = tmedia_none;
+ const tsdp_header_M_t* M;
+ tsk_size_t index = 0;
+
+ if (!sdp) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tmedia_none;
+ }
+
+ while ((M = (const tsdp_header_M_t*)tsdp_message_get_headerAt(sdp, tsdp_htype_M, index++))) {
+ type |= tmedia_type_from_sdp_headerM(M);
+ }
+ return type;
+}
+
+tmedia_type_t tmedia_type_from_sdp_headerM(const tsdp_header_M_t* M)
+{
+ const tmedia_session_plugin_def_t* plugin;
+ const tsdp_header_A_t* A;
+ if (!M) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tmedia_none;
+ }
+ if (M->port && (plugin = tmedia_session_plugin_find_by_media(M->media))) {
+ if (plugin->type == tmedia_audio || plugin->type == tmedia_video) {
+ // check if it's BFCP audio/video session
+ // content attribute described in http://tools.ietf.org/html/rfc4796
+ if ((A = tsdp_header_M_findA(M, "content")) && (!tsk_striequals(A->value, "main"))) {
+ return plugin->type == tmedia_audio ? tmedia_bfcp_audio : tmedia_bfcp_video;
+ }
+ }
+ return plugin->type;
+ }
+ return tmedia_none;
+}
+
+
+int tmedia_parse_rtpmap(const char* rtpmap, char** name, int32_t* rate, int32_t* channels)
+{
+ /* e.g. AMR-WB/16000/2 */
+
+ int len;
+ int index, pos = 0;
+
+ if(tsk_strnullORempty(rtpmap)){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ *name = tsk_null;
+ *rate = *channels = 0;
+ len = (int)tsk_strlen(rtpmap);
+
+ /* name */
+ if((index = tsk_strindexOf(rtpmap, len, "/")) != -1){
+ *name = tsk_strndup(rtpmap, index);
+ len -= (index + 1), pos = (index + 1);
+ /* rate */
+ if(len>0){
+ if((index = tsk_strindexOf((rtpmap + pos), len, "/")) != -1){
+ *rate = atoi(&rtpmap[pos]);
+ len -= (index + 1), pos += (index + 1);
+ /* channels */
+ if(len>0){
+ *channels = atoi(&rtpmap[pos]);
+ }
+ }
+ else{
+ *rate = atoi(&rtpmap[pos]);
+ }
+ }
+ }
+ else{
+ *name = tsk_strdup(rtpmap);
+ }
+
+ return 0;
+
+ ///* e.g. AMR-WB/16000/2 */
+ //if(sscanf(rtpmap, "%*s/%*d/%*d") != EOF){
+ // int index = tsk_strindexOf(rtpmap, len, "/");
+ // *name = tsk_strndup(rtpmap, index);
+ // sscanf(&rtpmap[index+1], "%d/%d", rate, channels);
+ // return 0;
+ //}
+ ///* e.g. AMR-WB/16000 */
+ //else if(sscanf(rtpmap, "%*s/%*d") != EOF){
+ // int index = tsk_strindexOf(rtpmap, len, "/");
+ // *name = tsk_strndup(rtpmap, index);
+ // *rate = atoi(&rtpmap[index+1]);
+ // return 0;
+ //}
+ ///* e.g. AMR-WB */
+ //else if(sscanf(rtpmap, "%*s") != EOF){
+ // *name = tsk_strdup(rtpmap);
+ // return 0;
+ //}
+ //else{
+ // TSK_DEBUG_ERROR("%s is not a valid rtpmap value", rtpmap);
+ // return -2;
+ //}
+}
+
+int tmedia_video_get_size(tmedia_pref_video_size_t pref_vs, unsigned *width, unsigned *height)
+{
+ int i;
+ for(i=0; i<sizeof(fmtp_sizes)/sizeof(fmtp_sizes[0]); i++){
+ if(fmtp_sizes[i].pref_vs == pref_vs){
+ if(width) *width = fmtp_sizes[i].width;
+ if(height) *height = fmtp_sizes[i].height;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int tmedia_video_get_closest_cif_size(tmedia_pref_video_size_t pref_vs, tmedia_pref_video_size_t *cif_vs)
+{
+ int i;
+ if(!cif_vs){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ for(i=0; i<sizeof(fmtp_sizes)/sizeof(fmtp_sizes[0]); i++){
+ if(fmtp_sizes[i].pref_vs <= pref_vs && fmtp_sizes[i].cif_family){
+ *cif_vs = fmtp_sizes[i].pref_vs;
+ return 0;
+ }
+ }
+ return -2;
+}
+
+int tmedia_video_get_closest_pref_size(unsigned width, unsigned height, tmedia_pref_video_size_t *pref_vs)
+{
+ int i;
+ unsigned size;
+ if (!pref_vs){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ size = width * height;
+ for (i = 0; i<sizeof(fmtp_sizes) / sizeof(fmtp_sizes[0]); i++){
+ if (size >= fmtp_sizes[i].height * fmtp_sizes[i].width){
+ *pref_vs = fmtp_sizes[i].pref_vs;
+ return 0;
+ }
+ }
+ return -2;
+}
+
+int tmedia_parse_video_fmtp(const char* fmtp, tmedia_pref_video_size_t pref_vs, unsigned* width, unsigned* height, unsigned* fps)
+{
+ int ret = -2;
+ tsk_params_L_t* params = tsk_null;
+ const tsk_param_t* param = tsk_null;
+ const tsk_list_item_t* item;
+ int i;
+ tmedia_pref_video_size_t best_vs;
+
+ if(!fmtp || !width || !height || !fps){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ // set default values
+ best_vs = fmtp_sizes[(sizeof(fmtp_sizes)/sizeof(fmtp_sizes[0])) - 1].pref_vs /* last = lowest resolution */;
+ ret = tmedia_video_get_size(pref_vs, width, height);
+ *fps = 15;
+
+ if((params = tsk_params_fromstring(fmtp, ";", tsk_true))){
+ // set real values
+ tsk_list_foreach(item, params){
+ if(!(param = TSK_PARAM(item->data)) || !param->name || !param->value){
+ continue;
+ }
+ for(i=0; i<sizeof(fmtp_sizes)/sizeof(fmtp_sizes[0]); i++){
+ if((int)pref_vs >= (int)fmtp_sizes[i].pref_vs && tsk_striequals(fmtp_sizes[i].name, param->name) && ((int)best_vs <= (int)fmtp_sizes[i].pref_vs)){
+ *width= fmtp_sizes[i].width;
+ *height = fmtp_sizes[i].height;
+ *fps = atoi(param->value);
+ *fps = *fps ? 30/(*fps) : 15;
+ ret = 0;
+ best_vs = fmtp_sizes[i].pref_vs;
+ // rfc 4629 section 8.2.1: Parameters offered first are the most preferred picture mode to be received.
+ // /!\ asterisk do not respect this :)
+ /* goto done */;
+ }
+ }
+ }
+/* done: */
+ TSK_OBJECT_SAFE_FREE(params);
+ }
+
+ return ret;
+}
+
+static void _imageattr_get_best_size(const tmedia_imageattr_set_xt* set, xyvalue_t *width, xyvalue_t *height)
+{
+ tsk_size_t i;
+ if(set->xrange.is_range){
+ *width = TSK_MIN(set->xrange.range.end, *width);
+ }
+ else{
+ for(i = 0; i < set->xrange.array.count; ++i){
+ *width = TSK_MIN(set->xrange.array.values[i], *width);
+ }
+ }
+ if(set->yrange.is_range){
+ *height = TSK_MIN(set->yrange.range.end, *height);
+ }
+ else{
+ for(i = 0; i < set->yrange.array.count; ++i){
+ *height = TSK_MIN(set->yrange.array.values[i], *height);
+ }
+ }
+}
+
+int tmedia_parse_video_imageattr(const char* imageattr, tmedia_pref_video_size_t pref_vs, unsigned* in_width, unsigned* in_height, unsigned* out_width, unsigned* out_height)
+{
+ tmedia_imageattr_xt attr;
+ int ret;
+ tsk_size_t i;
+
+ if(!imageattr || !in_width || !in_height || !out_width || !out_height){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ // set default values
+ ret = tmedia_video_get_size(pref_vs, in_width, in_height);
+ if(ret != 0){
+ TSK_DEBUG_ERROR("tmedia_video_get_size() failed with error code=%d", ret);
+ return ret;
+ }
+ *out_width = *in_width, *out_height = *in_height;
+
+ if((ret = tmedia_imageattr_parse(&attr, imageattr, (tsk_size_t)tsk_strlen(imageattr)))){
+ TSK_DEBUG_ERROR("Failed to parse");
+ return 0; // use default values
+ }
+
+
+ for(i = 0; i < attr.send.count; ++i) _imageattr_get_best_size(&attr.send.sets[i], (xyvalue_t*)out_width, (xyvalue_t*)out_height);
+ for(i = 0; i < attr.recv.count; ++i) _imageattr_get_best_size(&attr.recv.sets[i], (xyvalue_t*)in_width, (xyvalue_t*)in_height);
+
+ return 0;
+}
+
+char* tmedia_get_video_fmtp(tmedia_pref_video_size_t pref_vs)
+{
+ tsk_size_t i;
+ char* fmtp = tsk_null;
+
+
+ for(i = 0; i < sizeof(fmtp_sizes)/sizeof(fmtp_sizes[0]); ++i){
+ if(fmtp_sizes[i].cif_family && fmtp_sizes[i].pref_vs <= pref_vs){
+ if(!fmtp) tsk_strcat_2(&fmtp, "%s=2", fmtp_sizes[i].name);
+ else tsk_strcat_2(&fmtp, ";%s=2", fmtp_sizes[i].name);
+ }
+ }
+ return fmtp;
+}
+
+char* tmedia_get_video_imageattr(tmedia_pref_video_size_t pref_vs, unsigned in_width, unsigned in_height, unsigned out_width, unsigned out_height)
+{
+ unsigned width, height;
+ const fmtp_size_t* size_min = &fmtp_sizes[(sizeof(fmtp_sizes) / sizeof(fmtp_sizes[0]))-1];
+ char* ret = tsk_null;
+ if(tmedia_video_get_size(pref_vs, &width, &height) == 0){
+ tsk_sprintf(&ret, "recv [x=[%u:16:%u],y=[%u:16:%u]] send [x=[%u:16:%u],y=[%u:16:%u]]",
+ size_min->width, in_width, size_min->height, in_height,
+ size_min->width, out_width, size_min->height, out_height);
+ }
+ return ret;
+}
+
+
+// #retval: 1(best)-31(worst) */
+int tmedia_get_video_quality(tmedia_bandwidth_level_t bl)
+{
+ switch(bl){
+ case tmedia_bl_low:
+ default: return 13;
+ case tmedia_bl_medium: return 9;
+ case tmedia_bl_hight: return 5;
+ case tmedia_bl_unrestricted: return 1;
+ }
+}
+
+int32_t tmedia_get_video_bandwidth_kbps(unsigned width, unsigned height, unsigned fps, unsigned motion_rank)
+{
+ return (int32_t)((width * height * fps * motion_rank * 0.07) / 1024);
+}
+
+int32_t tmedia_get_video_bandwidth_kbps_2(unsigned width, unsigned height, unsigned fps)
+{
+ return tmedia_get_video_bandwidth_kbps(width, height, fps, tmedia_defaults_get_video_motion_rank());
+}
+int32_t tmedia_get_video_bandwidth_kbps_3()
+{
+ unsigned width = 3840;
+ unsigned height = 2160;
+ tmedia_video_get_size(tmedia_defaults_get_pref_video_size(), &width, &height);
+ return tmedia_get_video_bandwidth_kbps(width, height, tmedia_defaults_get_video_fps(), tmedia_defaults_get_video_motion_rank());
+} \ No newline at end of file
diff --git a/tinyMEDIA/src/tmedia_consumer.c b/tinyMEDIA/src/tmedia_consumer.c
new file mode 100644
index 0000000..215a959
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_consumer.c
@@ -0,0 +1,288 @@
+/*
+* Copyright (C) 2010-2014 Mamadou DIOP
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tmedia_consumer.c
+ * @brief Base consumer object.
+ */
+#include "tinymedia/tmedia_consumer.h"
+#include "tinymedia/tmedia_defaults.h"
+
+#include "tsk_debug.h"
+
+
+/**@defgroup tmedia_consumer_group Producers
+*/
+
+/* pointer to all registered consumers */
+static const tmedia_consumer_plugin_def_t* __tmedia_consumer_plugins[TMED_CONSUMER_MAX_PLUGINS] = {0};
+
+/**@ingroup tmedia_consumer_group
+* Initialize the consumer.
+* @param self The consumer to initialize
+* @retval Zero if succeed and non-zero error code otherwise.
+*
+* @sa @ref tmedia_consumer_deinit
+*/
+int tmedia_consumer_init(tmedia_consumer_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ self->video.in.chroma = TMEDIA_CONSUMER_CHROMA_DEFAULT;
+ self->video.display.chroma = TMEDIA_CONSUMER_CHROMA_DEFAULT;
+
+ self->audio.bits_per_sample = TMEDIA_CONSUMER_BITS_PER_SAMPLE_DEFAULT;
+ self->audio.ptime = tmedia_defaults_get_audio_ptime();
+ self->audio.volume = tmedia_defaults_get_volume();
+
+ return 0;
+}
+
+/**@ingroup tmedia_consumer_group
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_consumer_set(tmedia_consumer_t *self, const tmedia_param_t* param)
+{
+ if(!self || !self->plugin || !self->plugin->set || !param){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return self->plugin->set(self, param);
+}
+
+/**@ingroup tmedia_consumer_group
+* Alert the consumer to be prepared to start.
+* @param self the consumer to prepare
+* @param codec Negociated codec
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_consumer_prepare(tmedia_consumer_t *self, const tmedia_codec_t* codec)
+{
+ int ret;
+ if(!self || !self->plugin || !self->plugin->prepare || !codec){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if((ret = self->plugin->prepare(self, codec)) == 0){
+ self->is_prepared = tsk_true;
+ }
+ return ret;
+}
+
+/**@ingroup tmedia_consumer_group
+* Starts the consumer
+* @param self The consumer to start
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_consumer_start(tmedia_consumer_t *self)
+{
+ int ret;
+ if (!self || !self->plugin || !self->plugin->start) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if ((ret = self->plugin->start(self)) == 0) {
+ self->is_started = tsk_true;
+ }
+ return ret;
+}
+
+/**@ingroup tmedia_consumer_group
+* Consumes data
+* @param self The consumer
+* @param buffer Pointer to the data to consume
+* @param size Size of the data to consume
+*/
+int tmedia_consumer_consume(tmedia_consumer_t* self, const void* buffer, tsk_size_t size, const tsk_object_t* proto_hdr)
+{
+ if(!self || !self->plugin || !self->plugin->consume){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return self->plugin->consume(self, buffer, size, proto_hdr);
+}
+
+/**@ingroup tmedia_consumer_group
+* Pauses the consumer
+* @param self The consumer to pause
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_consumer_pause(tmedia_consumer_t *self)
+{
+ if(!self || !self->plugin || !self->plugin->pause){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return self->plugin->pause(self);
+}
+
+
+/**@ingroup tmedia_consumer_group
+* Stops the consumer
+* @param self The consumer to stop
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_consumer_stop(tmedia_consumer_t *self)
+{
+ int ret;
+ if (!self || !self->plugin || !self->plugin->stop) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if ((ret = self->plugin->stop(self)) == 0) {
+ self->is_started = tsk_false;
+ }
+ return ret;
+}
+
+
+/**@ingroup tmedia_consumer_group
+* DeInitialize the consumer.
+* @param self The consumer to deinitialize
+* @retval Zero if succeed and non-zero error code otherwise.
+*
+* @sa @ref tmedia_consumer_deinit
+*/
+int tmedia_consumer_deinit(tmedia_consumer_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return 0;
+}
+
+/**@ingroup tmedia_consumer_group
+* Creates a new consumer using an already registered plugin.
+* @param type The type of the consumer to create
+* @param session_id
+* @sa @ref tmedia_consumer_plugin_register()
+*/
+tmedia_consumer_t* tmedia_consumer_create(tmedia_type_t type, uint64_t session_id)
+{
+ tmedia_consumer_t* consumer = tsk_null;
+ const tmedia_consumer_plugin_def_t* plugin;
+ tsk_size_t i = 0;
+
+ while((i < TMED_CONSUMER_MAX_PLUGINS) && (plugin = __tmedia_consumer_plugins[i++])){
+ if(plugin->objdef && plugin->type == type){
+ if((consumer = tsk_object_new(plugin->objdef))){
+ /* initialize the newly created consumer */
+ consumer->plugin = plugin;
+ consumer->session_id = session_id;
+ break;
+ }
+ }
+ }
+
+ return consumer;
+}
+
+/**@ingroup tmedia_consumer_group
+* Registers a consumer plugin.
+* @param plugin the definition of the plugin.
+* @retval Zero if succeed and non-zero error code otherwise.
+* @sa @ref tmedia_consumer_create()
+*/
+int tmedia_consumer_plugin_register(const tmedia_consumer_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ if(!plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* add or replace the plugin */
+ for(i = 0; i<TMED_CONSUMER_MAX_PLUGINS; i++){
+ if(!__tmedia_consumer_plugins[i] || (__tmedia_consumer_plugins[i] == plugin)){
+ __tmedia_consumer_plugins[i] = plugin;
+ return 0;
+ }
+ }
+
+ TSK_DEBUG_ERROR("There are already %d plugins.", TMED_CONSUMER_MAX_PLUGINS);
+ return -2;
+}
+
+/**@ingroup tmedia_consumer_group
+* UnRegisters a consumer plugin.
+* @param plugin the definition of the plugin.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tmedia_consumer_plugin_unregister(const tmedia_consumer_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+ if(!plugin){
+ TSK_DEBUG_ERROR("Invalid Parameter");
+ return -1;
+ }
+
+ /* find the plugin to unregister */
+ for(i = 0; i<TMED_CONSUMER_MAX_PLUGINS && __tmedia_consumer_plugins[i]; i++){
+ if(__tmedia_consumer_plugins[i] == plugin){
+ __tmedia_consumer_plugins[i] = tsk_null;
+ found = tsk_true;
+ break;
+ }
+ }
+
+ /* compact */
+ if(found){
+ for(; i<(TMED_CONSUMER_MAX_PLUGINS - 1); i++){
+ if(__tmedia_consumer_plugins[i+1]){
+ __tmedia_consumer_plugins[i] = __tmedia_consumer_plugins[i+1];
+ }
+ else{
+ break;
+ }
+ }
+ __tmedia_consumer_plugins[i] = tsk_null;
+ }
+ return (found ? 0 : -2);
+}
+
+/**@ingroup tmedia_consumer_group
+* UnRegisters all consumers matching the given type.
+* @param type the type of the consumers to unregister (e.g. audio|video).
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tmedia_consumer_plugin_unregister_by_type(tmedia_type_t type)
+{
+ int i, j;
+
+ /* find the plugin to unregister */
+ for (i = 0; i < TMED_CONSUMER_MAX_PLUGINS && __tmedia_consumer_plugins[i]; ) {
+ if ((__tmedia_consumer_plugins[i]->type & type) == __tmedia_consumer_plugins[i]->type) {
+ __tmedia_consumer_plugins[i] = tsk_null;
+ /* compact */
+ for (j = i; j < (TMED_CONSUMER_MAX_PLUGINS - 1) && __tmedia_consumer_plugins[j + 1]; ++j) {
+ __tmedia_consumer_plugins[j] = __tmedia_consumer_plugins[j + 1];
+ }
+ __tmedia_consumer_plugins[j] = tsk_null;
+ }
+ else {
+ ++i;
+ }
+ }
+ return 0;
+}
diff --git a/tinyMEDIA/src/tmedia_converter_video.c b/tinyMEDIA/src/tmedia_converter_video.c
new file mode 100644
index 0000000..27cc252
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_converter_video.c
@@ -0,0 +1,126 @@
+/*
+* Copyright (C) 2012 Doubango Telecom <http://www.doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tmedia_converter_video.c
+ * @brief Video converter plugin (chroma, rotation, scaling, ...)
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+ */
+#include "tinymedia/tmedia_converter_video.h"
+
+#include "tsk_debug.h"
+
+/* pointer to all registered converter_videos */
+static const tmedia_converter_video_plugin_def_t* __tmedia_converter_video_plugins[TMED_CONVERTER_VIDEO_MAX_PLUGINS] = {0};
+
+
+tmedia_converter_video_t* tmedia_converter_video_create(tsk_size_t srcWidth, tsk_size_t srcHeight, tmedia_chroma_t srcChroma, tsk_size_t dstWidth, tsk_size_t dstHeight, tmedia_chroma_t dstChroma)
+{
+ tmedia_converter_video_t* converter = tsk_null;
+ const tmedia_converter_video_plugin_def_t* plugin;
+ tsk_size_t i = 0;
+
+ while((i < TMED_CONVERTER_VIDEO_MAX_PLUGINS) && (plugin = __tmedia_converter_video_plugins[i++])){
+ if(plugin->objdef && (converter = tsk_object_new(plugin->objdef))){
+ converter->plugin = plugin;
+ converter->scale_rotated_frames = tsk_true;
+ // must not set other values beacause 'zero' is meaningful
+ if(converter->plugin->init){
+ if(converter->plugin->init(converter, srcWidth, srcHeight, srcChroma, dstWidth, dstHeight, dstChroma)){
+ TSK_DEBUG_ERROR("Failed to initialized the video converter");
+ TSK_OBJECT_SAFE_FREE(converter);
+ continue;
+ }
+ }
+ converter->srcChroma = srcChroma;
+ converter->dstChroma = dstChroma;
+ converter->srcWidth = srcWidth ? srcWidth : dstWidth;
+ converter->srcHeight = srcHeight ? srcHeight : dstHeight;
+ converter->dstWidth = dstWidth ? dstWidth : srcWidth;
+ converter->dstHeight = dstHeight ? dstHeight : srcHeight;
+ break;
+ }
+ }
+
+ return converter;
+}
+
+int tmedia_converter_video_plugin_register(const tmedia_converter_video_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ if(!plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* add or replace the plugin */
+ for(i = 0; i<TMED_CONVERTER_VIDEO_MAX_PLUGINS; i++){
+ if(!__tmedia_converter_video_plugins[i] || (__tmedia_converter_video_plugins[i] == plugin)){
+ __tmedia_converter_video_plugins[i] = plugin;
+ return 0;
+ }
+ }
+
+ TSK_DEBUG_ERROR("There are already %d plugins.", TMED_CONVERTER_VIDEO_MAX_PLUGINS);
+ return -2;
+}
+
+tsk_size_t tmedia_converter_video_plugin_registry_count()
+{
+ tsk_size_t count;
+ for(count = 0;
+ count < TMED_CONVERTER_VIDEO_MAX_PLUGINS && __tmedia_converter_video_plugins[count];
+ ++count) ;
+ return count;
+}
+
+int tmedia_converter_video_plugin_unregister(const tmedia_converter_video_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+ if(!plugin){
+ TSK_DEBUG_ERROR("Invalid Parameter");
+ return -1;
+ }
+
+ /* find the plugin to unregister */
+ for(i = 0; i<TMED_CONVERTER_VIDEO_MAX_PLUGINS && __tmedia_converter_video_plugins[i]; i++){
+ if(__tmedia_converter_video_plugins[i] == plugin){
+ __tmedia_converter_video_plugins[i] = tsk_null;
+ found = tsk_true;
+ break;
+ }
+ }
+
+ /* compact */
+ if(found){
+ for(; i<(TMED_CONVERTER_VIDEO_MAX_PLUGINS - 1); i++){
+ if(__tmedia_converter_video_plugins[i+1]){
+ __tmedia_converter_video_plugins[i] = __tmedia_converter_video_plugins[i+1];
+ }
+ else{
+ break;
+ }
+ }
+ __tmedia_converter_video_plugins[i] = tsk_null;
+ }
+ return (found ? 0 : -2);
+}
diff --git a/tinyMEDIA/src/tmedia_defaults.c b/tinyMEDIA/src/tmedia_defaults.c
new file mode 100644
index 0000000..b24c153
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_defaults.c
@@ -0,0 +1,618 @@
+/*
+ * Copyright (C) 2010-2011 Mamadou Diop.
+ *
+ * Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 "tinymedia/tmedia_defaults.h"
+
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#include <limits.h> /* INT_MAX */
+
+// /!\ These are global values shared by all sessions and stacks. Could be set (update) per session using "session_set()"
+
+static tmedia_profile_t __profile = tmedia_profile_default;
+static tmedia_bandwidth_level_t __bl = tmedia_bl_unrestricted;
+static tsk_bool_t __congestion_ctrl_enabled = tsk_false;
+static int32_t __video_fps = 15; // allowed values: ]0 - 120]
+static int32_t __video_motion_rank = 2; // allowed values: 1(low), 2(medium) or 4(high)
+static int32_t __bw_video_up_max_kbps = INT_MAX; // <= 0: unrestricted, Unit: kbps
+static int32_t __bw_video_down_max_kbps = INT_MAX; // <= 0: unrestricted, Unit: kbps
+static tmedia_pref_video_size_t __pref_video_size = tmedia_pref_video_size_cif; // 352 x 288: Android, iOS, WP7
+static int32_t __jb_margin_ms = -1; // disable
+static int32_t __jb_max_late_rate_percent = -1; // -1: disable 4: default for speex
+static uint32_t __echo_tail = 100;
+static uint32_t __echo_skew = 0;
+static tsk_bool_t __echo_supp_enabled;
+static tsk_bool_t __agc_enabled = tsk_false;
+static float __agc_level = 8000.0f;
+static tsk_bool_t __vad_enabled = tsk_false;
+static tsk_bool_t __noise_supp_enabled = tsk_true;
+static int32_t __noise_supp_level = -30;
+static tsk_bool_t __100rel_enabled = tsk_true;
+static int32_t __sx = -1;
+static int32_t __sy = -1;
+static int32_t __audio_producer_gain = 0;
+static int32_t __audio_consumer_gain = 0;
+static int32_t __audio_channels_playback = 1;
+static int32_t __audio_channels_record = 1;
+static int32_t __audio_ptime = 20;
+static uint16_t __rtp_port_range_start = 1024;
+static uint16_t __rtp_port_range_stop = 65535;
+static tsk_bool_t __rtp_symetric_enabled = tsk_false; // This option is force symetric RTP for remote size. Local: always ON
+static tmedia_type_t __media_type = tmedia_audio;
+static int32_t __volume = 100;
+static char* __producer_friendly_name[3] = { tsk_null/*audio*/, tsk_null/*video*/, tsk_null/*bfcpvideo*/ }; // pref. camera(index=1) and sound card(index=0) friendly names (e.g. Logitech HD Pro Webcam C920).
+static int32_t __inv_session_expires = 0; // Session Timers: 0: disabled
+static char* __inv_session_refresher = tsk_null;
+static tmedia_srtp_mode_t __srtp_mode = tmedia_srtp_mode_none;
+static tmedia_srtp_type_t __srtp_type = tmedia_srtp_type_sdes;
+static tsk_bool_t __rtcp_enabled = tsk_true;
+static tsk_bool_t __rtcpmux_enabled = tsk_true;
+static tsk_bool_t __ice_enabled = tsk_false;
+static char* __stun_server_ip = tsk_null; // STUN/TURN server IP address
+static uint16_t __stun_server_port = 3478; // STUN for SIP headers (Contact, Via...)
+static char* __stun_usr_name = tsk_null; // STUN/TURN credentials
+static char* __stun_usr_pwd = tsk_null; // STUN/TURN credentials
+static tsk_bool_t __stun_enabled = tsk_false; // Whether STUN for SIP headers is enabled
+static tsk_bool_t __icestun_enabled = tsk_true; // Whether STUN for ICE (reflexive candidates) is enabled
+static tsk_bool_t __iceturn_enabled = tsk_false; // Whether TURN for ICE (relay candidates) is enabled
+static tsk_bool_t __bypass_encoding_enabled = tsk_false;
+static tsk_bool_t __bypass_decoding_enabled = tsk_false;
+static tsk_bool_t __videojb_enabled = tsk_true;
+static tsk_bool_t __video_zeroartifacts_enabled = tsk_false; // Requires from remote parties to support AVPF (RTCP-FIR/NACK/PLI)
+static tsk_size_t __rtpbuff_size = 0x1FFFE; // Network buffer size used for RTP (SO_RCVBUF, SO_SNDBUF)
+static tsk_size_t __avpf_tail_min = 20; // Min size for tail used to honor RTCP-NACK requests
+static tsk_size_t __avpf_tail_max = 160; // Max size for tail used to honor RTCP-NACK requests
+static tmedia_mode_t __avpf_mode = tmedia_mode_optional; // Whether to use AVPF instead of AVP or negotiate. FIXME
+static uint32_t __opus_maxcapturerate = 16000; // supported: 8k,12k,16k,24k,48k. IMPORTANT: only 8k and 16k will work with WebRTC AEC
+static uint32_t __opus_maxplaybackrate = 48000; // supported: 8k,12k,16k,24k,48k
+static char* __ssl_certs_priv_path = tsk_null;
+static char* __ssl_certs_pub_path = tsk_null;
+static char* __ssl_certs_ca_path = tsk_null;
+static tsk_bool_t __ssl_certs_verify = tsk_false;
+static tsk_size_t __max_fds = 0; // Maximum number of FDs this process is allowed to open. Zero to disable.
+static tsk_bool_t __webproxy_auto_detect = tsk_false;
+static char* __webproxy_type = tsk_null;
+static char* __webproxy_host = tsk_null;
+static unsigned short __webproxy_port = 0;
+static char* __webproxy_login = tsk_null;
+static char* __webproxy_password = tsk_null;
+
+int tmedia_defaults_set_profile(tmedia_profile_t profile){
+ __profile = profile;
+ return 0;
+}
+tmedia_profile_t tmedia_defaults_get_profile(){
+ return __profile;
+}
+
+// @deprecated
+int tmedia_defaults_set_bl(tmedia_bandwidth_level_t bl){
+ __bl = bl;
+ return 0;
+}
+// @deprecated
+tmedia_bandwidth_level_t tmedia_defaults_get_bl(){
+ return __bl;
+}
+
+int tmedia_defaults_set_congestion_ctrl_enabled(tsk_bool_t enabled){
+ __congestion_ctrl_enabled = enabled;
+ return 0;
+}
+tsk_bool_t tmedia_defaults_get_congestion_ctrl_enabled(){
+ return __congestion_ctrl_enabled;
+}
+
+int tmedia_defaults_set_video_fps(int32_t video_fps){
+ if(video_fps > 0 && video_fps <= 120){
+ __video_fps = video_fps;
+ return 0;
+ }
+ TSK_DEBUG_ERROR("%d not valid for video fps", video_fps);
+ return -1;
+}
+int32_t tmedia_defaults_get_video_fps(){
+ return __video_fps;
+}
+
+int tmedia_defaults_set_video_motion_rank(int32_t video_motion_rank){
+ switch(video_motion_rank){
+ case 1/*low*/: case 2/*medium*/: case 4/*high*/: __video_motion_rank = video_motion_rank; return 0;
+ default: TSK_DEBUG_ERROR("%d not valid for video motion rank. Must be 1, 2 or 4", video_motion_rank); return -1;
+ }
+}
+int32_t tmedia_defaults_get_video_motion_rank(){
+ return __video_motion_rank;
+}
+
+int tmedia_defaults_set_bandwidth_video_upload_max(int32_t bw_video_up_max_kbps){
+ __bw_video_up_max_kbps = bw_video_up_max_kbps > 0 ? bw_video_up_max_kbps : INT_MAX;
+ return 0;
+}
+int32_t tmedia_defaults_get_bandwidth_video_upload_max(){
+ return __bw_video_up_max_kbps;
+}
+
+int tmedia_defaults_set_bandwidth_video_download_max(int32_t bw_video_down_max_kbps){
+ __bw_video_down_max_kbps = bw_video_down_max_kbps > 0 ? bw_video_down_max_kbps : INT_MAX;
+ return 0;
+}
+int32_t tmedia_defaults_get_bandwidth_video_download_max(){
+ return __bw_video_down_max_kbps;
+}
+
+int tmedia_defaults_set_pref_video_size(tmedia_pref_video_size_t pref_video_size){
+ __pref_video_size = pref_video_size;
+ return 0;
+}
+tmedia_pref_video_size_t tmedia_defaults_get_pref_video_size(){
+ return __pref_video_size;
+}
+
+int tmedia_defaults_set_jb_margin(int32_t jb_margin_ms){
+ __jb_margin_ms = jb_margin_ms;
+ return __jb_margin_ms;
+}
+
+int32_t tmedia_defaults_get_jb_margin(){
+ return __jb_margin_ms;
+}
+
+int tmedia_defaults_set_jb_max_late_rate(int32_t jb_max_late_rate_percent){
+ __jb_max_late_rate_percent = jb_max_late_rate_percent;
+ return 0;
+}
+
+int32_t tmedia_defaults_get_jb_max_late_rate(){
+ return __jb_max_late_rate_percent;
+}
+
+int tmedia_defaults_set_echo_tail(uint32_t echo_tail){
+ __echo_tail = echo_tail;
+ return 0;
+}
+
+int tmedia_defaults_set_echo_skew(uint32_t echo_skew){
+ __echo_skew = echo_skew;
+ return 0;
+}
+
+uint32_t tmedia_defaults_get_echo_tail()
+{
+ return __echo_tail;
+}
+
+uint32_t tmedia_defaults_get_echo_skew(){
+ return __echo_skew;
+}
+
+int tmedia_defaults_set_echo_supp_enabled(tsk_bool_t echo_supp_enabled){
+ __echo_supp_enabled = echo_supp_enabled;
+ return 0;
+}
+
+tsk_bool_t tmedia_defaults_get_echo_supp_enabled(){
+ return __echo_supp_enabled;
+}
+
+int tmedia_defaults_set_agc_enabled(tsk_bool_t agc_enabled){
+ __agc_enabled = agc_enabled;
+ return 0;
+}
+
+tsk_bool_t tmedia_defaults_get_agc_enabled(){
+ return __agc_enabled;
+}
+
+int tmedia_defaults_set_agc_level(float agc_level){
+ __agc_level = agc_level;
+ return 0;
+}
+
+float tmedia_defaults_get_agc_level()
+{
+ return __agc_level;
+}
+
+int tmedia_defaults_set_vad_enabled(tsk_bool_t vad_enabled){
+ __vad_enabled = vad_enabled;
+ return 0;
+}
+
+tsk_bool_t tmedia_defaults_get_vad_enabled(){
+ return __vad_enabled;
+}
+
+int tmedia_defaults_set_noise_supp_enabled(tsk_bool_t noise_supp_enabled){
+ __noise_supp_enabled = noise_supp_enabled;
+ return 0;
+}
+
+tsk_bool_t tmedia_defaults_get_noise_supp_enabled(){
+ return __noise_supp_enabled;
+}
+
+int tmedia_defaults_set_noise_supp_level(int32_t noise_supp_level){
+ __noise_supp_level = noise_supp_level;
+ return 0;
+}
+
+int32_t tmedia_defaults_get_noise_supp_level(){
+ return __noise_supp_level;
+}
+
+int tmedia_defaults_set_100rel_enabled(tsk_bool_t _100rel_enabled){
+ __100rel_enabled = _100rel_enabled;
+ return 0;
+}
+tsk_bool_t tmedia_defaults_get_100rel_enabled(){
+ return __100rel_enabled;
+}
+
+int tmedia_defaults_set_screen_size(int32_t sx, int32_t sy){
+ __sx = sx;
+ __sy = sy;
+ return 0;
+}
+
+int32_t tmedia_defaults_get_screen_x(){
+ return __sx;
+}
+
+int32_t tmedia_defaults_get_screen_y(){
+ return __sy;
+}
+
+int tmedia_defaults_set_audio_ptime(int32_t audio_ptime){
+ if(audio_ptime > 0){
+ __audio_ptime = audio_ptime;
+ return 0;
+ }
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+}
+int32_t tmedia_defaults_get_audio_ptime(){
+ return __audio_ptime;
+}
+int tmedia_defaults_set_audio_channels(int32_t channels_playback, int32_t channels_record){
+ if(channels_playback != 1 && channels_playback != 2) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; }
+ if(channels_record != 1 && channels_record != 2) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; }
+ __audio_channels_playback = channels_playback;
+ __audio_channels_record = channels_record;
+ return 0;
+}
+int32_t tmedia_defaults_get_audio_channels_playback(){
+ return __audio_channels_playback;
+}
+int32_t tmedia_defaults_get_audio_channels_record(){
+ return __audio_channels_record;
+}
+
+int tmedia_defaults_set_audio_gain(int32_t audio_producer_gain, int32_t audio_consumer_gain){
+ __audio_producer_gain = audio_producer_gain;
+ __audio_consumer_gain = audio_consumer_gain;
+ return 0;
+}
+
+int32_t tmedia_defaults_get_audio_producer_gain(){
+ return __audio_producer_gain;
+}
+
+int32_t tmedia_defaults_get_audio_consumer_gain(){
+ return __audio_consumer_gain;
+}
+
+uint16_t tmedia_defaults_get_rtp_port_range_start(){
+ return __rtp_port_range_start;
+}
+
+uint16_t tmedia_defaults_get_rtp_port_range_stop(){
+ return __rtp_port_range_stop;
+}
+int tmedia_defaults_set_rtp_port_range(uint16_t start, uint16_t stop){
+ if(start < 1024 || stop < 1024 || start >= stop){
+ TSK_DEBUG_ERROR("Invalid parameter: (%u < 1024 || %u < 1024 || %u >= %u)", start, stop, start, stop);
+ return -1;
+ }
+ __rtp_port_range_start = start;
+ __rtp_port_range_stop = stop;
+ return 0;
+}
+
+int tmedia_defaults_set_rtp_symetric_enabled(tsk_bool_t enabled){
+ __rtp_symetric_enabled = enabled;
+ return 0;
+}
+tsk_bool_t tmedia_defaults_get_rtp_symetric_enabled(){
+ return __rtp_symetric_enabled;
+}
+
+tmedia_type_t tmedia_defaults_get_media_type(){
+ return __media_type;
+}
+
+int tmedia_defaults_set_media_type(tmedia_type_t media_type){
+ __media_type = media_type;
+ return 0;
+}
+
+int tmedia_defaults_set_volume(int32_t volume){
+ __volume = TSK_CLAMP(0, volume, 100);
+ return 0;
+}
+int32_t tmedia_defaults_get_volume(){
+ return __volume;
+}
+
+int tmedia_producer_set_friendly_name(tmedia_type_t media_type, const char* friendly_name) {
+ if(media_type != tmedia_audio && media_type != tmedia_video && media_type != tmedia_bfcp_video) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_strupdate(&__producer_friendly_name[(media_type == tmedia_audio) ? 0 : (media_type == tmedia_bfcp_video ? 2 : 1)], friendly_name);
+ return 0;
+}
+const char* tmedia_producer_get_friendly_name(tmedia_type_t media_type){
+ if(media_type != tmedia_audio && media_type != tmedia_video && media_type != tmedia_bfcp_video) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+ return __producer_friendly_name[(media_type == tmedia_audio) ? 0 : (media_type == tmedia_bfcp_video ? 2 : 1)];
+}
+
+int32_t tmedia_defaults_get_inv_session_expires(){
+ return __inv_session_expires;
+}
+int tmedia_defaults_set_inv_session_expires(int32_t timeout){
+ if(timeout >= 0){
+ __inv_session_expires = timeout;
+ return 0;
+ }
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+}
+
+const char* tmedia_defaults_get_inv_session_refresher(){
+ return __inv_session_refresher;
+}
+int tmedia_defaults_set_inv_session_refresher(const char* refresher){
+ tsk_strupdate(&__inv_session_refresher, refresher);
+ return 0;
+}
+
+tmedia_srtp_mode_t tmedia_defaults_get_srtp_mode(){
+ return __srtp_mode;
+}
+int tmedia_defaults_set_srtp_mode(tmedia_srtp_mode_t mode){
+ __srtp_mode = mode;
+ return 0;
+}
+
+tmedia_srtp_type_t tmedia_defaults_get_srtp_type(){
+ return __srtp_type;
+}
+int tmedia_defaults_set_srtp_type(tmedia_srtp_type_t srtp_type){
+ __srtp_type = srtp_type;
+ return 0;
+}
+
+tsk_bool_t tmedia_defaults_get_rtcp_enabled(){
+ return __rtcp_enabled;
+}
+int tmedia_defaults_set_rtcp_enabled(tsk_bool_t rtcp_enabled){
+ __rtcp_enabled = rtcp_enabled;
+ return 0;
+}
+
+tsk_bool_t tmedia_defaults_get_rtcpmux_enabled(){
+ return __rtcpmux_enabled;
+}
+int tmedia_defaults_set_rtcpmux_enabled(tsk_bool_t rtcpmux_enabled){
+ __rtcpmux_enabled = rtcpmux_enabled;
+ return 0;
+}
+
+int tmedia_defaults_set_stun_server(const char* server_ip, uint16_t server_port){
+ tsk_strupdate(&__stun_server_ip, server_ip);
+ __stun_server_port = server_port;
+ return 0;
+}
+int tmedia_defaults_get_stun_server(const char** server_ip, uint16_t*const server_port){
+ static const char* __stun_server_ip_default = "numb.viagenie.ca"; // default server for backward compatibility
+ if(server_ip) *server_ip = tsk_strnullORempty(__stun_server_ip) ? __stun_server_ip_default : __stun_server_ip;
+ if(server_port) *server_port = __stun_server_port;
+ return 0;
+}
+
+int tmedia_defaults_set_stun_cred(const char* usr_name, const char* usr_pwd) {
+ tsk_strupdate(&__stun_usr_name, usr_name);
+ tsk_strupdate(&__stun_usr_pwd, usr_pwd);
+ return 0;
+}
+int tmedia_defaults_get_stun_cred(const char** usr_name, const char** usr_pwd){
+ if(usr_name) *usr_name = __stun_usr_name;
+ if(usr_pwd) *usr_pwd = __stun_usr_pwd;
+ return 0;
+}
+
+int tmedia_defaults_set_stun_enabled(tsk_bool_t stun_enabled){
+ __stun_enabled = stun_enabled;
+ return 0;
+}
+tsk_bool_t tmedia_defaults_get_stun_enabled(){
+ return __stun_enabled;
+}
+
+int tmedia_defaults_set_icestun_enabled(tsk_bool_t icestun_enabled){
+ __icestun_enabled = icestun_enabled;
+ return 0;
+}
+tsk_bool_t tmedia_defaults_get_icestun_enabled(){
+ return __icestun_enabled;
+}
+
+int tmedia_defaults_set_iceturn_enabled(tsk_bool_t iceturn_enabled){
+ __iceturn_enabled = iceturn_enabled;
+ return 0;
+}
+tsk_bool_t tmedia_defaults_get_iceturn_enabled(){
+ return __iceturn_enabled;
+}
+
+int tmedia_defaults_set_ice_enabled(tsk_bool_t ice_enabled){
+ __ice_enabled = ice_enabled;
+ return 0;
+}
+tsk_bool_t tmedia_defaults_get_ice_enabled(){
+ return __ice_enabled;
+}
+
+int tmedia_defaults_set_bypass_encoding(tsk_bool_t enabled){
+ __bypass_encoding_enabled = enabled;
+ return 0;
+}
+tsk_bool_t tmedia_defaults_get_bypass_encoding(){
+ return __bypass_encoding_enabled;
+}
+
+int tmedia_defaults_set_bypass_decoding(tsk_bool_t enabled){
+ __bypass_decoding_enabled = enabled;
+ return 0;
+}
+tsk_bool_t tmedia_defaults_get_bypass_decoding(){
+ return __bypass_decoding_enabled;
+}
+
+int tmedia_defaults_set_videojb_enabled(tsk_bool_t enabled){
+ __videojb_enabled = enabled;
+ return 0;
+}
+tsk_bool_t tmedia_defaults_get_videojb_enabled(){
+ return __videojb_enabled;
+}
+
+int tmedia_defaults_set_video_zeroartifacts_enabled(tsk_bool_t enabled){
+ __video_zeroartifacts_enabled = enabled;
+ return 0;
+}
+tsk_bool_t tmedia_defaults_get_video_zeroartifacts_enabled(){
+ return __video_zeroartifacts_enabled;
+}
+
+int tmedia_defaults_set_rtpbuff_size(tsk_size_t rtpbuff_size){
+ __rtpbuff_size = rtpbuff_size;
+ return 0;
+}
+tsk_size_t tmedia_defaults_get_rtpbuff_size(){
+ return __rtpbuff_size;
+}
+
+int tmedia_defaults_set_avpf_tail(tsk_size_t tail_min, tsk_size_t tail_max){
+ __avpf_tail_min = tail_min;
+ __avpf_tail_max = tail_max;
+ return 0;
+}
+tsk_size_t tmedia_defaults_get_avpf_tail_min(){
+ return __avpf_tail_min;
+}
+tsk_size_t tmedia_defaults_get_avpf_tail_max(){
+ return __avpf_tail_max;
+}
+
+int tmedia_defaults_set_avpf_mode(enum tmedia_mode_e mode) {
+ __avpf_mode = mode;
+ return 0;
+}
+enum tmedia_mode_e tmedia_defaults_get_avpf_mode() {
+ return __avpf_mode;
+}
+
+int tmedia_defaults_set_opus_maxcapturerate(uint32_t opus_maxcapturerate){
+ switch(opus_maxcapturerate){
+ case 8000: case 12000: case 16000: case 24000: case 48000: __opus_maxcapturerate = opus_maxcapturerate; return 0;
+ default: TSK_DEBUG_ERROR("%u not valid for opus_maxcapturerate", opus_maxcapturerate); return -1;
+ }
+}
+uint32_t tmedia_defaults_get_opus_maxcapturerate(){
+ return __opus_maxcapturerate;
+}
+
+int tmedia_defaults_set_opus_maxplaybackrate(uint32_t opus_maxplaybackrate){
+ switch(opus_maxplaybackrate){
+ case 8000: case 12000: case 16000: case 24000: case 48000: __opus_maxplaybackrate = opus_maxplaybackrate; return 0;
+ default: TSK_DEBUG_ERROR("%u not valid for opus_maxplaybackrate", opus_maxplaybackrate); return -1;
+ }
+}
+uint32_t tmedia_defaults_get_opus_maxplaybackrate(){
+ return __opus_maxplaybackrate;
+}
+
+int tmedia_defaults_set_ssl_certs(const char* priv_path, const char* pub_path, const char* ca_path, tsk_bool_t verify){
+ tsk_strupdate(&__ssl_certs_priv_path, priv_path);
+ tsk_strupdate(&__ssl_certs_pub_path, pub_path);
+ tsk_strupdate(&__ssl_certs_ca_path, ca_path);
+ __ssl_certs_verify = verify;
+ return 0;
+}
+int tmedia_defaults_get_ssl_certs(const char** priv_path, const char** pub_path, const char** ca_path, tsk_bool_t *verify){
+ if(priv_path) *priv_path = __ssl_certs_priv_path;
+ if(pub_path) *pub_path = __ssl_certs_pub_path;
+ if(ca_path) *ca_path = __ssl_certs_ca_path;
+ if(verify) *verify = __ssl_certs_verify;
+ return 0;
+}
+
+int tmedia_defaults_set_max_fds(int32_t max_fds) {
+ if (max_fds > 0 && max_fds < 0xFFFF) {
+ __max_fds = (tsk_size_t)max_fds;
+ return 0;
+ }
+ return -1;
+}
+tsk_size_t tmedia_defaults_get_max_fds() {
+ return __max_fds;
+}
+
+int tmedia_defaults_set_webproxy_auto_detect(tsk_bool_t auto_detect) {
+ __webproxy_auto_detect = auto_detect;
+ return 0;
+}
+tsk_bool_t tmedia_defaults_get_webproxy_auto_detect() {
+ return __webproxy_auto_detect;
+}
+int tmedia_defaults_set_webproxy_info(const char* type, const char* host, unsigned short port, const char* login, const char* password) {
+ tsk_strupdate(&__webproxy_type, type);
+ tsk_strupdate(&__webproxy_host, host);
+ tsk_strupdate(&__webproxy_login, login);
+ tsk_strupdate(&__webproxy_password, password);
+ __webproxy_port = port;
+ return 0;
+}
+
+int tmedia_defaults_get_webproxy_info(const char** type, const char** host, unsigned short* port, const char** login, const char** password) {
+ if (type) *type = __webproxy_type;
+ if (host) *host = __webproxy_host;
+ if (port) *port = __webproxy_port;
+ if (login) *login = __webproxy_login;
+ if (password) *password = __webproxy_password;
+ return 0;
+}
diff --git a/tinyMEDIA/src/tmedia_denoise.c b/tinyMEDIA/src/tmedia_denoise.c
new file mode 100644
index 0000000..4c0f74b
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_denoise.c
@@ -0,0 +1,242 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_denoise.c
+* @brief Denoiser (Noise suppression, AGC, AEC, VAD) Plugin
+*
+* @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+*
+
+*/
+#include "tinymedia/tmedia_denoise.h"
+#include "tinymedia/tmedia_defaults.h"
+
+#include "tsk_debug.h"
+
+static const tmedia_denoise_plugin_def_t* __tmedia_denoise_plugin = tsk_null;
+
+int tmedia_denoise_init(tmedia_denoise_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ self->echo_tail = tmedia_defaults_get_echo_tail();
+ self->echo_skew = tmedia_defaults_get_echo_skew();
+ self->echo_supp_enabled = tmedia_defaults_get_echo_supp_enabled();
+ self->agc_enabled = tmedia_defaults_get_agc_enabled();
+ self->agc_level = tmedia_defaults_get_agc_level();
+ self->vad_enabled = tmedia_defaults_get_vad_enabled();
+ self->noise_supp_enabled = tmedia_defaults_get_noise_supp_enabled();
+ self->noise_supp_level = tmedia_defaults_get_noise_supp_level();
+
+ return 0;
+}
+
+int tmedia_denoise_set(tmedia_denoise_t* self, const tmedia_param_t* param)
+{
+ if(!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(self->plugin->set){
+ return self->plugin->set(self, param);
+ }
+ return 0;
+}
+
+int tmedia_denoise_open(tmedia_denoise_t* self, uint32_t record_frame_size_samples, uint32_t record_sampling_rate, uint32_t record_channels, uint32_t playback_frame_size_samples, uint32_t playback_sampling_rate, uint32_t playback_channels)
+{
+ if (!self || !self->plugin) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (self->opened) {
+ TSK_DEBUG_WARN("Denoiser already opened");
+ return 0;
+ }
+
+ if (self->plugin->open) {
+ int ret;
+
+ TSK_OBJECT_SAFE_FREE(self->record_frame);
+ TSK_OBJECT_SAFE_FREE(self->playback_frame);
+ if (!(self->record_frame = tsk_buffer_create(tsk_null, (record_frame_size_samples * sizeof(int16_t))))) {
+ TSK_DEBUG_ERROR("Failed to create record the buffer");
+ return -2;
+ }
+ if (!(self->playback_frame = tsk_buffer_create(tsk_null, (playback_frame_size_samples * sizeof(int16_t))))) {
+ TSK_DEBUG_ERROR("Failed to create playback the buffer");
+ return -2;
+ }
+ if ((ret = self->plugin->open(self, record_frame_size_samples, record_sampling_rate, record_channels, playback_frame_size_samples, playback_sampling_rate, playback_channels))) {
+ TSK_DEBUG_ERROR("Failed to open [%s] denoiser", self->plugin->desc);
+ return ret;
+ }
+ else {
+ self->opened = tsk_true;
+ return 0;
+ }
+ }
+ else{
+ self->opened = tsk_true;
+ return 0;
+ }
+}
+
+int tmedia_denoise_echo_playback(tmedia_denoise_t* self, const void* echo_frame, uint32_t echo_frame_size_bytes)
+{
+ if(!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(!self->opened){
+ TSK_DEBUG_ERROR("Denoiser not opened");
+ return -2;
+ }
+
+ if(self->plugin->echo_playback){
+ return self->plugin->echo_playback(self, echo_frame, echo_frame_size_bytes);
+ }
+ else{
+ return 0;
+ }
+}
+
+int tmedia_denoise_process_record(tmedia_denoise_t* self, void* audio_frame, uint32_t audio_frame_size_bytes, tsk_bool_t* silence_or_noise)
+{
+ if(!self || !self->plugin || !silence_or_noise){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(!self->opened){
+ TSK_DEBUG_ERROR("Denoiser not opened");
+ return -2;
+ }
+
+ if(self->plugin->process_record){
+ return self->plugin->process_record(self, audio_frame, audio_frame_size_bytes, silence_or_noise);
+ }
+ else{
+ *silence_or_noise = tsk_false;
+ return 0;
+ }
+}
+
+int tmedia_denoise_process_playback(tmedia_denoise_t* self, void* audio_frame, uint32_t audio_frame_size_bytes)
+{
+ if(!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(!self->opened){
+ TSK_DEBUG_ERROR("Denoiser not opened");
+ return -2;
+ }
+
+ if(self->plugin->process_playback){
+ return self->plugin->process_playback(self, audio_frame, audio_frame_size_bytes);
+ }
+ return 0;
+}
+
+int tmedia_denoise_close(tmedia_denoise_t* self)
+{
+ if(!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if(!self->opened){
+ return 0;
+ }
+
+ if(self->plugin->close){
+ int ret;
+
+ if((ret = self->plugin->close(self))){
+ TSK_DEBUG_ERROR("Failed to close [%s] denoiser", self->plugin->desc);
+ return ret;
+ }
+ else{
+ self->opened = tsk_false;
+ return 0;
+ }
+ }
+ else{
+ self->opened = tsk_false;
+ return 0;
+ }
+}
+
+int tmedia_denoise_deinit(tmedia_denoise_t* self)
+{
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (self->opened) {
+ tmedia_denoise_close(self);
+ }
+
+ TSK_OBJECT_SAFE_FREE(self->record_frame);
+ TSK_OBJECT_SAFE_FREE(self->playback_frame);
+
+ return 0;
+}
+
+int tmedia_denoise_plugin_register(const tmedia_denoise_plugin_def_t* plugin)
+{
+ if(!plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if(!__tmedia_denoise_plugin) {
+ TSK_DEBUG_INFO("Register denoiser: %s", plugin->desc);
+ __tmedia_denoise_plugin = plugin;
+ }
+ return 0;
+}
+
+int tmedia_denoise_plugin_unregister(const tmedia_denoise_plugin_def_t* plugin)
+{
+ (void)(plugin);
+ __tmedia_denoise_plugin = tsk_null;
+ return 0;
+}
+
+tmedia_denoise_t* tmedia_denoise_create()
+{
+ tmedia_denoise_t* denoise = tsk_null;
+
+ if(__tmedia_denoise_plugin){
+ if((denoise = tsk_object_new(__tmedia_denoise_plugin->objdef))){
+ denoise->plugin = __tmedia_denoise_plugin;
+ }
+ }
+ return denoise;
+}
diff --git a/tinyMEDIA/src/tmedia_imageattr.c b/tinyMEDIA/src/tmedia_imageattr.c
new file mode 100644
index 0000000..07440c4
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_imageattr.c
@@ -0,0 +1,954 @@
+
+/* #line 1 "./ragel/tmedia_imageattr.rl" */
+/*
+* Copyright (C) 2012-2015 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 tmedia_imageattr.c
+ * @brief 'image-attr' parser as per RFC 6236
+ */
+#include "tinymedia/tmedia_imageattr.h"
+
+#include "tsk_ragel_state.h"
+#include "tsk_debug.h"
+
+#include <stdlib.h>
+
+/***********************************
+* Ragel state machine.
+*/
+
+/* #line 135 "./ragel/tmedia_imageattr.rl" */
+
+
+static int tmedia_imageattr_reset(tmedia_imageattr_xt* self)
+{
+ if(self){
+ tsk_size_t i;
+ memset(self, 0, sizeof(*self));
+ for(i = 0; i < TMEDIA_imageattr_ARRAY_MAX_SIZE; ++i){
+ self->send.sets[i].qvalue = 0.5;
+ self->recv.sets[i].qvalue = 0.5;
+ }
+ return 0;
+ }
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+}
+
+int tmedia_imageattr_parse(tmedia_imageattr_xt* self, const void* in_data, tsk_size_t in_size)
+{
+ int cs = 0;
+ const char *p = in_data;
+ const char *pe = p + in_size;
+ const char *eof = pe;
+
+ const char *tag_start = tsk_null;
+
+ tmedia_imageattr_set_xt* sets = tsk_null;
+ tsk_size_t* sets_count = tsk_null;
+ tmedia_imageattr_xyrange_xt* xyrange = tsk_null;
+ tmedia_imageattr_srange_xt* srange = tsk_null;
+
+ TSK_RAGEL_DISABLE_WARNINGS_BEGIN()
+
+/* #line 72 "./src/tmedia_imageattr.c" */
+static const char _tmedia_machine_imageattr_actions[] = {
+ 0, 1, 0, 1, 1, 1, 2, 1,
+ 3, 1, 4, 1, 5, 1, 6, 1,
+ 7, 1, 8, 1, 9, 1, 10, 1,
+ 11, 1, 12, 1, 13, 1, 14, 1,
+ 15, 1, 16, 1, 17, 1, 18, 1,
+ 19, 1, 20, 2, 3, 0, 2, 4,
+ 0, 2, 6, 11, 2, 15, 0, 2,
+ 16, 13
+};
+
+static const short _tmedia_machine_imageattr_key_offsets[] = {
+ 0, 0, 6, 8, 10, 12, 14, 18,
+ 20, 22, 24, 26, 30, 32, 33, 36,
+ 39, 41, 42, 45, 49, 55, 57, 59,
+ 60, 61, 64, 65, 67, 70, 73, 74,
+ 76, 79, 82, 85, 86, 88, 91, 92,
+ 94, 97, 100, 101, 102, 104, 105, 107,
+ 108, 110, 114, 116, 117, 118, 121, 123,
+ 125, 126, 130, 131, 133, 137, 141, 145,
+ 147, 148, 150, 153, 154, 156, 160, 163,
+ 164, 166, 170, 174, 178, 180, 182, 183,
+ 185, 188, 189, 191, 194, 197, 200, 201,
+ 203, 204, 206, 210, 214, 216, 217, 219,
+ 223, 227, 231, 235, 237, 239, 243, 245,
+ 249, 253, 257, 261, 265, 267, 269, 273,
+ 277, 281, 285, 287, 289, 293, 297, 301,
+ 305, 309, 311, 313, 316, 319, 322, 325,
+ 328, 329, 331, 334, 337, 340, 343, 344,
+ 346, 350, 352, 356, 360, 364, 368, 372,
+ 374, 375, 379, 383, 387, 391, 393, 395,
+ 399, 403, 407, 411, 415, 417, 419, 422,
+ 425, 428, 431, 434, 435, 436, 438, 440,
+ 442, 444, 446, 447, 450, 453, 455, 456,
+ 459, 463, 469, 471, 473, 474, 475, 478,
+ 479, 481, 484, 487, 488, 490, 493, 496,
+ 499, 500, 502, 503, 505, 508, 511, 512,
+ 513, 515, 516, 518, 519, 521, 525, 527,
+ 528, 529, 532, 534, 536, 537, 541, 542,
+ 544, 548, 552, 556, 558, 559, 561, 564,
+ 565, 567, 571, 574, 575, 577, 581, 585,
+ 589, 591, 593, 594, 596, 599, 600, 602,
+ 605, 608, 611, 612, 614, 615, 617, 621,
+ 625, 627, 628, 630, 634, 638, 642, 646,
+ 648, 650, 654, 656, 660, 664, 668, 672,
+ 676, 678, 680, 684, 688, 692, 696, 698,
+ 700, 704, 708, 712, 716, 720, 722, 724,
+ 727, 730, 733, 736, 739, 740, 742, 745,
+ 748, 751, 754, 755, 757, 761, 763, 767,
+ 771, 775, 779, 783, 785, 786, 790, 794,
+ 798, 802, 804, 806, 810, 814, 818, 822,
+ 826, 828, 830, 833, 836, 839, 842, 845,
+ 846, 847, 849, 851, 853, 855, 861, 861,
+ 863, 869
+};
+
+static const char _tmedia_machine_imageattr_trans_keys[] = {
+ 9, 32, 82, 83, 114, 115, 69, 101,
+ 67, 99, 86, 118, 9, 32, 9, 32,
+ 42, 91, 69, 101, 67, 99, 86, 118,
+ 9, 32, 9, 32, 42, 91, 88, 120,
+ 61, 91, 49, 57, 44, 48, 57, 89,
+ 121, 61, 91, 49, 57, 44, 93, 48,
+ 57, 80, 81, 83, 112, 113, 115, 65,
+ 97, 82, 114, 61, 91, 48, 49, 57,
+ 46, 49, 57, 45, 48, 57, 48, 49,
+ 57, 46, 49, 57, 93, 48, 57, 93,
+ 48, 57, 93, 48, 57, 93, 44, 93,
+ 9, 32, 91, 46, 48, 57, 45, 48,
+ 57, 45, 48, 57, 45, 46, 48, 57,
+ 61, 48, 49, 46, 48, 57, 44, 93,
+ 48, 57, 44, 93, 46, 48, 44, 48,
+ 93, 65, 97, 82, 114, 61, 48, 91,
+ 49, 57, 46, 49, 57, 44, 93, 48,
+ 57, 44, 93, 48, 57, 44, 93, 48,
+ 57, 44, 93, 46, 48, 57, 48, 49,
+ 57, 46, 49, 57, 44, 45, 48, 57,
+ 48, 49, 57, 46, 49, 57, 44, 93,
+ 48, 57, 44, 93, 48, 57, 44, 93,
+ 48, 57, 44, 93, 44, 93, 46, 48,
+ 57, 48, 49, 57, 46, 49, 57, 93,
+ 48, 57, 93, 48, 57, 93, 48, 57,
+ 93, 44, 93, 46, 48, 57, 44, 45,
+ 48, 57, 44, 45, 48, 57, 44, 45,
+ 46, 48, 57, 44, 93, 48, 57, 44,
+ 93, 48, 57, 44, 93, 48, 57, 44,
+ 93, 48, 57, 44, 93, 49, 57, 44,
+ 58, 48, 57, 49, 57, 44, 93, 48,
+ 57, 44, 93, 48, 57, 44, 93, 48,
+ 57, 44, 93, 48, 57, 44, 93, 48,
+ 57, 44, 93, 44, 93, 44, 58, 48,
+ 57, 44, 58, 48, 57, 44, 58, 48,
+ 57, 44, 58, 48, 57, 44, 58, 49,
+ 57, 58, 93, 48, 57, 58, 93, 48,
+ 57, 58, 93, 48, 57, 58, 93, 48,
+ 57, 58, 93, 48, 57, 58, 93, 49,
+ 57, 93, 48, 57, 93, 48, 57, 93,
+ 48, 57, 93, 48, 57, 93, 48, 57,
+ 93, 44, 93, 44, 48, 57, 44, 48,
+ 57, 44, 48, 57, 44, 48, 57, 44,
+ 49, 57, 44, 58, 48, 57, 49, 57,
+ 44, 93, 48, 57, 44, 93, 48, 57,
+ 44, 93, 48, 57, 44, 93, 48, 57,
+ 44, 93, 48, 57, 44, 93, 44, 44,
+ 58, 48, 57, 44, 58, 48, 57, 44,
+ 58, 48, 57, 44, 58, 48, 57, 44,
+ 58, 49, 57, 58, 93, 48, 57, 58,
+ 93, 48, 57, 58, 93, 48, 57, 58,
+ 93, 48, 57, 58, 93, 48, 57, 58,
+ 93, 49, 57, 93, 48, 57, 93, 48,
+ 57, 93, 48, 57, 93, 48, 57, 93,
+ 48, 57, 93, 44, 69, 101, 78, 110,
+ 68, 100, 9, 32, 88, 120, 61, 91,
+ 49, 57, 44, 48, 57, 89, 121, 61,
+ 91, 49, 57, 44, 93, 48, 57, 80,
+ 81, 83, 112, 113, 115, 65, 97, 82,
+ 114, 61, 91, 48, 49, 57, 46, 49,
+ 57, 45, 48, 57, 48, 49, 57, 46,
+ 49, 57, 93, 48, 57, 93, 48, 57,
+ 93, 48, 57, 93, 44, 93, 46, 48,
+ 57, 45, 48, 57, 45, 48, 57, 45,
+ 46, 48, 57, 61, 48, 49, 46, 48,
+ 57, 44, 93, 48, 57, 44, 93, 46,
+ 48, 44, 48, 93, 65, 97, 82, 114,
+ 61, 48, 91, 49, 57, 46, 49, 57,
+ 44, 93, 48, 57, 44, 93, 48, 57,
+ 44, 93, 48, 57, 44, 93, 46, 48,
+ 57, 48, 49, 57, 46, 49, 57, 44,
+ 45, 48, 57, 48, 49, 57, 46, 49,
+ 57, 44, 93, 48, 57, 44, 93, 48,
+ 57, 44, 93, 48, 57, 44, 93, 44,
+ 93, 46, 48, 57, 48, 49, 57, 46,
+ 49, 57, 93, 48, 57, 93, 48, 57,
+ 93, 48, 57, 93, 44, 93, 46, 48,
+ 57, 44, 45, 48, 57, 44, 45, 48,
+ 57, 44, 45, 46, 48, 57, 44, 93,
+ 48, 57, 44, 93, 48, 57, 44, 93,
+ 48, 57, 44, 93, 48, 57, 44, 93,
+ 49, 57, 44, 58, 48, 57, 49, 57,
+ 44, 93, 48, 57, 44, 93, 48, 57,
+ 44, 93, 48, 57, 44, 93, 48, 57,
+ 44, 93, 48, 57, 44, 93, 44, 93,
+ 44, 58, 48, 57, 44, 58, 48, 57,
+ 44, 58, 48, 57, 44, 58, 48, 57,
+ 44, 58, 49, 57, 58, 93, 48, 57,
+ 58, 93, 48, 57, 58, 93, 48, 57,
+ 58, 93, 48, 57, 58, 93, 48, 57,
+ 58, 93, 49, 57, 93, 48, 57, 93,
+ 48, 57, 93, 48, 57, 93, 48, 57,
+ 93, 48, 57, 93, 44, 93, 44, 48,
+ 57, 44, 48, 57, 44, 48, 57, 44,
+ 48, 57, 44, 49, 57, 44, 58, 48,
+ 57, 49, 57, 44, 93, 48, 57, 44,
+ 93, 48, 57, 44, 93, 48, 57, 44,
+ 93, 48, 57, 44, 93, 48, 57, 44,
+ 93, 44, 44, 58, 48, 57, 44, 58,
+ 48, 57, 44, 58, 48, 57, 44, 58,
+ 48, 57, 44, 58, 49, 57, 58, 93,
+ 48, 57, 58, 93, 48, 57, 58, 93,
+ 48, 57, 58, 93, 48, 57, 58, 93,
+ 48, 57, 58, 93, 49, 57, 93, 48,
+ 57, 93, 48, 57, 93, 48, 57, 93,
+ 48, 57, 93, 48, 57, 93, 44, 69,
+ 101, 78, 110, 68, 100, 9, 32, 9,
+ 32, 82, 83, 114, 115, 9, 32, 9,
+ 32, 82, 83, 114, 115, 9, 32, 82,
+ 83, 91, 114, 115, 0
+};
+
+static const char _tmedia_machine_imageattr_single_lengths[] = {
+ 0, 6, 2, 2, 2, 2, 4, 2,
+ 2, 2, 2, 4, 2, 1, 1, 1,
+ 2, 1, 1, 2, 6, 2, 2, 1,
+ 1, 1, 1, 0, 1, 1, 1, 0,
+ 1, 1, 1, 1, 2, 3, 1, 0,
+ 1, 1, 1, 1, 0, 1, 2, 1,
+ 0, 2, 2, 1, 1, 3, 2, 2,
+ 1, 2, 1, 0, 2, 2, 2, 2,
+ 1, 0, 1, 1, 0, 2, 1, 1,
+ 0, 2, 2, 2, 2, 2, 1, 0,
+ 1, 1, 0, 1, 1, 1, 1, 2,
+ 1, 0, 2, 2, 2, 1, 0, 2,
+ 2, 2, 2, 2, 0, 2, 0, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 0, 2, 2, 2, 2,
+ 2, 2, 0, 1, 1, 1, 1, 1,
+ 1, 2, 1, 1, 1, 1, 1, 0,
+ 2, 0, 2, 2, 2, 2, 2, 2,
+ 1, 2, 2, 2, 2, 2, 0, 2,
+ 2, 2, 2, 2, 2, 0, 1, 1,
+ 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 2, 1, 1, 1, 2, 1, 1,
+ 2, 6, 2, 2, 1, 1, 1, 1,
+ 0, 1, 1, 1, 0, 1, 1, 1,
+ 1, 2, 1, 0, 1, 1, 1, 1,
+ 0, 1, 2, 1, 0, 2, 2, 1,
+ 1, 3, 2, 2, 1, 2, 1, 0,
+ 2, 2, 2, 2, 1, 0, 1, 1,
+ 0, 2, 1, 1, 0, 2, 2, 2,
+ 2, 2, 1, 0, 1, 1, 0, 1,
+ 1, 1, 1, 2, 1, 0, 2, 2,
+ 2, 1, 0, 2, 2, 2, 2, 2,
+ 0, 2, 0, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 0,
+ 2, 2, 2, 2, 2, 2, 0, 1,
+ 1, 1, 1, 1, 1, 2, 1, 1,
+ 1, 1, 1, 0, 2, 0, 2, 2,
+ 2, 2, 2, 2, 1, 2, 2, 2,
+ 2, 2, 0, 2, 2, 2, 2, 2,
+ 2, 0, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 6, 0, 2,
+ 6, 7
+};
+
+static const char _tmedia_machine_imageattr_range_lengths[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1,
+ 0, 0, 1, 1, 0, 0, 0, 0,
+ 0, 1, 0, 1, 1, 1, 0, 1,
+ 1, 1, 1, 0, 0, 0, 0, 1,
+ 1, 1, 0, 0, 1, 0, 0, 0,
+ 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 1, 1, 1, 0,
+ 0, 1, 1, 0, 1, 1, 1, 0,
+ 1, 1, 1, 1, 0, 0, 0, 1,
+ 1, 0, 1, 1, 1, 1, 0, 0,
+ 0, 1, 1, 1, 0, 0, 1, 1,
+ 1, 1, 1, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 0, 0, 1, 1,
+ 1, 1, 0, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 1, 1, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 1, 0, 1, 1,
+ 1, 1, 1, 1, 0, 1, 1, 1,
+ 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 1,
+ 1, 0, 0, 0, 0, 0, 1, 0,
+ 1, 1, 1, 0, 1, 1, 1, 1,
+ 0, 0, 0, 1, 1, 1, 0, 0,
+ 1, 0, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 1,
+ 1, 1, 1, 0, 0, 1, 1, 0,
+ 1, 1, 1, 0, 1, 1, 1, 1,
+ 0, 0, 0, 1, 1, 0, 1, 1,
+ 1, 1, 0, 0, 0, 1, 1, 1,
+ 0, 0, 1, 1, 1, 1, 1, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 1, 1, 0, 1,
+ 1, 1, 1, 1, 1, 0, 1, 1,
+ 1, 1, 1, 1, 0, 0, 1, 1,
+ 1, 1, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 0, 0, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1,
+ 0, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0
+};
+
+static const short _tmedia_machine_imageattr_index_offsets[] = {
+ 0, 0, 7, 10, 13, 16, 19, 24,
+ 27, 30, 33, 36, 41, 44, 46, 49,
+ 52, 55, 57, 60, 64, 71, 74, 77,
+ 79, 81, 84, 86, 88, 91, 94, 96,
+ 98, 101, 104, 107, 109, 112, 116, 118,
+ 120, 123, 126, 128, 130, 132, 134, 137,
+ 139, 141, 145, 148, 150, 152, 156, 159,
+ 162, 164, 168, 170, 172, 176, 180, 184,
+ 187, 189, 191, 194, 196, 198, 202, 205,
+ 207, 209, 213, 217, 221, 224, 227, 229,
+ 231, 234, 236, 238, 241, 244, 247, 249,
+ 252, 254, 256, 260, 264, 267, 269, 271,
+ 275, 279, 283, 287, 290, 292, 296, 298,
+ 302, 306, 310, 314, 318, 321, 324, 328,
+ 332, 336, 340, 343, 345, 349, 353, 357,
+ 361, 365, 368, 370, 373, 376, 379, 382,
+ 385, 387, 390, 393, 396, 399, 402, 404,
+ 406, 410, 412, 416, 420, 424, 428, 432,
+ 435, 437, 441, 445, 449, 453, 456, 458,
+ 462, 466, 470, 474, 478, 481, 483, 486,
+ 489, 492, 495, 498, 500, 502, 505, 508,
+ 511, 514, 517, 519, 522, 525, 528, 530,
+ 533, 537, 544, 547, 550, 552, 554, 557,
+ 559, 561, 564, 567, 569, 571, 574, 577,
+ 580, 582, 585, 587, 589, 592, 595, 597,
+ 599, 601, 603, 606, 608, 610, 614, 617,
+ 619, 621, 625, 628, 631, 633, 637, 639,
+ 641, 645, 649, 653, 656, 658, 660, 663,
+ 665, 667, 671, 674, 676, 678, 682, 686,
+ 690, 693, 696, 698, 700, 703, 705, 707,
+ 710, 713, 716, 718, 721, 723, 725, 729,
+ 733, 736, 738, 740, 744, 748, 752, 756,
+ 759, 761, 765, 767, 771, 775, 779, 783,
+ 787, 790, 793, 797, 801, 805, 809, 812,
+ 814, 818, 822, 826, 830, 834, 837, 839,
+ 842, 845, 848, 851, 854, 856, 859, 862,
+ 865, 868, 871, 873, 875, 879, 881, 885,
+ 889, 893, 897, 901, 904, 906, 910, 914,
+ 918, 922, 925, 927, 931, 935, 939, 943,
+ 947, 950, 952, 955, 958, 961, 964, 967,
+ 969, 971, 974, 977, 980, 983, 990, 991,
+ 994, 1001
+};
+
+static const short _tmedia_machine_imageattr_trans_targs[] = {
+ 1, 1, 2, 321, 2, 321, 0, 3,
+ 3, 0, 4, 4, 0, 5, 5, 0,
+ 6, 6, 0, 6, 6, 325, 169, 0,
+ 8, 8, 0, 9, 9, 0, 10, 10,
+ 0, 11, 11, 0, 11, 11, 326, 12,
+ 0, 13, 13, 0, 14, 0, 135, 15,
+ 0, 16, 130, 0, 17, 17, 0, 18,
+ 0, 100, 19, 0, 20, 327, 95, 0,
+ 21, 45, 54, 21, 45, 54, 0, 22,
+ 22, 0, 23, 23, 0, 24, 0, 25,
+ 0, 26, 43, 0, 27, 0, 28, 0,
+ 29, 40, 0, 30, 38, 0, 31, 0,
+ 32, 0, 36, 33, 0, 36, 34, 0,
+ 36, 35, 0, 36, 0, 20, 327, 0,
+ 37, 37, 12, 0, 39, 0, 32, 0,
+ 29, 41, 0, 29, 42, 0, 29, 0,
+ 44, 0, 28, 0, 46, 0, 47, 51,
+ 0, 48, 0, 49, 0, 20, 327, 50,
+ 0, 20, 327, 0, 52, 0, 53, 0,
+ 20, 50, 327, 0, 55, 55, 0, 56,
+ 56, 0, 57, 0, 58, 66, 64, 0,
+ 59, 0, 60, 0, 20, 327, 61, 0,
+ 20, 327, 62, 0, 20, 327, 63, 0,
+ 20, 327, 0, 65, 0, 60, 0, 67,
+ 93, 0, 68, 0, 69, 0, 70, 80,
+ 90, 0, 71, 78, 0, 72, 0, 73,
+ 0, 70, 77, 74, 0, 70, 77, 75,
+ 0, 70, 77, 76, 0, 70, 77, 0,
+ 20, 327, 0, 79, 0, 73, 0, 81,
+ 88, 0, 82, 0, 83, 0, 87, 84,
+ 0, 87, 85, 0, 87, 86, 0, 87,
+ 0, 20, 327, 0, 89, 0, 83, 0,
+ 70, 80, 91, 0, 70, 80, 92, 0,
+ 70, 80, 0, 94, 0, 69, 0, 20,
+ 327, 96, 0, 20, 327, 97, 0, 20,
+ 327, 98, 0, 20, 327, 99, 0, 20,
+ 327, 0, 101, 0, 102, 115, 110, 0,
+ 103, 0, 102, 109, 104, 0, 102, 109,
+ 105, 0, 102, 109, 106, 0, 102, 109,
+ 107, 0, 102, 109, 108, 0, 102, 109,
+ 0, 20, 327, 0, 102, 115, 111, 0,
+ 102, 115, 112, 0, 102, 115, 113, 0,
+ 102, 115, 114, 0, 102, 115, 0, 116,
+ 0, 122, 129, 117, 0, 122, 129, 118,
+ 0, 122, 129, 119, 0, 122, 129, 120,
+ 0, 122, 129, 121, 0, 122, 129, 0,
+ 123, 0, 129, 124, 0, 129, 125, 0,
+ 129, 126, 0, 129, 127, 0, 129, 128,
+ 0, 129, 0, 20, 327, 0, 16, 131,
+ 0, 16, 132, 0, 16, 133, 0, 16,
+ 134, 0, 16, 0, 136, 0, 137, 150,
+ 145, 0, 138, 0, 137, 144, 139, 0,
+ 137, 144, 140, 0, 137, 144, 141, 0,
+ 137, 144, 142, 0, 137, 144, 143, 0,
+ 137, 144, 0, 16, 0, 137, 150, 146,
+ 0, 137, 150, 147, 0, 137, 150, 148,
+ 0, 137, 150, 149, 0, 137, 150, 0,
+ 151, 0, 157, 164, 152, 0, 157, 164,
+ 153, 0, 157, 164, 154, 0, 157, 164,
+ 155, 0, 157, 164, 156, 0, 157, 164,
+ 0, 158, 0, 164, 159, 0, 164, 160,
+ 0, 164, 161, 0, 164, 162, 0, 164,
+ 163, 0, 164, 0, 16, 0, 166, 166,
+ 0, 167, 167, 0, 168, 168, 0, 11,
+ 11, 0, 170, 170, 0, 171, 0, 291,
+ 172, 0, 173, 286, 0, 174, 174, 0,
+ 175, 0, 256, 176, 0, 177, 328, 251,
+ 0, 178, 201, 210, 178, 201, 210, 0,
+ 179, 179, 0, 180, 180, 0, 181, 0,
+ 182, 0, 183, 199, 0, 184, 0, 185,
+ 0, 186, 196, 0, 187, 194, 0, 188,
+ 0, 189, 0, 193, 190, 0, 193, 191,
+ 0, 193, 192, 0, 193, 0, 177, 328,
+ 0, 195, 0, 189, 0, 186, 197, 0,
+ 186, 198, 0, 186, 0, 200, 0, 185,
+ 0, 202, 0, 203, 207, 0, 204, 0,
+ 205, 0, 177, 328, 206, 0, 177, 328,
+ 0, 208, 0, 209, 0, 177, 206, 328,
+ 0, 211, 211, 0, 212, 212, 0, 213,
+ 0, 214, 222, 220, 0, 215, 0, 216,
+ 0, 177, 328, 217, 0, 177, 328, 218,
+ 0, 177, 328, 219, 0, 177, 328, 0,
+ 221, 0, 216, 0, 223, 249, 0, 224,
+ 0, 225, 0, 226, 236, 246, 0, 227,
+ 234, 0, 228, 0, 229, 0, 226, 233,
+ 230, 0, 226, 233, 231, 0, 226, 233,
+ 232, 0, 226, 233, 0, 177, 328, 0,
+ 235, 0, 229, 0, 237, 244, 0, 238,
+ 0, 239, 0, 243, 240, 0, 243, 241,
+ 0, 243, 242, 0, 243, 0, 177, 328,
+ 0, 245, 0, 239, 0, 226, 236, 247,
+ 0, 226, 236, 248, 0, 226, 236, 0,
+ 250, 0, 225, 0, 177, 328, 252, 0,
+ 177, 328, 253, 0, 177, 328, 254, 0,
+ 177, 328, 255, 0, 177, 328, 0, 257,
+ 0, 258, 271, 266, 0, 259, 0, 258,
+ 265, 260, 0, 258, 265, 261, 0, 258,
+ 265, 262, 0, 258, 265, 263, 0, 258,
+ 265, 264, 0, 258, 265, 0, 177, 328,
+ 0, 258, 271, 267, 0, 258, 271, 268,
+ 0, 258, 271, 269, 0, 258, 271, 270,
+ 0, 258, 271, 0, 272, 0, 278, 285,
+ 273, 0, 278, 285, 274, 0, 278, 285,
+ 275, 0, 278, 285, 276, 0, 278, 285,
+ 277, 0, 278, 285, 0, 279, 0, 285,
+ 280, 0, 285, 281, 0, 285, 282, 0,
+ 285, 283, 0, 285, 284, 0, 285, 0,
+ 177, 328, 0, 173, 287, 0, 173, 288,
+ 0, 173, 289, 0, 173, 290, 0, 173,
+ 0, 292, 0, 293, 306, 301, 0, 294,
+ 0, 293, 300, 295, 0, 293, 300, 296,
+ 0, 293, 300, 297, 0, 293, 300, 298,
+ 0, 293, 300, 299, 0, 293, 300, 0,
+ 173, 0, 293, 306, 302, 0, 293, 306,
+ 303, 0, 293, 306, 304, 0, 293, 306,
+ 305, 0, 293, 306, 0, 307, 0, 313,
+ 320, 308, 0, 313, 320, 309, 0, 313,
+ 320, 310, 0, 313, 320, 311, 0, 313,
+ 320, 312, 0, 313, 320, 0, 314, 0,
+ 320, 315, 0, 320, 316, 0, 320, 317,
+ 0, 320, 318, 0, 320, 319, 0, 320,
+ 0, 173, 0, 322, 322, 0, 323, 323,
+ 0, 324, 324, 0, 6, 6, 0, 325,
+ 325, 7, 165, 7, 165, 0, 0, 37,
+ 37, 0, 329, 329, 7, 165, 7, 165,
+ 0, 329, 329, 7, 165, 169, 7, 165,
+ 0, 0
+};
+
+static const char _tmedia_machine_imageattr_trans_actions[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 5, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 5, 5, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 7, 43,
+ 0, 49, 0, 0, 0, 0, 0, 0,
+ 0, 9, 46, 0, 49, 49, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0,
+ 39, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 41, 0, 0, 41, 0, 0,
+ 41, 0, 0, 41, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 39, 0, 0, 39, 0, 0, 39, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1,
+ 0, 0, 0, 0, 0, 25, 25, 0,
+ 0, 25, 25, 0, 0, 0, 0, 0,
+ 25, 0, 25, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 52, 31, 52, 0,
+ 0, 0, 0, 0, 55, 55, 0, 0,
+ 55, 55, 0, 0, 55, 55, 0, 0,
+ 55, 55, 0, 0, 0, 0, 0, 1,
+ 1, 0, 0, 0, 0, 0, 33, 35,
+ 0, 0, 1, 1, 0, 0, 0, 0,
+ 0, 33, 33, 0, 0, 33, 33, 0,
+ 0, 33, 33, 0, 0, 33, 33, 0,
+ 27, 27, 0, 0, 0, 0, 0, 1,
+ 1, 0, 0, 0, 0, 0, 37, 0,
+ 0, 37, 0, 0, 37, 0, 0, 37,
+ 0, 29, 29, 0, 0, 0, 0, 0,
+ 33, 35, 0, 0, 33, 35, 0, 0,
+ 33, 35, 0, 0, 0, 0, 0, 49,
+ 49, 0, 0, 49, 49, 0, 0, 49,
+ 49, 0, 0, 49, 49, 0, 0, 49,
+ 49, 0, 1, 0, 23, 17, 0, 0,
+ 1, 0, 23, 23, 0, 0, 23, 23,
+ 0, 0, 23, 23, 0, 0, 23, 23,
+ 0, 0, 23, 23, 0, 0, 23, 23,
+ 0, 13, 13, 0, 23, 17, 0, 0,
+ 23, 17, 0, 0, 23, 17, 0, 0,
+ 23, 17, 0, 0, 23, 17, 0, 1,
+ 0, 19, 21, 0, 0, 19, 21, 0,
+ 0, 19, 21, 0, 0, 19, 21, 0,
+ 0, 19, 21, 0, 0, 19, 21, 0,
+ 1, 0, 21, 0, 0, 21, 0, 0,
+ 21, 0, 0, 21, 0, 0, 21, 0,
+ 0, 21, 0, 15, 15, 0, 49, 0,
+ 0, 49, 0, 0, 49, 0, 0, 49,
+ 0, 0, 49, 0, 1, 0, 23, 17,
+ 0, 0, 1, 0, 23, 23, 0, 0,
+ 23, 23, 0, 0, 23, 23, 0, 0,
+ 23, 23, 0, 0, 23, 23, 0, 0,
+ 23, 23, 0, 13, 0, 23, 17, 0,
+ 0, 23, 17, 0, 0, 23, 17, 0,
+ 0, 23, 17, 0, 0, 23, 17, 0,
+ 1, 0, 19, 21, 0, 0, 19, 21,
+ 0, 0, 19, 21, 0, 0, 19, 21,
+ 0, 0, 19, 21, 0, 0, 19, 21,
+ 0, 1, 0, 21, 0, 0, 21, 0,
+ 0, 21, 0, 0, 21, 0, 0, 21,
+ 0, 0, 21, 0, 15, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 3,
+ 3, 0, 0, 0, 0, 0, 0, 7,
+ 43, 0, 49, 0, 0, 0, 0, 0,
+ 0, 0, 9, 46, 0, 49, 49, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 0, 0, 0, 0,
+ 0, 39, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 41, 0, 0, 41, 0,
+ 0, 41, 0, 0, 41, 0, 0, 0,
+ 0, 0, 0, 0, 0, 39, 0, 0,
+ 39, 0, 0, 39, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 0, 0, 0,
+ 0, 0, 25, 25, 0, 0, 25, 25,
+ 0, 0, 0, 0, 0, 25, 0, 25,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 52, 31, 52, 0, 0, 0, 0,
+ 0, 55, 55, 0, 0, 55, 55, 0,
+ 0, 55, 55, 0, 0, 55, 55, 0,
+ 0, 0, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 33, 35, 0, 0, 1,
+ 1, 0, 0, 0, 0, 0, 33, 33,
+ 0, 0, 33, 33, 0, 0, 33, 33,
+ 0, 0, 33, 33, 0, 27, 27, 0,
+ 0, 0, 0, 0, 1, 1, 0, 0,
+ 0, 0, 0, 37, 0, 0, 37, 0,
+ 0, 37, 0, 0, 37, 0, 29, 29,
+ 0, 0, 0, 0, 0, 33, 35, 0,
+ 0, 33, 35, 0, 0, 33, 35, 0,
+ 0, 0, 0, 0, 49, 49, 0, 0,
+ 49, 49, 0, 0, 49, 49, 0, 0,
+ 49, 49, 0, 0, 49, 49, 0, 1,
+ 0, 23, 17, 0, 0, 1, 0, 23,
+ 23, 0, 0, 23, 23, 0, 0, 23,
+ 23, 0, 0, 23, 23, 0, 0, 23,
+ 23, 0, 0, 23, 23, 0, 13, 13,
+ 0, 23, 17, 0, 0, 23, 17, 0,
+ 0, 23, 17, 0, 0, 23, 17, 0,
+ 0, 23, 17, 0, 1, 0, 19, 21,
+ 0, 0, 19, 21, 0, 0, 19, 21,
+ 0, 0, 19, 21, 0, 0, 19, 21,
+ 0, 0, 19, 21, 0, 1, 0, 21,
+ 0, 0, 21, 0, 0, 21, 0, 0,
+ 21, 0, 0, 21, 0, 0, 21, 0,
+ 15, 15, 0, 49, 0, 0, 49, 0,
+ 0, 49, 0, 0, 49, 0, 0, 49,
+ 0, 1, 0, 23, 17, 0, 0, 1,
+ 0, 23, 23, 0, 0, 23, 23, 0,
+ 0, 23, 23, 0, 0, 23, 23, 0,
+ 0, 23, 23, 0, 0, 23, 23, 0,
+ 13, 0, 23, 17, 0, 0, 23, 17,
+ 0, 0, 23, 17, 0, 0, 23, 17,
+ 0, 0, 23, 17, 0, 1, 0, 19,
+ 21, 0, 0, 19, 21, 0, 0, 19,
+ 21, 0, 0, 19, 21, 0, 0, 19,
+ 21, 0, 0, 19, 21, 0, 1, 0,
+ 21, 0, 0, 21, 0, 0, 21, 0,
+ 0, 21, 0, 0, 21, 0, 0, 21,
+ 0, 15, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 11,
+ 11, 0, 11, 11, 11, 11, 11, 11,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0
+};
+
+static const char _tmedia_machine_imageattr_eof_actions[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 11,
+ 11, 0
+};
+
+static const int tmedia_machine_imageattr_start = 1;
+static const int tmedia_machine_imageattr_first_final = 325;
+static const int tmedia_machine_imageattr_error = 0;
+
+static const int tmedia_machine_imageattr_en_main = 1;
+
+
+/* #line 168 "./ragel/tmedia_imageattr.rl" */
+ (void)(eof);
+ (void)(tmedia_machine_imageattr_first_final);
+ (void)(tmedia_machine_imageattr_error);
+ (void)(tmedia_machine_imageattr_en_main);
+
+/* #line 695 "./src/tmedia_imageattr.c" */
+ {
+ cs = tmedia_machine_imageattr_start;
+ }
+
+/* #line 173 "./ragel/tmedia_imageattr.rl" */
+ tmedia_imageattr_reset(self);
+
+/* #line 703 "./src/tmedia_imageattr.c" */
+ {
+ int _klen;
+ unsigned int _trans;
+ const char *_acts;
+ unsigned int _nacts;
+ const char *_keys;
+
+ if ( p == pe )
+ goto _test_eof;
+ if ( cs == 0 )
+ goto _out;
+_resume:
+ _keys = _tmedia_machine_imageattr_trans_keys + _tmedia_machine_imageattr_key_offsets[cs];
+ _trans = _tmedia_machine_imageattr_index_offsets[cs];
+
+ _klen = _tmedia_machine_imageattr_single_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + _klen - 1;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( (*p) < *_mid )
+ _upper = _mid - 1;
+ else if ( (*p) > *_mid )
+ _lower = _mid + 1;
+ else {
+ _trans += (_mid - _keys);
+ goto _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _tmedia_machine_imageattr_range_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( (*p) < _mid[0] )
+ _upper = _mid - 2;
+ else if ( (*p) > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ _trans += ((_mid - _keys)>>1);
+ goto _match;
+ }
+ }
+ _trans += _klen;
+ }
+
+_match:
+ cs = _tmedia_machine_imageattr_trans_targs[_trans];
+
+ if ( _tmedia_machine_imageattr_trans_actions[_trans] == 0 )
+ goto _again;
+
+ _acts = _tmedia_machine_imageattr_actions + _tmedia_machine_imageattr_trans_actions[_trans];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 )
+ {
+ switch ( *_acts++ )
+ {
+ case 0:
+/* #line 40 "./ragel/tmedia_imageattr.rl" */
+ {
+ tag_start = p;
+ }
+ break;
+ case 1:
+/* #line 44 "./ragel/tmedia_imageattr.rl" */
+ {
+ sets = &self->send.sets[0];
+ sets_count = &self->send.count;
+ *sets_count = 0;
+ }
+ break;
+ case 2:
+/* #line 50 "./ragel/tmedia_imageattr.rl" */
+ {
+ sets = &self->recv.sets[0];
+ sets_count = &self->recv.count;
+ *sets_count = 0;
+ }
+ break;
+ case 3:
+/* #line 56 "./ragel/tmedia_imageattr.rl" */
+ {
+ xyrange = (*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE) ? &sets[*sets_count].xrange : tsk_null;
+ }
+ break;
+ case 4:
+/* #line 59 "./ragel/tmedia_imageattr.rl" */
+ {
+ xyrange = (*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE) ? &sets[*sets_count].yrange : tsk_null;
+ }
+ break;
+ case 5:
+/* #line 62 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE) (*sets_count)++;
+ }
+ break;
+ case 6:
+/* #line 65 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(xyrange) xyrange->is_range = 0;
+ }
+ break;
+ case 7:
+/* #line 68 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(xyrange) xyrange->is_range = 1;
+ }
+ break;
+ case 8:
+/* #line 71 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(xyrange)xyrange->range.start = atoi(tag_start);
+ }
+ break;
+ case 9:
+/* #line 74 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(xyrange)xyrange->range.step = atoi(tag_start);
+ }
+ break;
+ case 10:
+/* #line 77 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(xyrange)xyrange->range.end = atoi(tag_start);
+ }
+ break;
+ case 11:
+/* #line 80 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(xyrange && xyrange->array.count < TMEDIA_imageattr_ARRAY_MAX_SIZE){
+ xyrange->array.values[xyrange->array.count++] = atoi(tag_start);
+ }
+ }
+ break;
+ case 12:
+/* #line 85 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE){
+ sets[*sets_count].qvalue = atof(tag_start);
+ }
+ }
+ break;
+ case 13:
+/* #line 91 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(srange) srange->is_range = 0;
+ }
+ break;
+ case 14:
+/* #line 94 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(srange) srange->is_range = 1;
+ }
+ break;
+ case 15:
+/* #line 97 "./ragel/tmedia_imageattr.rl" */
+ {
+ srange = (*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE) ? &sets[*sets_count].srange : tsk_null;
+ }
+ break;
+ case 16:
+/* #line 100 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(srange && srange->array.count < TMEDIA_imageattr_ARRAY_MAX_SIZE){
+ srange->array.values[srange->array.count++] = atof(tag_start);
+ }
+ }
+ break;
+ case 17:
+/* #line 105 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(srange) srange->range.start = atof(tag_start);
+ }
+ break;
+ case 18:
+/* #line 108 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(srange) srange->range.end = atof(tag_start);
+ }
+ break;
+ case 19:
+/* #line 112 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE) sets[*sets_count].prange.start = atof(tag_start);
+ }
+ break;
+ case 20:
+/* #line 115 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE) sets[*sets_count].prange.end = atof(tag_start), sets[*sets_count].prange.is_present = 1;
+ }
+ break;
+/* #line 912 "./src/tmedia_imageattr.c" */
+ }
+ }
+
+_again:
+ if ( cs == 0 )
+ goto _out;
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ if ( p == eof )
+ {
+ const char *__acts = _tmedia_machine_imageattr_actions + _tmedia_machine_imageattr_eof_actions[cs];
+ unsigned int __nacts = (unsigned int) *__acts++;
+ while ( __nacts-- > 0 ) {
+ switch ( *__acts++ ) {
+ case 5:
+/* #line 62 "./ragel/tmedia_imageattr.rl" */
+ {
+ if(*sets_count < TMEDIA_imageattr_ARRAY_MAX_SIZE) (*sets_count)++;
+ }
+ break;
+/* #line 934 "./src/tmedia_imageattr.c" */
+ }
+ }
+ }
+
+ _out: {}
+ }
+
+/* #line 175 "./ragel/tmedia_imageattr.rl" */
+ TSK_RAGEL_DISABLE_WARNINGS_END()
+
+ if( cs <
+/* #line 946 "./src/tmedia_imageattr.c" */
+325
+/* #line 177 "./ragel/tmedia_imageattr.rl" */
+ ){
+ TSK_DEBUG_ERROR("Parsing failed to parse image-attr=%s", (char*)in_data);
+ return -1;
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/tinyMEDIA/src/tmedia_jitterbuffer.c b/tinyMEDIA/src/tmedia_jitterbuffer.c
new file mode 100644
index 0000000..108eee1
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_jitterbuffer.c
@@ -0,0 +1,281 @@
+/*
+* Copyright (C) 2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_jitterbuffer.c
+ * @brief Audio/Video JitterBuffer plugin
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ */
+#include "tinymedia/tmedia_jitterbuffer.h"
+
+#include "tsk_debug.h"
+
+/* pointer to all registered jitter_buffers */
+static const tmedia_jitterbuffer_plugin_def_t* __tmedia_jitterbuffer_plugins[TMED_JITTER_BUFFER_MAX_PLUGINS] = {0};
+
+int tmedia_jitterbuffer_init(tmedia_jitterbuffer_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return 0;
+}
+
+int tmedia_jitterbuffer_set(tmedia_jitterbuffer_t *self, const tmedia_param_t* param)
+{
+ if(!self || !self->plugin || !param){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return 0;
+ }
+ return self->plugin->set ? self->plugin->set(self, param) : 0;
+}
+
+int tmedia_jitterbuffer_open(tmedia_jitterbuffer_t* self, uint32_t frame_duration, uint32_t rate, uint32_t channels)
+{
+ int ret;
+
+ if(!self || !self->plugin || !self->plugin->open){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if(self->opened){
+ TSK_DEBUG_WARN("JitterBuffer already opened");
+ return 0;
+ }
+
+ if((ret = self->plugin->open(self, frame_duration, rate, channels))){
+ TSK_DEBUG_ERROR("Failed to open [%s] jitterbufferr", self->plugin->desc);
+ return ret;
+ }
+ else{
+ self->opened = tsk_true;
+ return 0;
+ }
+}
+
+int tmedia_jitterbuffer_tick(tmedia_jitterbuffer_t* self)
+{
+ if(!self || !self->plugin || !self->plugin->tick){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(!self->opened){
+ TSK_DEBUG_ERROR("JitterBuffer not opened");
+ return -1;
+ }
+
+ return self->plugin->tick(self);
+}
+
+int tmedia_jitterbuffer_put(tmedia_jitterbuffer_t* self, void* data, tsk_size_t data_size, const tsk_object_t* proto_hdr)
+{
+ if(!self || !self->plugin || !self->plugin->put){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(!self->opened){
+ TSK_DEBUG_ERROR("JitterBuffer not opened");
+ return -1;
+ }
+
+ return self->plugin->put(self, data, data_size, proto_hdr);
+}
+
+tsk_size_t tmedia_jitterbuffer_get(tmedia_jitterbuffer_t* self, void* out_data, tsk_size_t out_size)
+{
+ if(!self || !self->plugin || !self->plugin->get){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return 0;
+ }
+
+ if(!self->opened){
+ TSK_DEBUG_ERROR("JitterBuffer not opened");
+ return 0;
+ }
+
+ return self->plugin->get(self, out_data, out_size);
+}
+
+int tmedia_jitterbuffer_reset(tmedia_jitterbuffer_t* self)
+{
+ if(!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if(self->opened && self->plugin->reset){
+ return self->plugin->reset(self);
+ }
+
+ return 0;
+}
+
+int tmedia_jitterbuffer_close(tmedia_jitterbuffer_t* self)
+{
+ if(!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if(!self->opened){
+ TSK_DEBUG_WARN("JitterBuffer not opened");
+ return 0;
+ }
+
+ if(self->plugin->close){
+ int ret;
+
+ if((ret = self->plugin->close(self))){
+ TSK_DEBUG_ERROR("Failed to close [%s] jitterbufferr", self->plugin->desc);
+ return ret;
+ }
+ else{
+ self->opened = tsk_false;
+ return 0;
+ }
+ }
+ else{
+ self->opened = tsk_false;
+ return 0;
+ }
+}
+
+int tmedia_jitterbuffer_deinit(tmedia_jitterbuffer_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(self->opened){
+ tmedia_jitterbuffer_close(self);
+ }
+
+ return 0;
+}
+
+tmedia_jitterbuffer_t* tmedia_jitterbuffer_create(tmedia_type_t type)
+{
+ tmedia_jitterbuffer_t* jitter_buffer = tsk_null;
+ const tmedia_jitterbuffer_plugin_def_t* plugin;
+ tsk_size_t i = 0;
+
+ while((i < TMED_JITTER_BUFFER_MAX_PLUGINS) && (plugin = __tmedia_jitterbuffer_plugins[i++])){
+ if(plugin->objdef && plugin->type == type){
+ if((jitter_buffer = tsk_object_new(plugin->objdef))){
+ /* initialize the newly created jitter_buffer */
+ jitter_buffer->plugin = plugin;
+ break;
+ }
+ }
+ }
+
+ return jitter_buffer;
+}
+
+int tmedia_jitterbuffer_plugin_register(const tmedia_jitterbuffer_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ if(!plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* add or replace the plugin */
+ for(i = 0; i<TMED_JITTER_BUFFER_MAX_PLUGINS; i++){
+ if(!__tmedia_jitterbuffer_plugins[i] || (__tmedia_jitterbuffer_plugins[i] == plugin)){
+ __tmedia_jitterbuffer_plugins[i] = plugin;
+ return 0;
+ }
+ }
+
+ TSK_DEBUG_ERROR("There are already %d plugins.", TMED_JITTER_BUFFER_MAX_PLUGINS);
+ return -2;
+}
+
+/**@ingroup tmedia_jitterbuffer_group
+* UnRegisters a jitter_buffer plugin.
+* @param plugin the definition of the plugin.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tmedia_jitterbuffer_plugin_unregister(const tmedia_jitterbuffer_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+ if(!plugin){
+ TSK_DEBUG_ERROR("Invalid Parameter");
+ return -1;
+ }
+
+ /* find the plugin to unregister */
+ for(i = 0; i<TMED_JITTER_BUFFER_MAX_PLUGINS && __tmedia_jitterbuffer_plugins[i]; i++){
+ if(__tmedia_jitterbuffer_plugins[i] == plugin){
+ __tmedia_jitterbuffer_plugins[i] = tsk_null;
+ found = tsk_true;
+ break;
+ }
+ }
+
+ /* compact */
+ if(found){
+ for(; i<(TMED_JITTER_BUFFER_MAX_PLUGINS - 1); i++){
+ if(__tmedia_jitterbuffer_plugins[i+1]){
+ __tmedia_jitterbuffer_plugins[i] = __tmedia_jitterbuffer_plugins[i+1];
+ }
+ else{
+ break;
+ }
+ }
+ __tmedia_jitterbuffer_plugins[i] = tsk_null;
+ }
+ return (found ? 0 : -2);
+}
+
+int tmedia_jitterbuffer_plugin_unregister_by_type(tmedia_type_t type)
+{
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+
+ /* find the plugin to unregister */
+ for(i = 0; i<TMED_JITTER_BUFFER_MAX_PLUGINS && __tmedia_jitterbuffer_plugins[i]; i++){
+ if((__tmedia_jitterbuffer_plugins[i]->type & type) == __tmedia_jitterbuffer_plugins[i]->type){
+ __tmedia_jitterbuffer_plugins[i] = tsk_null;
+ found = tsk_true;
+ break;
+ }
+ }
+
+ /* compact */
+ if(found){
+ for(; i<(TMED_JITTER_BUFFER_MAX_PLUGINS - 1); i++){
+ if(__tmedia_jitterbuffer_plugins[i+1]){
+ __tmedia_jitterbuffer_plugins[i] = __tmedia_jitterbuffer_plugins[i+1];
+ }
+ else{
+ break;
+ }
+ }
+ __tmedia_jitterbuffer_plugins[i] = tsk_null;
+ }
+ return (found ? 0 : -2);
+}
diff --git a/tinyMEDIA/src/tmedia_params.c b/tinyMEDIA/src/tmedia_params.c
new file mode 100644
index 0000000..85e9df3
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_params.c
@@ -0,0 +1,197 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_params.c
+ * @brief Media parameters used to configure any session or plugin.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tinymedia/tmedia_params.h"
+
+#include "tinymedia/tmedia_session.h"
+
+#include "tsk_params.h"
+#include "tsk_debug.h"
+#include "tsk_memory.h"
+
+tmedia_param_t* tmedia_param_create(tmedia_param_access_type_t access_type,
+ tmedia_type_t media_type,
+ tmedia_param_plugin_type_t plugin_type,
+ tmedia_param_value_type_t value_type,
+ const char* key,
+ void* value)
+{
+ tmedia_param_t* param;
+
+ if(!key || (!value && (value_type != tmedia_pvt_pobject && value_type != tmedia_pvt_pchar))){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ if((param = tsk_object_new(tmedia_param_def_t))){
+ param->access_type = access_type;
+ param->media_type = media_type;
+ param->plugin_type = plugin_type;
+ param->value_type = value_type;
+ param->key = tsk_strdup(key);
+ if(access_type == tmedia_pat_get){
+ param->value = (value);
+ }
+ else if(access_type == tmedia_pat_set){
+ switch(value_type){
+ case tmedia_pvt_int32:
+ if((param->value = tsk_calloc(1, sizeof(int32_t)))){
+ memcpy(param->value, value, sizeof(int32_t));
+ }
+ break;
+ case tmedia_pvt_pobject:
+ param->value = tsk_object_ref(value);
+ break;
+ case tmedia_pvt_pchar:
+ param->value = tsk_strdup(value);
+ break;
+ case tmedia_pvt_int64:
+ if((param->value = tsk_calloc(1, sizeof(int64_t)))){
+ memcpy(param->value, value, sizeof(int64_t));
+ }
+ break;
+ }
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to create media parameter");
+ }
+ return param;
+}
+
+tmedia_params_L_t* tmedia_params_create_2(va_list *app)
+{
+ tmedia_session_param_type_t curr;
+ tmedia_params_L_t* params;
+
+ if(!app){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ params = tmedia_params_create();
+
+ while((curr = va_arg(*app, tmedia_session_param_type_t)) != tmedia_sptype_null){
+ switch(curr){
+ case tmedia_sptype_set:
+ case tmedia_sptype_get:
+ { /* (tmedia_type_t)MEDIA_TYPE_ENUM, (tmedia_param_plugin_type_t)PLUGIN_TYPE_ENUM, (tmedia_param_value_type_t)VALUE_TYPE_ENUM \
+ (const char*)KEY_STR, (void*)&VALUE */
+ /* IMPORTANT: do not pass va_arg() directly into the function */
+ tmedia_type_t media_type = va_arg(*app, tmedia_type_t);
+ tmedia_param_plugin_type_t plugin_type = va_arg(*app, tmedia_param_plugin_type_t);
+ tmedia_param_value_type_t value_type = va_arg(*app, tmedia_param_value_type_t);
+ const char* key = va_arg(*app, const char*);
+ void* value = va_arg(*app, void*);
+ tmedia_params_add_param(&params, (curr == tmedia_sptype_set) ? tmedia_pat_set : tmedia_pat_get,
+ media_type, plugin_type, value_type, key, value);
+ break;
+ }
+ default:
+ { /* va_list will be unsafe => exit */
+ TSK_DEBUG_ERROR("%d NOT a valid pname", curr);
+ break;
+ }
+ }/* switch */
+ }/* while */
+
+ return params;
+}
+
+int tmedia_params_add_param(tmedia_params_L_t **self,
+ tmedia_param_access_type_t access_type,
+ tmedia_type_t media_type,
+ tmedia_param_plugin_type_t plugin_type,
+ tmedia_param_value_type_t value_type,
+ const char* key,
+ void* value)
+{
+ tmedia_param_t *param;
+
+ if(!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(!*self){
+ *self = tmedia_params_create();
+ }
+
+ if((param = tmedia_param_create(access_type, media_type, plugin_type, value_type, key, value))){
+ tsk_list_push_back_data(*self, (void**)&param);
+ }
+ return 0;
+}
+
+
+
+
+//=================================================================================================
+// param object definition
+//
+static tsk_object_t* tmedia_param_ctor(tsk_object_t* self, va_list * app)
+{
+ tmedia_param_t *param = self;
+ if(param){
+ }
+
+ return self;
+}
+
+static tsk_object_t* tmedia_param_dtor(tsk_object_t* self)
+{
+ tmedia_param_t *param = self;
+ if(param){
+ TSK_FREE(param->key);
+ if(param->access_type == tmedia_pat_set){
+ switch(param->value_type){
+ case tmedia_pvt_pobject:
+ TSK_OBJECT_SAFE_FREE(param->value);
+ break;
+ case tmedia_pvt_pchar:
+ case tmedia_pvt_int64:
+ case tmedia_pvt_int32:
+ TSK_FREE(param->value);
+ break;
+ }
+ }
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tmedia_param_def_s =
+{
+ sizeof(tmedia_param_t),
+ tmedia_param_ctor,
+ tmedia_param_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tmedia_param_def_t = &tmedia_param_def_s;
+
diff --git a/tinyMEDIA/src/tmedia_producer.c b/tinyMEDIA/src/tmedia_producer.c
new file mode 100644
index 0000000..4b7c252
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_producer.c
@@ -0,0 +1,304 @@
+/*
+* Copyright (C) 2010-2014 Mamadou DIOP
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tmedia_producer.c
+ * @brief Base producer object.
+ */
+#include "tinymedia/tmedia_producer.h"
+#include "tinymedia/tmedia_defaults.h"
+
+#include "tsk_debug.h"
+
+/**@defgroup tmedia_producer_group Producers
+*/
+
+/* pointer to all registered producers */
+const tmedia_producer_plugin_def_t* __tmedia_producer_plugins[TMED_PRODUCER_MAX_PLUGINS] = {0};
+
+/**@ingroup tmedia_producer_group
+* Initialize the producer.
+* @param self The producer to initialize
+* @retval Zero if succeed and non-zero error code otherwise.
+*
+* @sa @ref tmedia_producer_deinit
+*/
+int tmedia_producer_init(tmedia_producer_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ self->video.chroma = TMEDIA_PRODUCER_CHROMA_DEFAULT;
+ self->audio.bits_per_sample = TMEDIA_PRODUCER_BITS_PER_SAMPLE_DEFAULT;
+ self->audio.channels = TMEDIA_PRODUCER_CHANNELS_DEFAULT;
+ self->audio.rate = TMEDIA_PRODUCER_RATE_DEFAULT;
+ self->audio.volume = tmedia_defaults_get_volume();
+
+ return 0;
+}
+
+/**@ingroup tmedia_producer_group
+* callback to encode and send() data
+*/
+int tmedia_producer_set_enc_callback(tmedia_producer_t *self, tmedia_producer_enc_cb_f callback, const void* callback_data)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ self->enc_cb.callback = callback;
+ self->enc_cb.callback_data = callback_data;
+
+ return 0;
+}
+
+/**@ingroup tmedia_producer_group
+* callback to send() data "as is"
+*/
+int tmedia_producer_set_raw_callback(tmedia_producer_t *self, tmedia_producer_raw_cb_f callback, const void* callback_data)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ self->raw_cb.callback = callback;
+ self->raw_cb.chunck_curr.usr_data = callback_data;
+
+ return 0;
+}
+
+/**@ingroup tmedia_producer_group
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_producer_set(tmedia_producer_t* self, const tmedia_param_t* param)
+{
+ if(!self || !self->plugin || !self->plugin->set || !param){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return self->plugin->set(self, param);
+}
+
+/**@ingroup tmedia_producer_group
+* Alert the producer to be prepared to start.
+* @param self the producer to prepare
+* @param codec The codec to use to prepare the producer
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_producer_prepare(tmedia_producer_t *self, const tmedia_codec_t* codec)
+{
+ int ret;
+ if (!self || !self->plugin || !self->plugin->prepare || !codec) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if ((ret = self->plugin->prepare(self, codec)) == 0) {
+ self->is_prepared = tsk_true;
+ }
+ return ret;
+}
+
+/**@ingroup tmedia_producer_group
+* Starts the producer
+* @param self The producer to start
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_producer_start(tmedia_producer_t *self)
+{
+ int ret;
+ if (!self || !self->plugin || !self->plugin->start) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if ((ret = self->plugin->start(self)) == 0) {
+ self->is_started = tsk_true;
+ }
+ return ret;
+}
+
+
+/**@ingroup tmedia_producer_group
+* Pauses the producer
+* @param self The producer to pause
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_producer_pause(tmedia_producer_t *self)
+{
+ if (!self || !self->plugin || !self->plugin->pause) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return self->plugin->pause(self);
+}
+
+
+/**@ingroup tmedia_producer_group
+* Stops the producer
+* @param self The producer to stop
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_producer_stop(tmedia_producer_t *self)
+{
+ int ret;
+ if (!self || !self->plugin || !self->plugin->stop) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if ((ret = self->plugin->stop(self)) == 0) {
+ self->is_started = tsk_false;
+ }
+ return ret;
+}
+
+
+/**@ingroup tmedia_producer_group
+* DeInitialize the producer.
+* @param self The producer to deinitialize
+* @retval Zero if succeed and non-zero error code otherwise.
+*
+* @sa @ref tmedia_producer_deinit
+*/
+int tmedia_producer_deinit(tmedia_producer_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return 0;
+}
+
+/**@ingroup tmedia_producer_group
+* Creates a new producer using an already registered plugin.
+* @param type The type of the producer to create
+* @param session_id
+* @sa @ref tmedia_producer_plugin_register()
+*/
+tmedia_producer_t* tmedia_producer_create(tmedia_type_t type, uint64_t session_id)
+{
+ tmedia_producer_t* producer = tsk_null;
+ const tmedia_producer_plugin_def_t* plugin;
+ tsk_size_t i = 0;
+
+ while((i < TMED_PRODUCER_MAX_PLUGINS) && (plugin = __tmedia_producer_plugins[i++])){
+ if(plugin->objdef && plugin->type == type){
+ if((producer = tsk_object_new(plugin->objdef))){
+ /* initialize the newly created producer */
+ producer->plugin = plugin;
+ producer->session_id = session_id;
+ break;
+ }
+ }
+ }
+
+ return producer;
+}
+
+/**@ingroup tmedia_producer_group
+* Registers a producer plugin.
+* @param plugin the definition of the plugin.
+* @retval Zero if succeed and non-zero error code otherwise.
+* @sa @ref tmedia_producer_create()
+*/
+int tmedia_producer_plugin_register(const tmedia_producer_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ if(!plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* add or replace the plugin */
+ for(i = 0; i<TMED_PRODUCER_MAX_PLUGINS; i++){
+ if(!__tmedia_producer_plugins[i] || (__tmedia_producer_plugins[i] == plugin)){
+ __tmedia_producer_plugins[i] = plugin;
+ return 0;
+ }
+ }
+
+ TSK_DEBUG_ERROR("There are already %d plugins.", TMED_PRODUCER_MAX_PLUGINS);
+ return -2;
+}
+
+/**@ingroup tmedia_producer_group
+* UnRegisters a producer plugin.
+* @param plugin the definition of the plugin.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tmedia_producer_plugin_unregister(const tmedia_producer_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+ if(!plugin){
+ TSK_DEBUG_ERROR("Invalid Parameter");
+ return -1;
+ }
+
+ /* find the plugin to unregister */
+ for(i = 0; i<TMED_PRODUCER_MAX_PLUGINS && __tmedia_producer_plugins[i]; i++){
+ if(__tmedia_producer_plugins[i] == plugin){
+ __tmedia_producer_plugins[i] = tsk_null;
+ found = tsk_true;
+ break;
+ }
+ }
+
+ /* compact */
+ if(found){
+ for(; i<(TMED_PRODUCER_MAX_PLUGINS - 1); i++){
+ if(__tmedia_producer_plugins[i+1]){
+ __tmedia_producer_plugins[i] = __tmedia_producer_plugins[i+1];
+ }
+ else{
+ break;
+ }
+ }
+ __tmedia_producer_plugins[i] = tsk_null;
+ }
+ return (found ? 0 : -2);
+}
+
+/**@ingroup tmedia_producer_group
+* UnRegisters all producers matching the given type.
+* @param type the type of the plugins to unregister.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tmedia_producer_plugin_unregister_by_type(tmedia_type_t type)
+{
+ int i, j;
+
+ /* find the plugin to unregister */
+ for (i = 0; i < TMED_PRODUCER_MAX_PLUGINS && __tmedia_producer_plugins[i]; ) {
+ if ((__tmedia_producer_plugins[i]->type & type) == __tmedia_producer_plugins[i]->type) {
+ __tmedia_producer_plugins[i] = tsk_null;
+ /* compact */
+ for (j = i; j < (TMED_PRODUCER_MAX_PLUGINS - 1) && __tmedia_producer_plugins[j + 1]; ++j) {
+ __tmedia_producer_plugins[j] = __tmedia_producer_plugins[j + 1];
+ }
+ __tmedia_producer_plugins[j] = tsk_null;
+ }
+ else {
+ ++i;
+ }
+ }
+ return 0;
+}
diff --git a/tinyMEDIA/src/tmedia_qos.c b/tinyMEDIA/src/tmedia_qos.c
new file mode 100644
index 0000000..c5c9d3d
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_qos.c
@@ -0,0 +1,862 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_qos.c
+ * @brief RFC 3312 (Preconditions) implementation.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tinymedia/tmedia_qos.h"
+
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+/* ========================= Internal ==================================*/
+
+static const char* tmedia_qos_strength_tostring(tmedia_qos_strength_t strength)
+{
+ switch(strength){
+ case tmedia_qos_strength_none:
+ return "none";
+ case tmedia_qos_strength_mandatory:
+ return "mandatory";
+ case tmedia_qos_strength_optional:
+ return "optional";
+ case tmedia_qos_strength_failure:
+ return "failure";
+ case tmedia_qos_strength_unknown:
+ default:
+ return "unknown";
+ }
+}
+
+static tmedia_qos_strength_t tmedia_qos_strength_fromstring(const char* strength)
+{
+ if(tsk_strequals(strength, "none")){
+ return tmedia_qos_strength_none;
+ }
+ else if(tsk_strequals(strength, "mandatory")){
+ return tmedia_qos_strength_mandatory;
+ }
+ else if(tsk_strequals(strength, "optional")){
+ return tmedia_qos_strength_optional;
+ }
+ else if(tsk_strequals(strength, "failure")){
+ return tmedia_qos_strength_failure;
+ }
+ else{
+ return tmedia_qos_strength_unknown;
+ }
+}
+
+static tmedia_qos_direction_t tmedia_qos_direction_fromstring(const char* direction)
+{
+ if(tsk_strequals(direction, "send")){
+ return tmedia_qos_direction_send;
+ }
+ else if(tsk_strequals(direction, "recv")){
+ return tmedia_qos_direction_recv;
+ }
+ else if(tsk_strequals(direction, "sendrecv")){
+ return tmedia_qos_direction_sendrecv;
+ }
+ else{
+ return tmedia_qos_direction_none;
+ }
+}
+
+/* ========================= Common ==================================*/
+
+tmedia_qos_tline_t* tmedia_qos_tline_create(tmedia_qos_stype_t type, tmedia_qos_strength_t strength)
+{
+ switch(type){
+ case tmedia_qos_stype_e2e:
+ return (tmedia_qos_tline_t*)tmedia_qos_tline_e2e_create(strength);
+ case tmedia_qos_stype_segmented:
+ return (tmedia_qos_tline_t*)tmedia_qos_tline_segmented_create(strength);
+ default: break;
+ }
+ return tsk_null;
+}
+
+tmedia_qos_stype_t tmedia_qos_get_type(const tsdp_header_M_t* m)
+{
+ const tsdp_header_A_t* A;
+ char s0[10];
+
+ if(!m){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tmedia_qos_stype_none;
+ }
+
+ if((A = tsdp_header_M_findA(m, "curr"))){
+ if(sscanf(A->value, "qos %s %*s", s0) != EOF){
+ return tsk_strequals(s0, "e2e") ? tmedia_qos_stype_e2e : tmedia_qos_stype_segmented;
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse a=%s:%s", A->field, A->value);
+ }
+ }
+
+ return tmedia_qos_stype_none;
+}
+
+tmedia_qos_tline_t* tmedia_qos_tline_from_sdp(const tsdp_header_M_t* m)
+{
+ if(!m){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ switch(tmedia_qos_get_type(m)){
+ case tmedia_qos_stype_e2e:
+ return (tmedia_qos_tline_t*)tmedia_qos_tline_e2e_from_sdp(m);
+ case tmedia_qos_stype_segmented:
+ return (tmedia_qos_tline_t*)tmedia_qos_tline_segmented_from_sdp(m);
+ default:
+ return tsk_null;
+ }
+}
+
+int tmedia_qos_tline_to_sdp(const tmedia_qos_tline_t* self, tsdp_header_M_t* m)
+{
+ if(!self || !m){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ switch(self->type){
+ case tmedia_qos_stype_e2e:
+ return tmedia_qos_tline_e2e_to_sdp((tmedia_qos_tline_e2e_t*)self, m);
+ case tmedia_qos_stype_segmented:
+ return tmedia_qos_tline_segmented_to_sdp((tmedia_qos_tline_segmented_t*)self, m);
+ default:
+ TSK_DEBUG_ERROR("Invalid type");
+ return -2;
+ }
+}
+
+int tmedia_qos_tline_set_ro(tmedia_qos_tline_t* self, const tmedia_qos_tline_t* ro)
+{
+ if(!self || !ro){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ switch(self->type){
+ case tmedia_qos_stype_e2e:
+ return tmedia_qos_tline_e2e_set_ro((tmedia_qos_tline_e2e_t*)self, (const tmedia_qos_tline_e2e_t*)ro);
+ case tmedia_qos_stype_segmented:
+ return tmedia_qos_tline_segmented_set_ro((tmedia_qos_tline_segmented_t*)self, (const tmedia_qos_tline_segmented_t*)ro);
+ default:
+ TSK_DEBUG_ERROR("Invalid type");
+ return -2;
+ }
+}
+
+tsk_bool_t tmedia_qos_tline_canresume(const tmedia_qos_tline_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_true;
+ }
+ switch(self->type){
+ case tmedia_qos_stype_segmented:
+ return tmedia_qos_tline_segmented_canresume((const tmedia_qos_tline_segmented_t*)self);
+ case tmedia_qos_stype_e2e:
+ return tmedia_qos_tline_e2e_canresume((const tmedia_qos_tline_e2e_t*)self);
+ default:
+ return tsk_true;
+ }
+}
+
+/* ========================= E2E ==================================*/
+
+tmedia_qos_tline_e2e_t* tmedia_qos_tline_e2e_create(tmedia_qos_strength_t strength)
+{
+ return tsk_object_new(tmedia_qos_tline_e2e_def_t, strength);
+}
+
+tmedia_qos_tline_e2e_t* tmedia_qos_tline_e2e_from_sdp(const tsdp_header_M_t* m)
+{
+ tmedia_qos_tline_e2e_t* e2e = tsk_null;
+ const tsdp_header_A_t* A;
+ tsk_size_t i;
+
+ char s0[10], s1[10];
+
+ if(!m){
+ TSK_DEBUG_ERROR("invalid parameter");
+ return tsk_null;
+ }
+
+ /* Example
+ a=curr:qos e2e none
+ a=des:qos mandatory e2e sendrecv
+ a=conf:qos e2e recv
+ */
+
+ e2e = tmedia_qos_tline_e2e_create(tmedia_qos_strength_unknown);
+
+ /* curr */
+ for(i = 0; (A = tsdp_header_M_findA_at(m, "curr", i)); i++){
+ if(sscanf(A->value, "qos e2e %10s", s0) != EOF){
+ tmedia_qos_direction_t dir = tmedia_qos_direction_fromstring(s0);
+ switch(dir){
+ case tmedia_qos_direction_send:
+ e2e->send.current = tsk_true;
+ break;
+ case tmedia_qos_direction_recv:
+ e2e->recv.current = tsk_true;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ e2e->send.current = tsk_true;
+ e2e->recv.current = tsk_true;
+ break;
+ case tmedia_qos_direction_none:
+ e2e->send.current = tsk_false;
+ e2e->recv.current = tsk_false;
+ break;
+ default:
+ break;
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse a=%s:%s", A->field, A->value);
+ }
+ }
+
+ /* des */
+ for(i = 0; (A = tsdp_header_M_findA_at(m, "des", i)); i++){
+ if(sscanf(A->value, "qos %10s e2e %10s", s0, s1) != EOF){
+ tmedia_qos_strength_t strength = tmedia_qos_strength_fromstring(s0);
+ tmedia_qos_direction_t dir = tmedia_qos_direction_fromstring(s1);
+ switch(dir){
+ case tmedia_qos_direction_send:
+ e2e->send.strength = strength;
+ break;
+ case tmedia_qos_direction_recv:
+ e2e->recv.strength = strength;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ e2e->send.strength = strength;
+ e2e->recv.strength = strength;
+ break;
+ default:
+ break;
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse a=%s:%s", A->field, A->value);
+ }
+ }
+
+ /* conf */
+ for(i = 0; (A = tsdp_header_M_findA_at(m, "conf", i)); i++){
+ if(sscanf(A->value, "qos e2e %10s", s0) != EOF){
+ tmedia_qos_direction_t dir = tmedia_qos_direction_fromstring(s0);
+ switch(dir){
+ case tmedia_qos_direction_send:
+ e2e->send.confirm = tsk_true;
+ break;
+ case tmedia_qos_direction_recv:
+ e2e->recv.confirm = tsk_true;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ e2e->send.confirm = tsk_true;
+ e2e->recv.confirm = tsk_true;
+ break;
+ default:
+ break;
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse a=%s:%s", A->field, A->value);
+ }
+ }
+
+ return e2e;
+}
+
+int tmedia_qos_tline_e2e_to_sdp(const tmedia_qos_tline_e2e_t* self, tsdp_header_M_t* m)
+{
+ /* RFC 3312 - 5.1.1 SDP encoding
+
+ For the end-to-end status type, the user agent MUST generate one
+ current status line with the tag "e2e" for the media stream. If the
+ strength-tags for both directions are equal (e.g., both "mandatory")
+ in the transaction status table, the user agent MUST add one desired
+ status line with the tag "sendrecv". If both tags are different, the
+ user agent MUST include two desired status lines, one with the tag
+ "send" and the other with the tag "recv".
+ */
+ char* temp = tsk_null;
+
+ if(!self || !m){
+ TSK_DEBUG_ERROR("invalid parameter");
+ return -1;
+ }
+ /* Example
+ a=curr:qos e2e none
+ a=des:qos mandatory e2e sendrecv
+ */
+
+
+ /* curr */
+ tsk_sprintf(&temp, "qos e2e %s", (self->recv.current && self->send.current) ? "sendrecv" : (self->recv.current ? "recv" : (self->send.current ? "send" : "none")));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("curr", temp),
+ tsk_null);
+ TSK_FREE(temp);
+
+ /* des */
+ if(self->recv.strength == self->send.strength){
+ /* sendrecv */
+ tsk_sprintf(&temp, "qos %s e2e sendrecv", tmedia_qos_strength_tostring(self->recv.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+ else{
+ /* send */
+ tsk_sprintf(&temp, "qos %s e2e send", tmedia_qos_strength_tostring(self->send.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+
+ /* recv */
+ tsk_sprintf(&temp, "qos %s e2e recv", tmedia_qos_strength_tostring(self->recv.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+
+ /* conf (should not request confirm on "send" direction)*/
+ if(self->recv.confirm){
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("conf", "qos e2e recv"),
+ tsk_null);
+ }
+ return 0;
+}
+
+int tmedia_qos_tline_e2e_set_ro(tmedia_qos_tline_e2e_t* self, const tmedia_qos_tline_e2e_t* ro)
+{
+ if(!self || !ro){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* We were the offerer
+ * Remote asked for confirmation in its "recv" direction?
+ * "recv" direction for remote is our "send" direction
+ * As we don't support RSVP (under the way), confirm immediatly.
+ * "send" direction should not requested for confirmation
+ */
+ if(ro->recv.confirm){
+ self->send.current = tsk_true;
+ goto bail;
+ }
+ if(ro->send.current){
+ self->recv.confirm = tsk_false; /* remote confirmed */
+ self->recv.current = tsk_true; /* because ro confirmed */
+ self->send.current = tsk_true; /* beacuse we don't support RSVP */
+ goto bail;
+ }
+
+ /* We are the answerer
+ * As we don't support RSVP (under the way):
+ * ==> request confirmation for "recv" direction if equal to "none" (not reserved)
+ * =>
+ */
+ if(!self->recv.current){
+ self->recv.confirm = tsk_true;
+ goto bail;
+ }
+
+bail:
+ /* all other cases: success */
+ return 0;
+}
+
+tsk_bool_t tmedia_qos_tline_e2e_canresume(const tmedia_qos_tline_e2e_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_true;
+ }
+
+ /* Example
+ a=curr:qos e2e none
+ a=des:qos mandatory e2e sendrecv
+
+ Or
+
+ a=curr:qos e2e send
+ a=des:qos mandatory e2e recv
+ a=des:qos optional e2e send
+ */
+
+ /* only "mandatory" strength should force the application to continue nego. */
+ if(self->recv.strength == tmedia_qos_strength_mandatory && !self->recv.current){
+ return tsk_false;
+ }
+ /*else */if(self->send.strength == tmedia_qos_strength_mandatory && !self->send.current){
+ return tsk_false;
+ }
+
+ /* "optinal" and "none" strengths */
+ return tsk_true;
+}
+
+//
+// E2E QoS line object definition
+//
+static tsk_object_t* tmedia_qos_tline_e2e_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_qos_tline_e2e_t *e2e = self;
+ if(e2e){
+ e2e->recv.strength = e2e->send.strength = va_arg(*app, tmedia_qos_strength_t);
+ TMEDIA_QOS_TLINE(e2e)->type = tmedia_qos_stype_e2e;
+ }
+ return self;
+}
+
+static tsk_object_t* tmedia_qos_tline_e2e_dtor(tsk_object_t * self)
+{
+ tmedia_qos_tline_e2e_t *e2e = self;
+ if(e2e){
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tmedia_qos_tline_e2e_def_s =
+{
+ sizeof(tmedia_qos_tline_e2e_t),
+ tmedia_qos_tline_e2e_ctor,
+ tmedia_qos_tline_e2e_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tmedia_qos_tline_e2e_def_t = &tmedia_qos_tline_e2e_def_s;
+
+
+
+
+
+
+
+
+
+
+/* ========================= Segmented ==================================*/
+
+tmedia_qos_tline_segmented_t* tmedia_qos_tline_segmented_create(tmedia_qos_strength_t strength)
+{
+ return tsk_object_new(tmedia_qos_tline_segmented_def_t, strength);
+}
+
+tmedia_qos_tline_segmented_t* tmedia_qos_tline_segmented_from_sdp(const tsdp_header_M_t* m)
+{
+ tmedia_qos_tline_segmented_t* segmented = tsk_null;
+ const tsdp_header_A_t* A;
+ tsk_size_t i;
+
+ char s0[10], s1[10], s2[10];
+
+ if(!m){
+ TSK_DEBUG_ERROR("invalid parameter");
+ return tsk_null;
+ }
+
+ /* Example
+ a=curr:qos local none
+ a=curr:qos remote none
+ a=des:qos optional remote send
+ a=des:qos none remote recv
+ a=des:qos none local sendrecv
+ a=conf:qos local recv
+ */
+ segmented = tmedia_qos_tline_segmented_create(tmedia_qos_strength_unknown);
+
+ /* curr */
+ for(i = 0; (A = tsdp_header_M_findA_at(m, "curr", i)); i++){
+ if(sscanf(A->value, "qos %10s %10s", s0, s1) != EOF){
+ /* For segmented, s0 should be equal to "local" or "remote" */
+ tmedia_qos_direction_t dir = tmedia_qos_direction_fromstring(s1);
+ if(tsk_strequals(s0, "local")){
+ /* local */
+ switch(dir){
+ case tmedia_qos_direction_send:
+ segmented->local_send.current = tsk_true;
+ break;
+ case tmedia_qos_direction_recv:
+ segmented->local_recv.current = tsk_true;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ segmented->local_send.current = tsk_true;
+ segmented->local_recv.current = tsk_true;
+ break;
+ case tmedia_qos_direction_none:
+ segmented->local_send.current = tsk_false;
+ segmented->local_recv.current = tsk_false;
+ break;
+ default:
+ break;
+ }
+ }
+ else{
+ /* remote */
+ switch(dir){
+ case tmedia_qos_direction_send:
+ segmented->remote_send.current = tsk_true;
+ break;
+ case tmedia_qos_direction_recv:
+ segmented->remote_recv.current = tsk_true;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ segmented->remote_send.current = tsk_true;
+ segmented->remote_recv.current = tsk_true;
+ break;
+ case tmedia_qos_direction_none:
+ segmented->remote_send.current = tsk_false;
+ segmented->remote_recv.current = tsk_false;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse a=%s:%s", A->field, A->value);
+ }
+ }
+
+ /* des */
+ for(i = 0; (A = tsdp_header_M_findA_at(m, "des", i)); i++){
+ if(sscanf(A->value, "qos %10s %10s %10s", s0, s1, s2) != EOF){
+ /* For segmented, s1 should be equal to "local" or "remote" */
+ tmedia_qos_strength_t strength = tmedia_qos_strength_fromstring(s0);
+ tmedia_qos_direction_t dir = tmedia_qos_direction_fromstring(s2);
+ if(tsk_strequals(s1, "local")){
+ /* local */
+ switch(dir){
+ case tmedia_qos_direction_send:
+ segmented->local_send.strength = strength;
+ break;
+ case tmedia_qos_direction_recv:
+ segmented->local_recv.strength = strength;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ segmented->local_send.strength = strength;
+ segmented->local_recv.strength = strength;
+ break;
+ default:
+ break;
+ }
+ }
+ else{
+ /* remote */
+ switch(dir){
+ case tmedia_qos_direction_send:
+ segmented->remote_send.strength = strength;
+ break;
+ case tmedia_qos_direction_recv:
+ segmented->remote_recv.strength = strength;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ segmented->remote_send.strength = strength;
+ segmented->remote_recv.strength = strength;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse a=%s:%s", A->field, A->value);
+ }
+ }
+
+ /* conf */
+ for(i = 0; (A = tsdp_header_M_findA_at(m, "conf", i)); i++){
+ if(sscanf(A->value, "qos %10s %10s", s0, s1) != EOF){
+ /* For segmented, s0 should be equal to "local" or "remote" */
+ tmedia_qos_direction_t dir = tmedia_qos_direction_fromstring(s1);
+ if(tsk_strequals(s0, "local")){
+ /* local */
+ switch(dir){
+ case tmedia_qos_direction_send:
+ segmented->local_send.confirm = tsk_true;
+ break;
+ case tmedia_qos_direction_recv:
+ segmented->local_recv.confirm = tsk_true;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ segmented->local_send.confirm = tsk_true;
+ segmented->local_recv.confirm = tsk_true;
+ break;
+ default:
+ break;
+ }
+ }
+ else{
+ /* remote */
+ switch(dir){
+ case tmedia_qos_direction_send:
+ segmented->remote_send.confirm = tsk_true;
+ break;
+ case tmedia_qos_direction_recv:
+ segmented->remote_recv.confirm = tsk_true;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ segmented->remote_send.confirm = tsk_true;
+ segmented->remote_recv.confirm = tsk_true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse a=%s:%s", A->field, A->value);
+ }
+ }
+
+ return segmented;
+}
+
+int tmedia_qos_tline_segmented_to_sdp(const tmedia_qos_tline_segmented_t* self, tsdp_header_M_t* m)
+{
+ /* RFC 3312 - 5.1.1 SDP encoding
+
+ For the segmented status type, the user agent MUST generate two
+ current status lines: one with the tag "local" and the other with the
+ tag "remote". The user agent MUST add one or two desired status
+ lines per segment (i.e., local and remote). If, for a particular
+ segment (local or remote), the tags for both directions in the
+ transaction status table are equal (e.g., both "mandatory"), the user
+ agent MUST add one desired status line with the tag "sendrecv". If
+ both tags are different, the user agent MUST include two desired
+ status lines, one with the tag "send" and the other with the tag "recv".
+ */
+ char* temp = tsk_null;
+
+ if(!self || !m){
+ TSK_DEBUG_ERROR("invalid parameter");
+ return -1;
+ }
+
+ /* Example
+ a=curr:qos local none
+ a=curr:qos remote none
+ a=des:qos optional remote send
+ a=des:qos none remote recv
+ a=des:qos none local sendrecv
+ */
+
+ /* curr:local */
+ tsk_sprintf(&temp, "qos local %s", (self->local_recv.current && self->local_send.current) ? "sendrecv" : (self->local_recv.current ? "recv" : (self->local_send.current ? "send" : "none")));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("curr", temp),
+ tsk_null);
+ TSK_FREE(temp);
+
+ /* curr:remote */
+ tsk_sprintf(&temp, "qos remote %s", (self->remote_recv.current && self->remote_send.current) ? "sendrecv" : (self->remote_recv.current ? "recv" : (self->remote_send.current ? "send" : "none")));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("curr", temp),
+ tsk_null);
+ TSK_FREE(temp);
+
+
+ /* des:local */
+ if(self->local_recv.strength == self->local_send.strength){
+ /* sendrecv */
+ tsk_sprintf(&temp, "qos %s local sendrecv", tmedia_qos_strength_tostring(self->local_send.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+ else{
+ /* send */
+ tsk_sprintf(&temp, "qos %s local send", tmedia_qos_strength_tostring(self->local_send.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+
+ /* recv */
+ tsk_sprintf(&temp, "qos %s local recv", tmedia_qos_strength_tostring(self->local_recv.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+
+
+ /* des:remote */
+ if(self->remote_recv.strength == self->remote_send.strength){
+ /* sendrecv */
+ tsk_sprintf(&temp, "qos %s remote sendrecv", tmedia_qos_strength_tostring(self->remote_send.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+ else{
+ /* send */
+ tsk_sprintf(&temp, "qos %s remote send", tmedia_qos_strength_tostring(self->remote_send.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+
+ /* recv */
+ tsk_sprintf(&temp, "qos %s remote recv", tmedia_qos_strength_tostring(self->remote_recv.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+
+ /* conf */
+ if(self->remote_recv.confirm || self->remote_send.confirm){
+ tsk_sprintf(&temp, "qos remote %s", (self->remote_recv.confirm && self->remote_send.confirm) ? "sendrecv" : (self->remote_recv.confirm ? "recv" : (self->remote_send.confirm ? "send" : "none")));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("conf", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+
+ return 0;
+}
+
+int tmedia_qos_tline_segmented_set_ro(tmedia_qos_tline_segmented_t* self, const tmedia_qos_tline_segmented_t* ro)
+{
+ if(!self || !ro){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ //////////////
+ if(!ro->local_recv.current && !ro->remote_recv.confirm){
+ /* request confirmation */
+ self->remote_recv.confirm = tsk_true;
+ }
+ else{
+ self->remote_recv.confirm = tsk_false;
+ self->local_recv.current = tsk_true;
+ }
+ if(!ro->local_send.current && !ro->remote_send.confirm){
+ /* request confirmation */
+ self->remote_send.confirm = tsk_true;
+ }
+ else{
+ self->remote_send.confirm = tsk_false;
+ self->local_send.current = tsk_true;
+ }
+
+ //////////////
+ if(ro->remote_recv.confirm){
+ self->local_recv.current = tsk_true;
+ }
+ if(ro->remote_send.confirm){
+ self->local_send.current = tsk_true;
+ }
+
+ //////////////
+ if(ro->local_recv.current){
+ self->remote_recv.current = tsk_true;
+ }
+ if(ro->local_send.current){
+ self->remote_send.current = tsk_true;
+ }
+
+ return 0;
+}
+
+tsk_bool_t tmedia_qos_tline_segmented_canresume(const tmedia_qos_tline_segmented_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_true;
+ }
+
+ /* == Strength is mandatory == */
+ if(self->local_recv.strength == tmedia_qos_strength_mandatory && !self->local_recv.current){
+ return tsk_false;
+ }
+
+ if(self->local_send.strength == tmedia_qos_strength_mandatory && !self->local_send.current){
+ return tsk_false;
+ }
+
+ if(self->remote_recv.strength == tmedia_qos_strength_mandatory && !self->remote_recv.current){
+ return tsk_false;
+ }
+
+ if(self->remote_send.strength == tmedia_qos_strength_mandatory && !self->remote_send.current){
+ return tsk_false;
+ }
+
+ /* "optinal" and "none" strengths */
+ return tsk_true;
+}
+
+//
+// Segmented QoS line object definition
+//
+static tsk_object_t* tmedia_qos_tline_segmented_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_qos_tline_segmented_t *segmented = self;
+ if(segmented){
+ segmented->local_recv.strength = segmented->local_send.strength
+ = segmented->remote_recv.strength = segmented->remote_send.strength = va_arg(*app, tmedia_qos_strength_t);
+ TMEDIA_QOS_TLINE(segmented)->type = tmedia_qos_stype_segmented;
+ }
+ return self;
+}
+
+static tsk_object_t* tmedia_qos_tline_segmented_dtor(tsk_object_t * self)
+{
+ tmedia_qos_tline_segmented_t *segmented = self;
+ if(segmented){
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tmedia_qos_tline_segmented_def_s =
+{
+ sizeof(tmedia_qos_tline_segmented_t),
+ tmedia_qos_tline_segmented_ctor,
+ tmedia_qos_tline_segmented_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tmedia_qos_tline_segmented_def_t = &tmedia_qos_tline_segmented_def_s; \ No newline at end of file
diff --git a/tinyMEDIA/src/tmedia_resampler.c b/tinyMEDIA/src/tmedia_resampler.c
new file mode 100644
index 0000000..0d547cf
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_resampler.c
@@ -0,0 +1,152 @@
+/*
+* Copyright (C) 2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_resampler.c
+ * @brief Audio Resample plugin
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ */
+#include "tinymedia/tmedia_resampler.h"
+
+#include "tsk_debug.h"
+
+static const tmedia_resampler_plugin_def_t* __tmedia_resampler_plugin = tsk_null;
+
+int tmedia_resampler_init(tmedia_resampler_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return 0;
+}
+
+int tmedia_resampler_open(tmedia_resampler_t* self, uint32_t in_freq, uint32_t out_freq, uint32_t frame_duration, uint32_t in_channels, uint32_t out_channels, uint32_t quality, uint32_t bits_per_sample)
+{
+ int ret;
+
+ if (!self || !self->plugin || !self->plugin->open) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (self->opened) {
+ TSK_DEBUG_WARN("Resampler already opened");
+ return 0;
+ }
+
+ if ((ret = self->plugin->open(self, in_freq, out_freq, frame_duration, in_channels, out_channels, quality, bits_per_sample))) {
+ TSK_DEBUG_ERROR("Failed to open [%s] resamplerr", self->plugin->desc);
+ return ret;
+ }
+ else{
+ self->opened = tsk_true;
+ return 0;
+ }
+}
+
+tsk_size_t tmedia_resampler_process(tmedia_resampler_t* self, const void* in_data, tsk_size_t in_size_in_sample, void* out_data, tsk_size_t out_size_in_sample)
+{
+ if (!self || !in_data || !in_size_in_sample || !out_size_in_sample || !self->plugin || !self->plugin->process) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return 0;
+ }
+ if (!self->opened) {
+ TSK_DEBUG_ERROR("Resampler not opened");
+ return 0;
+ }
+ return self->plugin->process(self, in_data, in_size_in_sample, out_data, out_size_in_sample);
+}
+
+int tmedia_resampler_close(tmedia_resampler_t* self)
+{
+ if (!self || !self->plugin) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!self->opened) {
+ TSK_DEBUG_WARN("Resampler not opened");
+ return 0;
+ }
+
+ if (self->plugin->close) {
+ int ret;
+
+ if ((ret = self->plugin->close(self))) {
+ TSK_DEBUG_ERROR("Failed to close [%s] resamplerr", self->plugin->desc);
+ return ret;
+ }
+ else {
+ self->opened = tsk_false;
+ return 0;
+ }
+ }
+ else {
+ self->opened = tsk_false;
+ return 0;
+ }
+}
+
+int tmedia_resampler_deinit(tmedia_resampler_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(self->opened){
+ tmedia_resampler_close(self);
+ }
+
+ return 0;
+}
+
+int tmedia_resampler_plugin_register(const tmedia_resampler_plugin_def_t* plugin)
+{
+ if(!plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if(!__tmedia_resampler_plugin) {
+ TSK_DEBUG_INFO("Register resampler: %s", plugin->desc);
+ __tmedia_resampler_plugin = plugin;
+ }
+ return 0;
+}
+
+int tmedia_resampler_plugin_unregister(const tmedia_resampler_plugin_def_t* plugin)
+{
+ (void)(plugin);
+ __tmedia_resampler_plugin = tsk_null;
+ return 0;
+}
+
+tmedia_resampler_t* tmedia_resampler_create()
+{
+ tmedia_resampler_t* resampler = tsk_null;
+
+ if(__tmedia_resampler_plugin){
+ if((resampler = (tmedia_resampler_t*)tsk_object_new(__tmedia_resampler_plugin->objdef))){
+ resampler->plugin = __tmedia_resampler_plugin;
+ }
+ }
+ return resampler;
+}
diff --git a/tinyMEDIA/src/tmedia_session.c b/tinyMEDIA/src/tmedia_session.c
new file mode 100644
index 0000000..08348d3
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_session.c
@@ -0,0 +1,2524 @@
+/*
+* Copyright (C) 2010-2015 Mamadou DIOP.
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tmedia_session.h
+ * @brief Base session object.
+ *
+ */
+#include "tinymedia/tmedia_session.h"
+
+#include "tinymedia/tmedia_session_ghost.h"
+#include "tinymedia/tmedia_defaults.h"
+
+#include "tinysdp/headers/tsdp_header_O.h"
+
+#include "ice/tnet_ice_ctx.h"
+
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+/**@defgroup tmedia_session_group Media Session
+* For more information about the SOA, please refer to http://betelco.blogspot.com/2010/03/sdp-offeranswer-soa_2993.html
+*/
+
+#if !defined(va_copy)
+# define va_copy(D, S) ((D) = (S))
+#endif
+
+#define kSkipSessionLoadTrue tsk_true
+#define kSkipSessionLoadFalse tsk_false
+#define kForceUpdateLOTrue tsk_true
+#define kForceUpdateLOFalse tsk_false
+
+#define kSessionIndexAll -1
+
+extern const tmedia_codec_plugin_def_t* __tmedia_codec_plugins[TMED_CODEC_MAX_PLUGINS];
+
+/* pointer to all registered sessions */
+const tmedia_session_plugin_def_t* __tmedia_session_plugins[TMED_SESSION_MAX_PLUGINS] = { 0 };
+
+#if !defined(TMEDIA_SESSION_MAX_LINES)
+# define TMEDIA_SESSION_MAX_LINES 64 // too high to but who knows
+#endif /* TMEDIA_SESSION_MAX_LINES */
+
+/* === local functions === */
+static int _tmedia_session_mgr_recv_rtcp_event(tmedia_session_mgr_t* self, tmedia_type_t media_type, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media, uint64_t session_id);
+static int _tmedia_session_mgr_load_sessions(tmedia_session_mgr_t* self);
+static int _tmedia_session_mgr_disable_or_enable_session_with_type(tmedia_session_mgr_t* self, tmedia_type_t media_type, tsk_bool_t enable);
+#define _tmedia_session_mgr_disable_session_with_type(self, media_type) _tmedia_session_mgr_disable_or_enable_session_with_type((self), (media_type), tsk_false)
+#define _tmedia_session_mgr_enable_session_with_type(self, media_type) _tmedia_session_mgr_disable_or_enable_session_with_type((self), (media_type), tsk_true)
+static const tmedia_session_t* _tmedia_session_mgr_find_session_at_index(const tmedia_sessions_L_t* list, tsk_size_t index);
+static int _tmedia_session_mgr_clear_sessions(tmedia_session_mgr_t* self);
+static int _tmedia_session_mgr_apply_params(tmedia_session_mgr_t* self);
+static const tsdp_message_t* _tmedia_session_mgr_get_lo(tmedia_session_mgr_t* self, tsk_bool_t skip_session_load, tsk_bool_t force_update_lo);
+static int _tmedia_session_mgr_start(tmedia_session_mgr_t* self, int session_index);
+static int _tmedia_session_mgr_stop(tmedia_session_mgr_t* self, int session_index);
+
+static int _tmedia_session_prepare(tmedia_session_t* self);
+static int _tmedia_session_set_ro(tmedia_session_t* self, const tsdp_header_M_t* m);
+static int _tmedia_session_load_codecs(tmedia_session_t* self);
+const char* tmedia_session_get_media(const tmedia_session_t* self);
+const tsdp_header_M_t* tmedia_session_get_lo(tmedia_session_t* self);
+int tmedia_session_set_ro(tmedia_session_t* self, const tsdp_header_M_t* m);
+
+
+/*== Predicate function to find session object by media */
+static int __pred_find_session_by_media(const tsk_list_item_t *item, const void *media)
+{
+ if (item && item->data){
+ return tsk_stricmp(tmedia_session_get_media((const tmedia_session_t *)item->data), (const char*)media);
+ }
+ return -1;
+}
+
+/*== Predicate function to find session object by type */
+static int __pred_find_session_by_type(const tsk_list_item_t *item, const void *type)
+{
+ if (item && item->data){
+ return ((const tmedia_session_t *)item->data)->type - *((tmedia_type_t*)type);
+ }
+ return -1;
+}
+
+/*== Predicate function to find codec object by format */
+static int __pred_find_codec_by_format(const tsk_list_item_t *item, const void *codec)
+{
+ if (item && item->data && codec){
+ return tsk_stricmp(((const tmedia_codec_t*)item->data)->format, ((const tmedia_codec_t*)codec)->format);
+ }
+ return -1;
+}
+
+/*== Predicate function to find codec object by id */
+static int __pred_find_codec_by_id(const tsk_list_item_t *item, const void *id)
+{
+ if (item && item->data && id){
+ if (((const tmedia_codec_t*)item->data)->id == *((const tmedia_codec_id_t*)id)){
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static tsk_size_t __flags_sum(const tsk_bool_t *flags, tsk_size_t count) {
+ tsk_size_t sum = 0, i;
+ for (i = 0; i < count; ++i) {
+ if (flags[i] == tsk_true) ++sum;
+ }
+ return sum;
+}
+
+uint64_t tmedia_session_get_unique_id(){
+ static uint64_t __UniqueId = 1; // MUST not be equal to zero
+ return __UniqueId++;
+}
+
+/**@ingroup tmedia_session_group
+* Initializes a newly created media session.
+* @param self the media session to initialize.
+* @param type the type of the session to initialize.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tmedia_session_init(tmedia_session_t* self, tmedia_type_t type)
+{
+ int ret = 0;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (!self->initialized){
+ /* set values */
+ if (!self->id){
+ self->id = tmedia_session_get_unique_id();
+ }
+ self->type = type;
+ self->initialized = tsk_true;
+ self->bl = tmedia_defaults_get_bl();
+ self->codecs_allowed = tmedia_codec_id_all;
+ self->bypass_encoding = tmedia_defaults_get_bypass_encoding();
+ self->bypass_decoding = tmedia_defaults_get_bypass_decoding();
+ /* SSL certificates */{
+ const char* priv_path = tsk_null, *pub_path = tsk_null, *ca_path = tsk_null;
+ tsk_bool_t verify = tsk_false;
+ if ((ret = tmedia_defaults_get_ssl_certs(&priv_path, &pub_path, &ca_path, &verify))) {
+ return ret;
+ }
+ self->dtls.file_pvk = tsk_strdup(priv_path);
+ self->dtls.file_pbk = tsk_strdup(pub_path);
+ self->dtls.file_ca = tsk_strdup(ca_path);
+ self->dtls.verify = verify;
+ }
+ /* load associated codecs */
+ ret = _tmedia_session_load_codecs(self);
+ }
+
+ return 0;
+}
+
+int tmedia_session_set(tmedia_session_t* self, ...)
+{
+ va_list ap;
+ tmedia_params_L_t* params;
+
+ if (!self || !self->plugin || !self->plugin->set){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ va_start(ap, self);
+ if ((params = tmedia_params_create_2(&ap))){
+ const tsk_list_item_t *item;
+ const tmedia_param_t* param;
+ tsk_list_foreach(item, params){
+ if (!(param = item->data)){
+ continue;
+ }
+ if ((self->type & param->media_type)){
+ self->plugin->set(self, param);
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(params);
+ }
+ va_end(ap);
+ return 0;
+}
+
+tsk_bool_t tmedia_session_set_2(tmedia_session_t* self, const tmedia_param_t* param)
+{
+ if (!self || !param){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_false;
+ }
+
+ if (param->plugin_type == tmedia_ppt_session){
+ if (param->value_type == tmedia_pvt_int32){
+ if (tsk_striequals(param->key, "codecs-supported")){
+ //if(self->M.lo){
+ // TSK_DEBUG_WARN("Cannot change codec values at this stage");
+ //}
+ //else{
+ int32_t codecs_allowed = *((int32_t*)param->value);
+ if (self->codecs_allowed != codecs_allowed){
+ self->codecs_allowed = codecs_allowed;
+ return (_tmedia_session_load_codecs(self) == 0);
+ }
+ return 0;
+ //}
+ return tsk_true;
+ }
+ else if (tsk_striequals(param->key, "bypass-encoding")){
+ self->bypass_encoding = *((int32_t*)param->value);
+ return tsk_true;
+ }
+ else if (tsk_striequals(param->key, "bypass-decoding")){
+ self->bypass_decoding = *((int32_t*)param->value);
+ return tsk_true;
+ }
+ else if (tsk_striequals(param->key, "dtls-cert-verify")){
+ self->dtls.verify = *((int32_t*)param->value) ? tsk_true : tsk_false;
+ return tsk_true;
+ }
+ }
+ else if (param->value_type == tmedia_pvt_pchar){
+ if (tsk_striequals(param->key, "dtls-file-ca")){
+ tsk_strupdate(&self->dtls.file_ca, param->value);
+ return tsk_true;
+ }
+ else if (tsk_striequals(param->key, "dtls-file-pbk")){
+ tsk_strupdate(&self->dtls.file_pbk, param->value);
+ return tsk_true;
+ }
+ else if (tsk_striequals(param->key, "dtls-file-pvk")){
+ tsk_strupdate(&self->dtls.file_pvk, param->value);
+ return tsk_true;
+ }
+ }
+ }
+
+ return tsk_false;
+}
+
+int tmedia_session_get(tmedia_session_t* self, tmedia_param_t* param)
+{
+ if (!self || !param) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (self->plugin && self->plugin->get) {
+ return self->plugin->get(self, param);
+ }
+ return -2;
+}
+
+/**@ingroup tmedia_session_group
+* Generic function to compare two sessions.
+* @param sess1 The first session to compare.
+* @param sess2 The second session to compare.
+* @retval Returns an integral value indicating the relationship between the two sessions:
+* <0 : @a sess1 less than @a sess2.<br>
+* 0 : @a sess1 identical to @a sess2.<br>
+* >0 : @a sess1 greater than @a sess2.<br>
+*/
+int tmedia_session_cmp(const tsk_object_t* sess1, const tsk_object_t* sess2)
+{
+ int ret;
+ tsk_subsat_int32_ptr(sess1, sess2, &ret);
+ return ret;
+}
+
+/**@ingroup tmedia_session_group
+* Registers a session plugin.
+* @param plugin the definition of the plugin.
+* @retval Zero if succeed and non-zero error code otherwise.
+* @sa @ref tmedia_session_create()
+*/
+int tmedia_session_plugin_register(const tmedia_session_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ if (!plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* add or replace the plugin */
+ for (i = 0; i < TMED_SESSION_MAX_PLUGINS; i++){
+ if (!__tmedia_session_plugins[i] || (__tmedia_session_plugins[i] == plugin)){
+ __tmedia_session_plugins[i] = plugin;
+ return 0;
+ }
+ }
+
+ TSK_DEBUG_ERROR("There are already %d plugins.", TMED_SESSION_MAX_PLUGINS);
+ return -2;
+}
+
+/**@ingroup tmedia_session_group
+* Finds a plugin by media.
+*/
+const tmedia_session_plugin_def_t* tmedia_session_plugin_find_by_media(const char* media)
+{
+ tsk_size_t i = 0;
+ if (tsk_strnullORempty(media)){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ /* add or replace the plugin */
+ while ((i < TMED_SESSION_MAX_PLUGINS) && (__tmedia_session_plugins[i])){
+ if (tsk_striequals(__tmedia_session_plugins[i]->media, media)){
+ return __tmedia_session_plugins[i];
+ }
+ i++;
+ }
+ return tsk_null;
+}
+
+/**@ingroup tmedia_session_group
+* UnRegisters a session plugin.
+* @param plugin the definition of the plugin.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tmedia_session_plugin_unregister(const tmedia_session_plugin_def_t* plugin)
+{
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+ if (!plugin){
+ TSK_DEBUG_ERROR("Invalid Parameter");
+ return -1;
+ }
+
+ /* find the plugin to unregister */
+ for (i = 0; i < TMED_SESSION_MAX_PLUGINS && __tmedia_session_plugins[i]; i++){
+ if (__tmedia_session_plugins[i] == plugin){
+ __tmedia_session_plugins[i] = tsk_null;
+ found = tsk_true;
+ break;
+ }
+ }
+
+ /* compact */
+ if (found){
+ for (; i < (TMED_SESSION_MAX_PLUGINS - 1); i++){
+ if (__tmedia_session_plugins[i + 1]){
+ __tmedia_session_plugins[i] = __tmedia_session_plugins[i + 1];
+ }
+ else{
+ break;
+ }
+ }
+ __tmedia_session_plugins[i] = tsk_null;
+ }
+ return (found ? 0 : -2);
+}
+
+/**@ingroup tmedia_session_group
+* Creates a new session using an already registered plugin.
+* @param format The type of the codec to create.
+* @sa @ref tmedia_codec_plugin_register()
+*/
+tmedia_session_t* tmedia_session_create(tmedia_type_t type)
+{
+ tmedia_session_t* session = tsk_null;
+ const tmedia_session_plugin_def_t* plugin;
+ tsk_size_t i = 0;
+
+ while ((i < TMED_SESSION_MAX_PLUGINS) && (plugin = __tmedia_session_plugins[i++])){
+ if (plugin->objdef && (plugin->type == type)){
+ if ((session = tsk_object_new(plugin->objdef))){
+ if (!session->initialized){
+ tmedia_session_init(session, type);
+ }
+ session->plugin = plugin;
+ }
+ break;
+ }
+ }
+ return session;
+}
+
+/* internal funtion: prepare lo */
+static int _tmedia_session_prepare(tmedia_session_t* self)
+{
+ int ret;
+ if (!self || !self->plugin || !self->plugin->prepare){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (self->prepared){
+ TSK_DEBUG_WARN("Session already prepared");
+ return 0;
+ }
+ if ((ret = self->plugin->prepare(self))){
+ TSK_DEBUG_ERROR("Failed to prepare the session");
+ }
+ else{
+ self->prepared = tsk_true;
+ }
+ return ret;
+}
+
+/* internal function used to set remote offer */
+int _tmedia_session_set_ro(tmedia_session_t* self, const tsdp_header_M_t* m)
+{
+ int ret;
+ if (!self || !self->plugin || !self->plugin->set_remote_offer){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!(ret = self->plugin->set_remote_offer(self, m))){
+ self->ro_changed = tsk_true;
+ self->ro_held = tsdp_header_M_is_held(m, tsk_false);
+ }
+ return ret;
+}
+
+/* internal function: get media */
+const char* tmedia_session_get_media(const tmedia_session_t* self)
+{
+ if (!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ /* ghost? */
+ if (self->plugin == tmedia_session_ghost_plugin_def_t){
+ return ((const tmedia_session_ghost_t*)self)->media;
+ }
+ else{
+ return self->plugin->media;
+ }
+}
+/* internal function: get local offer */
+const tsdp_header_M_t* tmedia_session_get_lo(tmedia_session_t* self)
+{
+ const tsdp_header_M_t* m;
+
+ if (!self || !self->plugin || !self->plugin->get_local_offer){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ if ((m = self->plugin->get_local_offer(self))){
+ self->ro_changed = tsk_false; /* we should have a fresh local offer (based on the latest ro) */
+ }
+ return m;
+}
+
+/* Match a codec */
+tmedia_codecs_L_t* tmedia_session_match_codec(tmedia_session_t* self, const tsdp_header_M_t* M)
+{
+ const tmedia_codec_t *codec;
+ char *rtpmap = tsk_null, *fmtp = tsk_null, *image_attr = tsk_null, *name = tsk_null;
+ const tsdp_fmt_t* fmt;
+ const tsk_list_item_t *it1, *it2;
+ tsk_bool_t found = tsk_false;
+ tmedia_codecs_L_t* matchingCodecs = tsk_null;
+
+ if (!self || !M){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+
+ /* foreach format */
+ tsk_list_foreach(it1, M->FMTs){
+ fmt = it1->data;
+
+ /* foreach codec */
+ tsk_list_foreach(it2, self->codecs){
+ /* 'tmedia_codec_id_none' is used for fake codecs (e.g. dtmf or msrp) and should not be filtered beacuse of backward compatibility*/
+ if (!(codec = it2->data) || !codec->plugin || !(codec->id == tmedia_codec_id_none || (codec->id & self->codecs_allowed))){
+ continue;
+ }
+
+ // Guard to avoid matching a codec more than once
+ // For example, H.264 codecs without profiles (Jitsi, Tiscali PC client) to distinguish them could match more than once
+ if (matchingCodecs && tsk_list_find_object_by_pred(matchingCodecs, __pred_find_codec_by_format, codec)){
+ continue;
+ }
+
+ // Dyn. payload type
+ if (codec->dyn && (rtpmap = tsdp_header_M_get_rtpmap(M, fmt->value))){
+ int32_t rate, channels;
+ /* parse rtpmap */
+ if (tmedia_parse_rtpmap(rtpmap, &name, &rate, &channels)){
+ goto next;
+ }
+
+ /* compare name and rate... what about channels? */
+ if (tsk_striequals(name, codec->name) && (!rate || !codec->plugin->rate || (codec->plugin->rate == rate))){
+ goto compare_fmtp;
+ }
+ }
+ // Fixed payload type
+ else{
+ if (tsk_striequals(fmt->value, codec->format)){
+ goto compare_fmtp;
+ }
+ }
+
+ /* rtpmap do not match: free strings and try next codec */
+ goto next;
+
+ compare_fmtp:
+ if ((fmtp = tsdp_header_M_get_fmtp(M, fmt->value))){ /* remote have fmtp? */
+ if (tmedia_codec_sdp_att_match(codec, "fmtp", fmtp)){ /* fmtp matches? */
+ if (codec->type & tmedia_video) goto compare_imageattr;
+ else found = tsk_true;
+ }
+ else goto next;
+ }
+ else{ /* no fmtp -> always match */
+ if (codec->type & tmedia_video) goto compare_imageattr;
+ else found = tsk_true;
+ }
+
+ compare_imageattr:
+ if (codec->type & tmedia_video){
+ if ((image_attr = tsdp_header_M_get_imageattr(M, fmt->value))){
+ if (tmedia_codec_sdp_att_match(codec, "imageattr", image_attr)) found = tsk_true;
+ }
+ else found = tsk_true;
+ }
+
+ // update neg. format
+ if (found) tsk_strupdate((char**)&codec->neg_format, fmt->value);
+
+ next:
+ TSK_FREE(name);
+ TSK_FREE(fmtp);
+ TSK_FREE(rtpmap);
+ TSK_FREE(image_attr);
+ if (found){
+ tmedia_codec_t * copy;
+ if (!matchingCodecs){
+ matchingCodecs = tsk_list_create();
+ }
+ copy = tsk_object_ref((void*)codec);
+ tsk_list_push_back_data(matchingCodecs, (void**)&copy);
+
+ found = tsk_false;
+ break;
+ }
+ }
+ }
+
+
+ return matchingCodecs;
+}
+
+int tmedia_session_set_onrtcp_cbfn(tmedia_session_t* self, const void* context, tmedia_session_rtcp_onevent_cb_f func)
+{
+ if (self && self->plugin && self->plugin->rtcp.set_onevent_cbfn){
+ return self->plugin->rtcp.set_onevent_cbfn(self, context, func);
+ }
+ return -1;
+}
+
+int tmedia_session_send_rtcp_event(tmedia_session_t* self, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media)
+{
+ if (self && self->plugin && self->plugin->rtcp.send_event){
+ return self->plugin->rtcp.send_event(self, event_type, ssrc_media);
+ }
+ TSK_DEBUG_INFO("Not sending RTCP event with SSRC = %u because no callback function found", ssrc_media);
+ return -1;
+}
+
+int tmedia_session_recv_rtcp_event(tmedia_session_t* self, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media)
+{
+ if (self && self->plugin && self->plugin->rtcp.recv_event){
+ return self->plugin->rtcp.recv_event(self, event_type, ssrc_media);
+ }
+ TSK_DEBUG_INFO("Not receiving RTCP event with SSRC = %u because no callback function found", ssrc_media);
+ return -1;
+}
+
+int tmedia_session_set_onerror_cbfn(tmedia_session_t* self, const void* usrdata, tmedia_session_onerror_cb_f fun)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->onerror_cb.fun = fun;
+ self->onerror_cb.usrdata = usrdata;
+ return 0;
+}
+
+int tmedia_session_set_rfc5168_cbfn(tmedia_session_t* self, const void* usrdata, tmedia_session_rfc5168_cb_f fun)
+{
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->rfc5168_cb.fun = fun;
+ self->rfc5168_cb.usrdata = usrdata;
+ return 0;
+}
+
+int tmedia_session_set_bfcp_cbfn(tmedia_session_t* self, const void* usrdata, tmedia_session_bfcp_cb_f fun)
+{
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->bfcp_cb.fun = fun;
+ self->bfcp_cb.usrdata = usrdata;
+ return 0;
+}
+
+/**@ingroup tmedia_session_group
+* DeInitializes a media session.
+* @param self the media session to deinitialize.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tmedia_session_deinit(tmedia_session_t* self)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* free codecs */
+ TSK_OBJECT_SAFE_FREE(self->codecs);
+ TSK_OBJECT_SAFE_FREE(self->neg_codecs);
+
+ /* free lo, no and ro */
+ TSK_OBJECT_SAFE_FREE(self->M.lo);
+ TSK_OBJECT_SAFE_FREE(self->M.ro);
+
+ /* QoS */
+ TSK_OBJECT_SAFE_FREE(self->qos);
+
+ /* DTLS */
+ TSK_FREE(self->dtls.file_ca);
+ TSK_FREE(self->dtls.file_pbk);
+ TSK_FREE(self->dtls.file_pvk);
+
+ return 0;
+}
+
+/**@ingroup tmedia_session_group
+* Send DTMF event
+* @param self the audio session to use to send a DTMF event
+* @param event the DTMF event to send (should be between 0-15)
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tmedia_session_audio_send_dtmf(tmedia_session_audio_t* self, uint8_t event)
+{
+ if (!self || !TMEDIA_SESSION(self)->plugin || !TMEDIA_SESSION(self)->plugin->audio.send_dtmf){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return TMEDIA_SESSION(self)->plugin->audio.send_dtmf(TMEDIA_SESSION(self), event);
+}
+
+int tmedia_session_t140_set_ondata_cbfn(tmedia_session_t* self, const void* context, tmedia_session_t140_ondata_cb_f func)
+{
+ if (self && self->plugin && self->plugin->t140.set_ondata_cbfn){
+ return self->plugin->t140.set_ondata_cbfn(self, context, func);
+ }
+ return -1;
+}
+
+int tmedia_session_t140_send_data(tmedia_session_t* self, enum tmedia_t140_data_type_e data_type, const void* data_ptr, unsigned data_size)
+{
+ if (self && self->plugin && self->plugin->t140.send_data){
+ return self->plugin->t140.send_data(self, data_type, data_ptr, data_size);
+ }
+ return -1;
+}
+
+/* internal function used to prepare a session */
+int _tmedia_session_load_codecs(tmedia_session_t* self)
+{
+ tsk_size_t i = 0;
+ tmedia_codec_t* codec;
+ const tmedia_codec_plugin_def_t* plugin;
+ const tsk_list_item_t* item;
+ tmedia_type_t type;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (!self->codecs && !(self->codecs = tsk_list_create())){
+ TSK_DEBUG_ERROR("Failed to create new list");
+ return -1;
+ }
+
+ tsk_list_lock(self->codecs);
+
+ /* remove old codecs */
+ tsk_list_clear_items(self->codecs);
+
+ type = self->type;
+ if ((type & tmedia_bfcp_video) == tmedia_bfcp_video) {
+ type |= tmedia_video;
+ }
+ if ((type & tmedia_bfcp_audio) == tmedia_bfcp_audio) {
+ type |= tmedia_audio;
+ }
+
+ /* for each registered plugin create a session instance */
+ while ((i < TMED_CODEC_MAX_PLUGINS) && (plugin = __tmedia_codec_plugins[i++])){
+ /* 'tmedia_codec_id_none' is used for fake codecs (e.g. dtmf, bfcp or msrp) and should not be filtered beacuse of backward compatibility*/
+ if ((plugin->type & type) && (plugin->codec_id == tmedia_codec_id_none || (plugin->codec_id & self->codecs_allowed))){
+ // do not load bfcp codec for "audiobfcp" and "videobfcp" session
+ if ((plugin->type == tmedia_bfcp) && (type != tmedia_bfcp)) {
+ continue;
+ }
+ if ((codec = tmedia_codec_create(plugin->format))){
+ if (!self->codecs){
+ self->codecs = tsk_list_create();
+ }
+ tsk_list_push_back_data(self->codecs, (void**)(&codec));
+ }
+ }
+ }
+
+ // filter negotiated codecs with the newly loaded codecs
+ if (1){ // code valid for all use-cases but for now it's not fully tested and not needed for the clients
+ filter_neg_codecs:
+ tsk_list_foreach(item, self->neg_codecs){
+ if (!(codec = (item->data))){
+ continue;
+ }
+ if (!(tsk_list_find_item_by_pred(self->codecs, __pred_find_codec_by_id, &codec->id))){
+ const char* codec_name = codec->plugin ? codec->plugin->name : "unknown";
+ const char* neg_format = codec->neg_format ? codec->neg_format : codec->format;
+ TSK_DEBUG_INFO("Codec '%s' with format '%s' was negotiated but [supported codecs] updated without it -> removing", codec_name, neg_format);
+ // update sdp and remove the codec from the list
+ if (self->M.lo && !TSK_LIST_IS_EMPTY(self->M.lo->FMTs)){
+ if (self->M.lo->FMTs->head->next == tsk_null && tsdp_header_M_have_fmt(self->M.lo, neg_format)){ // single item?
+ // rejecting a media with port equal to zero requires at least one format
+ TSK_DEBUG_INFO("[supported codecs] updated but do not remove codec with name='%s' and format='%s' because it's the last one", codec_name, neg_format);
+ self->M.lo->port = 0;
+ }
+ else{
+ tsdp_header_M_remove_fmt(self->M.lo, neg_format);
+ }
+ }
+ tsk_list_remove_item_by_data(self->neg_codecs, codec);
+ goto filter_neg_codecs;
+ }
+ }
+ }
+
+ tsk_list_unlock(self->codecs);
+
+ return 0;
+}
+
+
+/**@ingroup tmedia_session_group
+* Creates new session manager.
+* @param type the type of the session to create. For example, (@ref tmed_sess_type_audio | @ref tmed_sess_type_video).
+* @param addr the local ip address or FQDN to use in the sdp message.
+* @param ipv6 indicates whether @a addr is IPv6 address or not. Useful when @a addr is a FQDN.
+* @param load_sessions Whether the offerer or not.
+* will create an audio/video session.
+* @retval new @ref tmedia_session_mgr_t object
+*/
+tmedia_session_mgr_t* tmedia_session_mgr_create(tmedia_type_t type, const char* addr, tsk_bool_t ipv6, tsk_bool_t offerer)
+{
+ tmedia_session_mgr_t* mgr;
+
+ if (!(mgr = tsk_object_new(tmedia_session_mgr_def_t))){
+ TSK_DEBUG_ERROR("Failed to create Media Session manager");
+ return tsk_null;
+ }
+
+ /* init */
+ mgr->type = type;
+ mgr->addr = tsk_strdup(addr);
+ mgr->ipv6 = ipv6;
+
+ /* load sessions (will allow us to generate lo) */
+ if (offerer){
+ mgr->offerer = tsk_true;
+ //if(_tmedia_session_mgr_load_sessions(mgr)){
+ /* Do nothing */
+ // TSK_DEBUG_ERROR("Failed to load sessions");
+ //}
+ }
+
+ return mgr;
+}
+
+/**@ingroup tmedia_session_group
+ */
+int tmedia_session_mgr_set_media_type(tmedia_session_mgr_t* self, tmedia_type_t type)
+{
+ static tsk_bool_t __force_set = tsk_false;
+ return tmedia_session_mgr_set_media_type_2(self, type, __force_set);
+}
+
+/**@ingroup tmedia_session_group
+ */
+int tmedia_session_mgr_set_media_type_2(tmedia_session_mgr_t* self, tmedia_type_t type, tsk_bool_t force)
+{
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (force || self->type != type) {
+ self->mediaType_changed = tsk_true;
+ self->type = type;
+ }
+ return 0;
+}
+
+// special set() case
+int tmedia_session_mgr_set_codecs_supported(tmedia_session_mgr_t* self, tmedia_codec_id_t codecs_supported)
+{
+ int ret = 0;
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ // calling set() could create zombies (media sessions with port equal to zero)
+ ret = tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_INT32(self->type, "codecs-supported", codecs_supported),
+ tsk_null);
+ if (ret == 0 && self->sdp.lo){
+ // update type (will discard zombies)
+ tmedia_type_t new_type = tmedia_type_from_sdp(self->sdp.lo);
+ if (new_type != self->type){
+ TSK_DEBUG_INFO("codecs-supported updated and media type changed from %d to %d", self->type, new_type);
+ self->type = new_type;
+ }
+ }
+ return ret;
+}
+
+/**@ingroup tmedia_session_group
+*/
+tmedia_session_t* tmedia_session_mgr_find(tmedia_session_mgr_t* self, tmedia_type_t type)
+{
+ tmedia_session_t* session;
+
+ tsk_list_lock(self->sessions);
+ session = (tmedia_session_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &type);
+ tsk_list_unlock(self->sessions);
+
+ return tsk_object_ref(session);
+}
+
+/**@ingroup tmedia_session_group
+*/
+int tmedia_session_mgr_set_natt_ctx(tmedia_session_mgr_t* self, struct tnet_nat_ctx_s* natt_ctx, const char* public_addr)
+{
+ if (!self || !natt_ctx){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ TSK_OBJECT_SAFE_FREE(self->natt_ctx);
+ self->natt_ctx = tsk_object_ref(natt_ctx);
+ tsk_strupdate(&self->public_addr, public_addr);
+
+ tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_POBJECT(self->type, "natt-ctx", self->natt_ctx),
+ TMEDIA_SESSION_SET_NULL());
+ return 0;
+}
+
+// @deprecated
+int tmedia_session_mgr_set_ice_ctx(tmedia_session_mgr_t* self, struct tnet_ice_ctx_s* ctx_audio, struct tnet_ice_ctx_s* ctx_video)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ TSK_OBJECT_SAFE_FREE(self->ice.ctx_audio); // backward compatibility
+ TSK_OBJECT_SAFE_FREE(self->ice.ctx_video); // backward compatibility
+ if (self->type & tmedia_audio) {
+ tmedia_session_mgr_set_ice_ctx_2(self, tmedia_audio, ctx_audio);
+ }
+ if (self->type & tmedia_video) {
+ tmedia_session_mgr_set_ice_ctx_2(self, tmedia_video, ctx_video);
+ }
+ return 0;
+}
+
+int tmedia_session_mgr_set_ice_ctx_2(tmedia_session_mgr_t* self, tmedia_type_t type, struct tnet_ice_ctx_s* ctx)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if ((self->type & type) == type) {
+ struct tnet_ice_ctx_s **_ctx = tsk_null;
+ switch (type) {
+ case tmedia_audio: _ctx = &self->ice.ctx_audio; break;
+ case tmedia_video: _ctx = &self->ice.ctx_video; break;
+ case tmedia_bfcp_video: _ctx = &self->ice.ctx_bfcpvid; break;
+ default: TSK_DEBUG_ERROR("Media type(%d) not supported by this session manager", type); return -2;
+ }
+ TSK_OBJECT_SAFE_FREE((*_ctx));
+ *_ctx = tsk_object_ref(ctx);
+ return tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_POBJECT(type, "ice-ctx", ctx),
+ TMEDIA_SESSION_SET_NULL());
+ }
+ else if (!ctx) { //cleanup
+ switch (type) {
+ case tmedia_audio: TSK_OBJECT_SAFE_FREE(self->ice.ctx_audio); return 0;
+ case tmedia_video: TSK_OBJECT_SAFE_FREE(self->ice.ctx_video); return 0;
+ case tmedia_bfcp_video: TSK_OBJECT_SAFE_FREE(self->ice.ctx_bfcpvid); return 0;
+ }
+ }
+ TSK_DEBUG_ERROR("Ignoring ICE context definition for media type %d", type);
+ return -2;
+}
+
+/**@ingroup tmedia_session_group
+* Starts the session manager by starting all underlying sessions.
+* You should set both remote and local offers before calling this function.
+* @param self The session manager to start.
+* @retval Zero if succced and non-zero error code otherwise.
+*
+* @sa @ref tmedia_session_mgr_stop
+*/
+int tmedia_session_mgr_start(tmedia_session_mgr_t* self)
+{
+ return _tmedia_session_mgr_start(self, kSessionIndexAll);
+}
+
+/**@ingroup tmedia_session_group
+* sets parameters for one or several sessions.
+* @param self The session manager
+* @param ... Any TMEDIA_SESSION_SET_*() macros
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_session_mgr_set(tmedia_session_mgr_t* self, ...)
+{
+ va_list ap;
+ int ret;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ va_start(ap, self);
+ ret = tmedia_session_mgr_set_2(self, &ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/**@ingroup tmedia_session_group
+* sets parameters for one or several sessions.
+* @param self The session manager
+* @param app List of parameters.
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_session_mgr_set_2(tmedia_session_mgr_t* self, va_list *app)
+{
+ tmedia_params_L_t* params;
+
+ if (!self || !app){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if ((params = tmedia_params_create_2(app))){
+ if (!self->params){
+ self->params = tsk_object_ref(params);
+ }
+ else{
+ tsk_list_pushback_list(self->params, params);
+ }
+ TSK_OBJECT_SAFE_FREE(params);
+ }
+
+ /* load params if we already have sessions */
+ if (!TSK_LIST_IS_EMPTY(self->sessions)){
+ _tmedia_session_mgr_apply_params(self);
+ }
+
+ return 0;
+}
+
+/**@ingroup tmedia_session_group
+* sets parameters for one or several sessions.
+* @param self The session manager
+* @param params List of parameters to set
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_session_mgr_set_3(tmedia_session_mgr_t* self, const tmedia_params_L_t* params)
+{
+ if (!self || !params){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (!self->params){
+ self->params = tsk_list_create();
+ }
+ tsk_list_pushback_list(self->params, params);
+
+ /* load params if we already have sessions */
+ if (!TSK_LIST_IS_EMPTY(self->sessions)){
+ _tmedia_session_mgr_apply_params(self);
+ }
+
+ return 0;
+}
+
+int tmedia_session_mgr_get(tmedia_session_mgr_t* self, ...)
+{
+ va_list ap;
+ int ret = 0;
+ tmedia_params_L_t* params;
+ const tsk_list_item_t *item1, *item2;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ va_start(ap, self);
+
+ if ((params = tmedia_params_create_2(&ap))){
+ tmedia_session_t* session;
+ tmedia_param_t* param;
+ tsk_list_foreach(item2, params){
+ if ((param = item2->data)){
+ tsk_list_foreach(item1, self->sessions){
+ if (!(session = (tmedia_session_t*)item1->data) || !session->plugin){
+ continue;
+ }
+ if ((session->type & param->media_type) == session->type && session->plugin->set){
+ ret = session->plugin->get(session, param);
+ }
+ }
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(params);
+ }
+
+ va_end(ap);
+
+ return ret;
+}
+
+/**@ingroup tmedia_session_group
+* Stops the session manager by stopping all underlying sessions.
+* @param self The session manager to stop.
+* @retval Zero if succced and non-zero error code otherwise.
+*
+* @sa @ref tmedia_session_mgr_start
+*/
+int tmedia_session_mgr_stop(tmedia_session_mgr_t* self)
+{
+ return _tmedia_session_mgr_stop(self, kSessionIndexAll);
+}
+
+/**@ingroup tmedia_session_group
+* Gets local offer.
+*/
+const tsdp_message_t* tmedia_session_mgr_get_lo(tmedia_session_mgr_t* self)
+{
+ return _tmedia_session_mgr_get_lo(self, kSkipSessionLoadFalse, kForceUpdateLOFalse);
+}
+
+
+/**@ingroup tmedia_session_group
+* Sets remote offer.
+*/
+int tmedia_session_mgr_set_ro(tmedia_session_mgr_t* self, const tsdp_message_t* sdp, tmedia_ro_type_t ro_type)
+{
+ const tmedia_session_t* ms;
+ const tsdp_header_M_t* M;
+ const tsdp_header_C_t* C; /* global "c=" line */
+ const tsdp_header_O_t* O;
+ tsk_size_t index = 0;
+ tsk_size_t active_sessions_count = 0, m_lines_count = 0;
+ int ret = 0;
+ tsk_bool_t found;
+ tsk_bool_t stopped_to_reconf[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_ro_codecs_changed[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_local_encoder_still_ok[TMEDIA_SESSION_MAX_LINES] = { tsk_false }; // decoder is dynamically mapped for each incoming rtp frame -> no need to check it
+ tsk_bool_t is_ro_network_info_changed[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_ro_hold_resume_changed[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_ro_loopback_address[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_ice_enabled[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_ice_restart[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_dtls_fingerprint_changed[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_sdes_crypto_changed[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tmedia_type_t media_types[TMEDIA_SESSION_MAX_LINES] = { tmedia_none };
+ tsk_bool_t is_media_type_changed = tsk_false;
+ tsk_bool_t is_ro_media_lines_changed = tsk_false;
+ tsk_bool_t had_ro_sdp, had_lo_sdp, had_ro_provisional, is_ro_provisional_final_matching = tsk_false;
+ tsk_bool_t is_new_mediatype_striped = tsk_false;
+ tmedia_qos_stype_t qos_type = tmedia_qos_stype_none;
+ tmedia_type_t new_mediatype = tmedia_none;
+ tmedia_sessions_L_t *list_tmp_sessions;
+
+ if (!self || !sdp) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!(list_tmp_sessions = tsk_list_create())) {
+ TSK_DEBUG_ERROR("Failed to create tmp list");
+ return -2;
+ }
+
+ tsk_safeobj_lock(self);
+ tsk_list_lock(self->sessions);
+
+ new_mediatype = tmedia_type_from_sdp(sdp);
+ had_ro_sdp = (self->sdp.ro != tsk_null);
+ had_lo_sdp = (self->sdp.lo != tsk_null);
+ had_ro_provisional = (had_ro_sdp && self->ro_provisional);
+
+ // Remove BFCP offer if not locally enabled. Only the client can init BFCP session.
+ if ((ro_type & tmedia_ro_type_offer)) {
+ if (!(self->type & tmedia_bfcp_video)) {
+ is_new_mediatype_striped |= (new_mediatype & tmedia_bfcp_video);
+ new_mediatype &= ~tmedia_bfcp_video;
+ }
+ if (!(self->type & tmedia_bfcp_audio)) {
+ is_new_mediatype_striped |= (new_mediatype & tmedia_bfcp_video);
+ new_mediatype &= ~tmedia_bfcp_audio;
+ }
+ if (!(self->type & tmedia_bfcp)) {
+ is_new_mediatype_striped |= (new_mediatype & tmedia_bfcp_video);
+ new_mediatype &= ~tmedia_bfcp;
+ }
+ }
+
+ /* RFC 3264 subcaluse 8
+ When issuing an offer that modifies the session, the "o=" line of the new SDP MUST be identical to that in the previous SDP,
+ except that the version in the origin field MUST increment by one from the previous SDP. If the version in the origin line
+ does not increment, the SDP MUST be identical to the SDP with that version number. The answerer MUST be prepared to receive
+ an offer that contains SDP with a version that has not changed; this is effectively a no-op.
+ */
+ if ((O = (const tsdp_header_O_t*)tsdp_message_get_header(sdp, tsdp_htype_O))){
+ tsk_bool_t is_ro_provisional;
+ if (self->sdp.ro_ver == (int32_t)O->sess_version){
+ TSK_DEBUG_INFO("Remote offer has not changed");
+ ret = 0;
+ goto bail;
+ }
+ // Last provisional and new final sdp messages match only if:
+ // - session version diff is == 1
+ // - previous sdp was provisional and new one is final
+ // - the new final sdp is inside an answer
+ is_ro_provisional = ((ro_type & tmedia_ro_type_provisional) == tmedia_ro_type_provisional);
+ is_ro_provisional_final_matching = ((had_ro_provisional && !is_ro_provisional) && ((self->sdp.ro_ver + 1) == O->sess_version) && ((ro_type & tmedia_ro_type_answer) == tmedia_ro_type_answer));
+ self->sdp.ro_ver = (int32_t)O->sess_version;
+ }
+ else{
+ TSK_DEBUG_ERROR("o= line is missing");
+ ret = -2;
+ goto bail;
+ }
+
+ /* SDP comparison */
+ if ((sdp && self->sdp.ro)){
+ const tsdp_header_M_t *M0, *M1;
+ const tsdp_header_C_t *C0, *C1;
+ const tsdp_header_A_t *A0, *A1;
+ const tsdp_header_A_t *A0_sess_fp, *A1_sess_fp; // session-level fingerprints
+ tsdp_header_M_diff_t med_level_diff; // media-level diff
+ index = 0;
+ A0_sess_fp = tsdp_message_get_headerA(self->sdp.ro, "fingerprint");
+ A1_sess_fp = tsdp_message_get_headerA(sdp, "fingerprint");
+ while ((M0 = (const tsdp_header_M_t*)tsdp_message_get_headerAt(self->sdp.ro, tsdp_htype_M, index))){
+ ++m_lines_count;
+ if (m_lines_count >= TMEDIA_SESSION_MAX_LINES) {
+ TSK_DEBUG_ERROR("Too many m-lines %u>%u", (unsigned)m_lines_count, (unsigned)TMEDIA_SESSION_MAX_LINES);
+ ret = -2;
+ goto bail;
+ }
+ M1 = (const tsdp_header_M_t*)tsdp_message_get_headerAt(sdp, tsdp_htype_M, index);
+ // media-level diffs
+
+ if ((ret = tsdp_header_M_diff(M0, M1, &med_level_diff)) != 0) {
+ goto bail;
+ }
+ if (med_level_diff & tsdp_header_M_diff_hold_resume) is_ro_hold_resume_changed[index] = tsk_true;
+ if (med_level_diff & tsdp_header_M_diff_index) is_ro_media_lines_changed = tsk_true;
+ if (med_level_diff & tsdp_header_M_diff_codecs) is_ro_codecs_changed[index] = tsk_true;
+ if (med_level_diff & tsdp_header_M_diff_network_info) is_ro_network_info_changed[index] = tsk_true;
+ if (tmedia_defaults_get_ice_enabled() && (med_level_diff & tsdp_header_M_diff_ice_enabled)) is_ice_enabled[index] = tsk_true;
+ if (tmedia_defaults_get_ice_enabled() && (med_level_diff & tsdp_header_M_diff_ice_restart)) is_ice_restart[index] = tsk_true;
+ if (med_level_diff & tsdp_header_M_diff_dtls_fingerprint) is_dtls_fingerprint_changed[index] = tsk_true;
+ if (med_level_diff & tsdp_header_M_diff_sdes_crypto) is_sdes_crypto_changed[index] = tsk_true;
+ if (med_level_diff & tsdp_header_M_diff_media_type); // cannot happen as media must keep same index
+
+ // dtls fingerprint (session-level)
+ if (!is_dtls_fingerprint_changed[index]) {
+ A0 = tsdp_header_M_findA_at(M0, "fingerprint", 0);
+ A1 = M1 ? tsdp_header_M_findA_at(M1, "fingerprint", 0) : tsk_null;
+ is_dtls_fingerprint_changed[index] = (A0 && A1 && !tsk_striequals(A0->value, A1->value));
+ }
+ // network info (session-level)
+ if (!is_ro_network_info_changed[index]) {
+ C0 = (const tsdp_header_C_t*)tsdp_message_get_headerAt(self->sdp.ro, tsdp_htype_C, index);
+ C1 = (const tsdp_header_C_t*)tsdp_message_get_headerAt(sdp, tsdp_htype_C, index);
+ // Connection informations must be both "null" or "not-null"
+ if (!(is_ro_network_info_changed[index] = !((C0 && C1) || (!C0 && !C1)))){
+ if (C0) {
+ is_ro_network_info_changed[index] = (!tsk_strequals(C1->addr, C0->addr) || !tsk_strequals(C1->nettype, C0->nettype) || !tsk_strequals(C1->addrtype, C0->addrtype));
+ }
+ }
+ }
+ // TODO: sdes crypo lines (session-level)
+
+ // media type
+ media_types[index] = tmedia_type_from_sdp_headerM(M1);
+
+ // ice (session-level)
+ if (tmedia_defaults_get_ice_enabled()) {
+ is_ice_enabled[index] |= tsdp_message_is_ice_enabled(sdp, index);
+ is_ice_restart[index] |= tsdp_message_is_ice_restart(sdp, index);
+ }
+
+ // ro_codecs
+ if (had_lo_sdp && is_ro_codecs_changed[index]) {
+ // we already have a local sdp (means codecs already negotiated) and the remote is changing the codecs
+ tmedia_session_t* ms = (tmedia_session_t*)tsk_object_ref(TSK_OBJECT(_tmedia_session_mgr_find_session_at_index(self->sessions, index)));
+ if (ms && ms->prepared) {
+ tmedia_codec_t* encoder = tsk_null;
+ tmedia_param_t* param_get_codec = tmedia_param_create_get_session(media_types[index], tmedia_pvt_pobject, "codec-encoder", &encoder);
+ if (param_get_codec) {
+ if (tmedia_session_get(ms, param_get_codec) == 0) {
+ if (encoder) {
+ const char* codec_name = encoder->plugin ? encoder->plugin->name : "unknown";
+ const char* neg_format = encoder->neg_format ? encoder->neg_format : encoder->format;
+ if (tsdp_header_M_have_fmt(M1, neg_format) == tsk_true) { // new ro has the old encoder?
+ // same rtpmap would produce same encoder -> change nothing
+ char* old_rtpmap = tsdp_header_M_get_rtpmap(M0, neg_format);
+ char* new_rtpmap = tsdp_header_M_get_rtpmap(M1, neg_format);
+ is_local_encoder_still_ok[index] = tsk_striequals(old_rtpmap, new_rtpmap);
+ TSK_FREE(old_rtpmap); TSK_FREE(new_rtpmap);
+ if (is_local_encoder_still_ok[index]) {
+ // TODO: add more checks
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(encoder); // destroying "param_get_codec" won't release "encoder"
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(param_get_codec);
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(ms);
+ }
+
+ ++index;
+ }
+ // the index was used against current ro which means at this step there is no longer any media at "index"
+ // to be sure that new and old sdp have same number of media lines, we just check that there is no media in the new sdp at "index"
+ is_ro_media_lines_changed |= (tsdp_message_get_headerAt(sdp, tsdp_htype_M, index) != tsk_null);
+ }
+
+ /*
+ * Make sure that the provisional response is an preview of the final as explained rfc6337 section 3.1.1. We only check the most important part (IP addr and ports).
+ * It's useless to check codecs or any other caps (SRTP, ICE, DTLS...) as our offer haven't changed
+ * If the preview is different than the final response than this is a bug on the remote party:
+ * As per rfc6337 section 3.1.1.:
+ * - [RFC3261] requires all SDP in the responses to the INVITE request to be identical.
+ * - After the UAS has sent the answer in a reliable provisional
+ response to the INVITE, the UAS should not include any SDPs in
+ subsequent responses to the INVITE.
+ * If the remote party is buggy, then the newly generated local SDP will be sent in the ACK request
+ */
+ is_ro_provisional_final_matching &= !(is_ro_media_lines_changed || __flags_sum((const tsk_bool_t*)&is_ro_network_info_changed, m_lines_count));
+
+ /* This is to hack fake forking from ZTE => ignore SDP with loopback address in order to not start/stop the camera several
+ * times which leads to more than ten seconds for session connection.
+ * Gets the global connection line: "c="
+ * Loopback address is only invalid on
+ */
+ if ((C = (const tsdp_header_C_t*)tsdp_message_get_header(sdp, tsdp_htype_C)) && C->addr){
+ tsk_bool_t _is_ro_loopback_address = (tsk_striequals("IP4", C->addrtype) && tsk_striequals("127.0.0.1", C->addr))
+ || (tsk_striequals("IP6", C->addrtype) && tsk_striequals("::1", C->addr));
+ for (index = 0; index < m_lines_count; ++index) {
+ is_ro_loopback_address[index] = _is_ro_loopback_address;
+ }
+ }
+
+ /* Check if media type has changed or not
+ * For initial offer we don't need to check anything
+ */
+ if (self->sdp.lo) {
+ if ((is_media_type_changed = (new_mediatype != self->type)) || is_new_mediatype_striped) {
+ tsk_bool_t force = !!is_new_mediatype_striped;
+ tmedia_session_mgr_set_media_type_2(self, new_mediatype, force);
+ TSK_DEBUG_INFO("media type has changed");
+ }
+ }
+
+ TSK_DEBUG_INFO(
+ "m_lines_count=%u,\n"
+ "is_dtls_fingerprint_changed=%u,\n"
+ "is_sdes_crypto_changed=%u,\n"
+ "is_ice_enabled=%u,\n"
+ "is_ice_restart=%u,\n"
+ "is_ro_hold_resume_changed=%u,\n"
+ "is_ro_provisional_final_matching=%d,\n"
+ "is_ro_media_lines_changed=%d,\n"
+ "is_ro_network_info_changed=%u,\n"
+ "is_ro_loopback_address=%u,\n"
+ "is_media_type_changed=%d,\n"
+ "is_ro_codecs_changed=%u\n"
+ "is_local_encoder_still_ok=%u\n",
+ (unsigned)m_lines_count,
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_dtls_fingerprint_changed, m_lines_count),
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_sdes_crypto_changed, m_lines_count),
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_ice_enabled, m_lines_count),
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_ice_restart, m_lines_count),
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_ro_hold_resume_changed, m_lines_count),
+ is_ro_provisional_final_matching,
+ is_ro_media_lines_changed,
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_ro_network_info_changed, m_lines_count),
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_ro_loopback_address, m_lines_count),
+ is_media_type_changed,
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_ro_codecs_changed, m_lines_count),
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_local_encoder_still_ok, m_lines_count)
+ );
+
+ /*
+ * It's almost impossible to update the codecs, the connection information etc etc while the sessions are running
+ * For example, if the video producer is already started then, you probably cannot update its configuration
+ * without stoping it and restarting it again with the right config. Same for RTP Network config (ip addresses, NAT, ports, IP version, ...)
+ *
+ * "is_loopback_address" is used as a guard to avoid reconf for loopback address used for example by ZTE for fake forking. In all case
+ * loopback address won't work on embedded devices such as iOS and Android.
+ *
+ */
+ if (self->started) {
+ for (index = 0; index < m_lines_count; ++index) {
+ if (/* && (!is_ro_loopback_address[index]) && */ ((is_ro_codecs_changed[index] && !is_local_encoder_still_ok[index]) || is_ro_network_info_changed[index] || is_dtls_fingerprint_changed[index] || is_sdes_crypto_changed[index])) {
+ TSK_DEBUG_INFO("Stop media index %d to reconf", (int)index);
+ stopped_to_reconf[index] = tsk_true;
+ tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_INT32(media_types[index], "stop-to-reconf", stopped_to_reconf[index]),
+ TMEDIA_SESSION_SET_NULL());
+ if ((ret = _tmedia_session_mgr_stop(self, (int)index))){
+ TSK_DEBUG_ERROR("Failed to stop session manager");
+ goto bail;
+ }
+ }
+ }
+ }
+
+ /* update remote offer */
+ TSK_OBJECT_SAFE_FREE(self->sdp.ro);
+ self->sdp.ro = tsk_object_ref((void*)sdp);
+
+ /* - if the session is running this means no session update is required unless some important changes
+ - this check must be done after the "ro" update
+ - "is_ro_hold_resume_changed" do not restart the session but updates the SDP
+ */
+ if (self->started && !(__flags_sum((const tsk_bool_t*)&is_ro_hold_resume_changed, m_lines_count) || __flags_sum((const tsk_bool_t*)&stopped_to_reconf, m_lines_count) || is_ro_media_lines_changed)) {
+ goto end_of_sessions_update;
+ }
+
+ /* prepare the session manager if not already done (create all sessions with their codecs)
+ * if network-initiated: think about tmedia_type_from_sdp() before creating the manager */
+ if (_tmedia_session_mgr_load_sessions(self)){
+ TSK_DEBUG_ERROR("Failed to prepare the session manager");
+ ret = -3;
+ goto bail;
+ }
+ // update media line counts
+ index = m_lines_count; // save old "m_lines_count" before loading sessions
+ m_lines_count = tsk_list_count_all(self->sessions); // "m_lines_count" after loading sessions
+ TSK_DEBUG_INFO("new m_lines_count = %u -> %u", (unsigned)index, (unsigned)m_lines_count);
+ if (index != m_lines_count) { // start new sessions
+ for (; index < m_lines_count; ++index) { // for(session in new_sessions)
+ stopped_to_reconf[index] = self->started; // start new session if mgr started
+ if (tmedia_defaults_get_ice_enabled()) {
+ is_ice_enabled[index] |= tsdp_message_is_ice_enabled(sdp, index);
+ is_ice_restart[index] |= tsdp_message_is_ice_restart(sdp, index);
+ }
+ }
+ }
+
+ /* get global connection line (common to all sessions)
+ * Each session should override this info if it has a different one in its "m=" line
+ * /!\ "remote-ip" is deprecated by "remote-sdp-message" and pending before complete remove
+ */
+ if (C && C->addr){
+ tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_STR(self->type, "remote-ip", C->addr),
+ TMEDIA_SESSION_SET_NULL());
+ }
+
+ /* pass complete remote sdp to the sessions to allow them to use session-level attributes
+ */
+ tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_POBJECT(self->type, "remote-sdp-message", self->sdp.ro),
+ TMEDIA_SESSION_SET_NULL());
+
+ /* foreach "m=" line in the remote offer create/prepare a session (requires the session to be stopped)*/
+ index = 0;
+ tsk_list_pushback_list(list_tmp_sessions, self->sessions);
+ tsk_list_clear_items(self->sessions);
+ while ((M = (const tsdp_header_M_t*)tsdp_message_get_headerAt(sdp, tsdp_htype_M, index++))) {
+ found = tsk_false;
+#if 1
+ // rfc3264 - 8 Modifying the Session
+ // if the previous SDP had N "m=" lines, the new SDP MUST have at least N "m=" lines
+ // Deleted media streams from a previous SDP MUST NOT be removed in a new SDP
+ if (had_lo_sdp) {
+ ms = _tmedia_session_mgr_find_session_at_index(list_tmp_sessions, (index - 1 - active_sessions_count));
+ }
+ else {
+ // Initial Offer
+ tmedia_type_t M_media_type = tmedia_type_from_sdp_headerM(M);
+ ms = tsk_list_find_object_by_pred(list_tmp_sessions, __pred_find_session_by_type, &M_media_type);
+ }
+#else
+ if (ro_type & tmedia_ro_type_answer) {
+ // Answer -> match by index
+ ms = _tmedia_session_mgr_find_session_at_index(list_tmp_sessions, (index - 1 - active_sessions_count));
+ }
+ else {
+ // Request -> match by type
+ tmedia_type_t M_media_type = tmedia_type_from_sdp_headerM(M);
+ ms = tsk_list_find_object_by_pred(list_tmp_sessions, __pred_find_session_by_type, &M_media_type);
+ }
+#endif
+ if (ms && (tsk_striequals(tmedia_session_get_media(ms), M->media))) {
+ /* prepare the media session */
+ if (!ms->prepared && M->port && (_tmedia_session_prepare(TMEDIA_SESSION(ms)))){
+ TSK_DEBUG_ERROR("Failed to prepare session"); /* should never happen */
+ goto bail;
+ }
+ /* set remote ro at session-level unless media is disabled (port=0) */
+ if (M->port == 0 || (ret = _tmedia_session_set_ro(TMEDIA_SESSION(ms), M)) == 0) {
+ tmedia_session_t* _ms = tsk_object_ref(TSK_OBJECT(ms));
+ found = tsk_true;
+ ++active_sessions_count;
+ tsk_list_push_back_data(self->sessions, (void**)&_ms); // add at the same index
+ tsk_list_remove_item_by_data(list_tmp_sessions, ms); // make sure not to use the session more than once
+ }
+ else {
+ TSK_DEBUG_WARN("_tmedia_session_set_ro() failed");
+ ret = 0; // add ghost for this session. Do not goto bail because set_ro() is allowed to fail (e.g. codec mismatch).
+ }
+ /* set QoS type (only if we are not the offerer) */
+ if (/*!self->offerer ==> we suppose that the remote party respected our demand &&*/ qos_type == tmedia_qos_stype_none) {
+ tmedia_qos_tline_t* tline = tmedia_qos_tline_from_sdp(M);
+ if (tline) {
+ qos_type = tline->type;
+ TSK_OBJECT_SAFE_FREE(tline);
+ }
+ }
+ }
+
+ if (!found /*&& (self->sdp.lo == tsk_null)*/){
+ /* Session not supported and we are not the initial offerer ==> add ghost session */
+ /*
+ An offered stream MAY be rejected in the answer, for any reason. If
+ a stream is rejected, the offerer and answerer MUST NOT generate
+ media (or RTCP packets) for that stream. To reject an offered
+ stream, the port number in the corresponding stream in the answer
+ MUST be set to zero. Any media formats listed are ignored. AT LEAST
+ ONE MUST BE PRESENT, AS SPECIFIED BY SDP.
+ */
+ tmedia_session_ghost_t* ghost;
+ if ((ghost = (tmedia_session_ghost_t*)tmedia_session_create(tmedia_ghost))){
+ tsk_strupdate(&ghost->media, M->media); /* copy media */
+ tsk_strupdate(&ghost->proto, M->proto); /* copy proto */
+ if (!TSK_LIST_IS_EMPTY(M->FMTs)){
+ tsk_strupdate(&ghost->first_format, ((const tsdp_fmt_t*)TSK_LIST_FIRST_DATA(M->FMTs))->value); /* copy format */
+ }
+ tsk_list_push_back_data(self->sessions, (void**)&ghost);
+ }
+ else {
+ TSK_DEBUG_ERROR("Failed to create ghost session");
+ continue;
+ }
+ }
+ }
+
+end_of_sessions_update:
+
+ /* update QoS type */
+ if (!self->offerer && (qos_type != tmedia_qos_stype_none)){
+ self->qos.type = qos_type;
+ }
+
+ /* signal that ro has changed (will be used to update lo) unless there was no ro_sdp */
+ self->ro_changed = (had_ro_sdp && (__flags_sum((const tsk_bool_t*)&is_ro_hold_resume_changed, m_lines_count) || __flags_sum((const tsk_bool_t*)&is_ro_network_info_changed, m_lines_count) || is_ro_media_lines_changed || __flags_sum((const tsk_bool_t*)&is_ro_codecs_changed, m_lines_count) /*|| is_media_type_changed || is_new_mediatype_striped*/));
+
+ /* update "provisional" info */
+ self->ro_provisional = ((ro_type & tmedia_ro_type_provisional) == tmedia_ro_type_provisional);
+
+ if (self->ro_changed) {
+ /* update local offer before restarting the session manager otherwise neg_codecs won't match if new codecs
+ have been added or removed. No need to load sessions again. */
+ (_tmedia_session_mgr_get_lo(self, kSkipSessionLoadTrue, kForceUpdateLOFalse));
+ }
+ /* manager was started and we stopped it in order to reconfigure it (codecs, network, ....)
+ * When ICE is active ("is_ice_active" = yes), the media session will be explicitly restarted when conncheck succeed or fail.
+ */
+ for (index = 0; index < m_lines_count; ++index) {
+ if (stopped_to_reconf[index] && !is_ice_enabled[index]) {
+ if ((ret = _tmedia_session_mgr_start(self, (int)index))) {
+ TSK_DEBUG_ERROR("Failed to re-start session at index = %d", (int)index);
+ goto bail;
+ }
+ }
+ }
+
+ // will send [488 Not Acceptable] / [BYE] if no active session
+ ret = (self->ro_changed && active_sessions_count <= 0) ? -0xFF : 0;
+
+bail:
+ TSK_OBJECT_SAFE_FREE(list_tmp_sessions);
+
+ tsk_safeobj_unlock(self);
+ tsk_list_unlock(self->sessions);
+ return ret;
+}
+
+const tsdp_message_t* tmedia_session_mgr_get_ro(tmedia_session_mgr_t* self)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+ return self->sdp.ro;
+}
+
+tsk_bool_t tmedia_session_mgr_is_new_ro(tmedia_session_mgr_t* self, const tsdp_message_t* sdp)
+{
+ tsk_bool_t is_new = tsk_true;
+ const tsdp_header_O_t* O;
+
+ if (!self || !sdp){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(self);
+
+ if ((O = (const tsdp_header_O_t*)tsdp_message_get_header(sdp, tsdp_htype_O))) {
+ is_new = (self->sdp.ro_ver != (int32_t)O->sess_version);
+ }
+ else {
+ TSK_DEBUG_ERROR("o= line is missing");
+ }
+
+ tsk_safeobj_unlock(self);
+ return is_new;
+}
+
+/**@ingroup tmedia_session_group
+* Holds the session as per 3GPP TS 34.610
+* @param self the session manager managing the session to hold.
+* @param type the type of the sessions to hold (you can combine several medias. e.g. audio|video|msrp).
+* @retval Zero if succeed and non zero error code otherwise.
+* @sa @ref tmedia_session_mgr_resume
+*/
+int tmedia_session_mgr_hold(tmedia_session_mgr_t* self, tmedia_type_t type)
+{
+ const tsk_list_item_t* item;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_list_foreach(item, self->sessions){
+ tmedia_session_t* session = TMEDIA_SESSION(item->data);
+ if (((session->type & type) == session->type) && session->M.lo){
+ if (tsdp_header_M_hold(session->M.lo, tsk_true) == 0){
+ self->state_changed = tsk_true;
+ session->lo_held = tsk_true;
+ }
+ }
+ }
+ return 0;
+}
+
+/**@ingroup tmedia_session_group
+* Indicates whether the specified medias are held or not.
+* @param self the session manager
+* @param type the type of the medias to check (you can combine several medias. e.g. audio|video|msrp)
+* @param local whether to check local or remote medias
+*/
+tsk_bool_t tmedia_session_mgr_is_held(tmedia_session_mgr_t* self, tmedia_type_t type, tsk_bool_t local)
+{
+ const tsk_list_item_t* item;
+ tsk_bool_t have_these_sessions = tsk_false;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_false;
+ }
+
+ tsk_list_foreach(item, self->sessions){
+ tmedia_session_t* session = TMEDIA_SESSION(item->data);
+ if ((session->type & type) == session->type){
+ if (local && session->M.lo){
+ have_these_sessions = tsk_true;
+ if (!tsdp_header_M_is_held(session->M.lo, tsk_true)){
+ return tsk_false;
+ }
+ }
+ else if (!local && session->M.ro){
+ have_these_sessions = tsk_true;
+ if (!tsdp_header_M_is_held(session->M.ro, tsk_false)){
+ return tsk_false;
+ }
+ }
+ }
+ }
+ /* none is held */
+ return have_these_sessions ? tsk_true : tsk_false;
+}
+
+/**@ingroup tmedia_session_group
+* Resumes the session as per 3GPP TS 34.610. Should be previously held
+* by using @ref tmedia_session_mgr_hold.
+* @param self the session manager managing the session to resume.
+* @param type the type of the sessions to resume (you can combine several medias. e.g. audio|video|msrp).
+* @retval Zero if succeed and non zero error code otherwise.
+* @sa @ref tmedia_session_mgr_hold
+*/
+int tmedia_session_mgr_resume(tmedia_session_mgr_t* self, tmedia_type_t type, tsk_bool_t local)
+{
+ const tsk_list_item_t* item;
+ int ret = 0;
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_list_foreach(item, self->sessions){
+ tmedia_session_t* session = TMEDIA_SESSION(item->data);
+ if (((session->type & type) == session->type) && session->M.lo){
+ if ((ret = tsdp_header_M_resume(session->M.lo, local)) == 0){
+ self->state_changed = tsk_true;
+ if (local){
+ session->lo_held = tsk_false;
+ }
+ else{
+ session->ro_held = tsk_false;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+/**@ingroup tmedia_session_group
+* Adds new medias to the manager. A media will only be added if it is missing
+* or previously removed (slot with port equal to zero).
+* @param self The session manager
+* @param The types of the medias to add (ou can combine several medias. e.g. audio|video|msrp)
+* @retval Zero if succeed and non zero error code otherwise.
+*/
+int tmedia_session_mgr_add_media(tmedia_session_mgr_t* self, tmedia_type_t type)
+{
+ tsk_size_t i = 0;
+ tmedia_session_t* session;
+ const tmedia_session_plugin_def_t* plugin;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* for each registered plugin match with the supplied type */
+ while ((i < TMED_SESSION_MAX_PLUGINS) && (plugin = __tmedia_session_plugins[i++])){
+ if ((plugin->type & type) == plugin->type){
+ /* check whether we already support this media */
+ if ((session = (tmedia_session_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &plugin->type)) && session->plugin){
+ if (session->prepared){
+ TSK_DEBUG_WARN("[%s] already active", plugin->media);
+ }
+ else{
+ /* exist but unprepared(port=0) */
+ _tmedia_session_prepare(session);
+ if (self->started && session->plugin->start){
+ session->plugin->start(session);
+ }
+ self->state_changed = tsk_true;
+ }
+ }
+ else{
+ /* session not supported */
+ self->state_changed = tsk_true;
+ if ((session = tmedia_session_create(plugin->type))){
+ if (self->started && session->plugin->start){
+ session->plugin->start(session);
+ }
+ tsk_list_push_back_data(self->sessions, (void**)(&session));
+ self->state_changed = tsk_true;
+ }
+ }
+ }
+ }
+
+ return self->state_changed ? 0 : -2;
+}
+
+/**@ingroup tmedia_session_group
+* Removes medias from the manager. This action will stop the media and sets it's port value to zero (up to the session).
+* @param self The session manager
+* @param The types of the medias to remove (ou can combine several medias. e.g. audio|video|msrp)
+* @retval Zero if succeed and non zero error code otherwise.
+*/
+int tmedia_session_mgr_remove_media(tmedia_session_mgr_t* self, tmedia_type_t type)
+{
+ const tsk_list_item_t* item;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_list_foreach(item, self->sessions){
+ tmedia_session_t* session = TMEDIA_SESSION(item->data);
+ if (((session->type & type) == session->type) && session->plugin->stop){
+ if (!session->plugin->stop(session)){
+ self->state_changed = tsk_true;
+ }
+ }
+ }
+ return 0;
+}
+
+/**@ingroup tmedia_session_group
+* Sets QoS type and strength
+* @param self The session manager
+* @param qos_type The QoS type
+* @param qos_strength The QoS strength
+* @retval Zero if succeed and non-zero error code otherwise
+*/
+int tmedia_session_mgr_set_qos(tmedia_session_mgr_t* self, tmedia_qos_stype_t qos_type, tmedia_qos_strength_t qos_strength)
+{
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ self->qos.type = qos_type;
+ self->qos.strength = qos_strength;
+ return 0;
+}
+
+/**@ingroup tmedia_session_group
+* Indicates whether all preconditions are met
+* @param self The session manager
+* @retval @a tsk_true if all preconditions have been met and @a tsk_false otherwise
+*/
+tsk_bool_t tmedia_session_mgr_canresume(tmedia_session_mgr_t* self)
+{
+ const tsk_list_item_t* item;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_true;
+ }
+
+ tsk_list_foreach(item, self->sessions){
+ tmedia_session_t* session = TMEDIA_SESSION(item->data);
+ if (session && session->qos && !tmedia_qos_tline_canresume(session->qos)){
+ return tsk_false;
+ }
+ }
+ return tsk_true;
+}
+
+
+/**@ingroup tmedia_session_group
+* Checks whether the manager holds at least one valid session (media port <> 0)
+*/
+tsk_bool_t tmedia_session_mgr_has_active_session(tmedia_session_mgr_t* self)
+{
+ const tsk_list_item_t* item;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_false;
+ }
+
+ tsk_list_foreach(item, self->sessions){
+ tmedia_session_t* session = TMEDIA_SESSION(item->data);
+ if (session && session->M.lo && session->M.lo->port){
+ return tsk_true;
+ }
+ }
+ return tsk_false;
+}
+
+int tmedia_session_mgr_send_dtmf(tmedia_session_mgr_t* self, uint8_t event)
+{
+ tmedia_session_audio_t* session;
+ static const tmedia_type_t audio_type = tmedia_audio;
+ int ret = -3;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ session = (tmedia_session_audio_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &audio_type);
+ if (session){
+ session = tsk_object_ref(session);
+ ret = tmedia_session_audio_send_dtmf(TMEDIA_SESSION_AUDIO(session), event);
+ TSK_OBJECT_SAFE_FREE(session);
+ }
+ else{
+ TSK_DEBUG_ERROR("No audio session associated to this manager");
+ }
+
+ return ret;
+}
+
+int tmedia_session_mgr_set_t140_ondata_cbfn(tmedia_session_mgr_t* self, const void* context, tmedia_session_t140_ondata_cb_f func)
+{
+ tmedia_session_t* session;
+ int ret = -1;
+ if ((session = tmedia_session_mgr_find(self, tmedia_t140))){
+ ret = tmedia_session_t140_set_ondata_cbfn(session, context, func);
+ TSK_OBJECT_SAFE_FREE(session);
+ }
+ return ret;
+}
+
+int tmedia_session_mgr_send_t140_data(tmedia_session_mgr_t* self, enum tmedia_t140_data_type_e data_type, const void* data_ptr, unsigned data_size)
+{
+ tmedia_session_t* session;
+ int ret = -1;
+ if ((session = tmedia_session_mgr_find(self, tmedia_t140))){
+ ret = tmedia_session_t140_send_data(session, data_type, data_ptr, data_size);
+ TSK_OBJECT_SAFE_FREE(session);
+ }
+ return ret;
+}
+
+int tmedia_session_mgr_set_onrtcp_cbfn(tmedia_session_mgr_t* self, tmedia_type_t media_type, const void* context, tmedia_session_rtcp_onevent_cb_f fun)
+{
+ tmedia_session_t* session;
+ tsk_list_item_t *item;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invlid parameter");
+ return -1;
+ }
+
+ tsk_list_lock(self->sessions);
+ tsk_list_foreach(item, self->sessions){
+ if (!(session = item->data) || !(session->type & media_type)){
+ continue;
+ }
+ tmedia_session_set_onrtcp_cbfn(session, context, fun);
+ }
+ tsk_list_unlock(self->sessions);
+
+ return 0;
+}
+
+int tmedia_session_mgr_send_rtcp_event(tmedia_session_mgr_t* self, tmedia_type_t media_type, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media)
+{
+ tmedia_session_t* session;
+ tsk_list_item_t *item;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invlid parameter");
+ return -1;
+ }
+
+ tsk_list_lock(self->sessions);
+ tsk_list_foreach(item, self->sessions){
+ if (!(session = item->data) || !(session->type & media_type)){
+ continue;
+ }
+ tmedia_session_send_rtcp_event(session, event_type, ssrc_media);
+ }
+ tsk_list_unlock(self->sessions);
+
+ return 0;
+}
+
+int tmedia_session_mgr_recv_rtcp_event(tmedia_session_mgr_t* self, tmedia_type_t media_type, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media)
+{
+ static const uint64_t __fake_session_id = 0;
+ return _tmedia_session_mgr_recv_rtcp_event(self, media_type, event_type, ssrc_media, __fake_session_id);
+}
+
+int tmedia_session_mgr_recv_rtcp_event_2(tmedia_session_mgr_t* self, tmedia_rtcp_event_type_t event_type, uint64_t session_id)
+{
+ static const uint32_t __fake_ssrc_media = 0;
+ static const tmedia_type_t __fake_media_type = tmedia_none;
+ return _tmedia_session_mgr_recv_rtcp_event(self, __fake_media_type, event_type, __fake_ssrc_media, session_id);
+}
+
+int tmedia_session_mgr_send_file(tmedia_session_mgr_t* self, const char* path, ...)
+{
+ tmedia_session_msrp_t* session;
+ tmedia_type_t msrp_type = tmedia_msrp;
+ int ret = -3;
+
+ if (!self || !path){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ session = (tmedia_session_msrp_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &msrp_type);
+ if (session && session->send_file){
+ va_list ap;
+ va_start(ap, path);
+ session = tsk_object_ref(session);
+ ret = session->send_file(TMEDIA_SESSION_MSRP(session), path, &ap);
+ TSK_OBJECT_SAFE_FREE(session);
+ va_end(ap);
+ }
+ else{
+ TSK_DEBUG_ERROR("No MSRP session associated to this manager or session does not support file transfer");
+ }
+
+ return ret;
+}
+
+int tmedia_session_mgr_send_message(tmedia_session_mgr_t* self, const void* data, tsk_size_t size, const tmedia_params_L_t *params)
+{
+ tmedia_session_msrp_t* session;
+ tmedia_type_t msrp_type = tmedia_msrp;
+ int ret = -3;
+
+ if (!self || !size || !data){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ session = (tmedia_session_msrp_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &msrp_type);
+ if (session && session->send_message){
+ session = tsk_object_ref(session);
+ ret = session->send_message(TMEDIA_SESSION_MSRP(session), data, size, params);
+ TSK_OBJECT_SAFE_FREE(session);
+ }
+ else{
+ TSK_DEBUG_ERROR("No MSRP session associated to this manager or session does not support file transfer");
+ }
+
+ return ret;
+}
+
+int tmedia_session_mgr_set_msrp_cb(tmedia_session_mgr_t* self, const void* callback_data, tmedia_session_msrp_cb_f func)
+{
+ tmedia_session_msrp_t* session;
+ tmedia_type_t msrp_type = tmedia_msrp;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if ((session = (tmedia_session_msrp_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &msrp_type))){
+ session->callback.data = callback_data;
+ session->callback.func = func;
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("No MSRP session associated to this manager or session does not support file transfer");
+ return -2;
+ }
+}
+
+int tmedia_session_mgr_set_onerror_cbfn(tmedia_session_mgr_t* self, const void* usrdata, tmedia_session_onerror_cb_f fun)
+{
+ tmedia_session_t* session;
+ tsk_list_item_t *item;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ // save for sessions created later
+ self->onerror_cb.fun = fun;
+ self->onerror_cb.usrdata = usrdata;
+
+ tsk_list_lock(self->sessions);
+ tsk_list_foreach(item, self->sessions){
+ if (!(session = item->data)){
+ continue;
+ }
+ tmedia_session_set_onerror_cbfn(session, usrdata, fun);
+ }
+ tsk_list_unlock(self->sessions);
+
+ return 0;
+}
+
+int tmedia_session_mgr_set_rfc5168_cbfn(tmedia_session_mgr_t* self, const void* usrdata, tmedia_session_rfc5168_cb_f fun)
+{
+ tmedia_session_t* session;
+ tsk_list_item_t *item;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ // save for functions created later
+ self->rfc5168_cb.fun = fun;
+ self->rfc5168_cb.usrdata = usrdata;
+
+ tsk_list_lock(self->sessions);
+ tsk_list_foreach(item, self->sessions){
+ if (!(session = item->data)){
+ continue;
+ }
+ tmedia_session_set_rfc5168_cbfn(session, usrdata, fun);
+ }
+ tsk_list_unlock(self->sessions);
+
+ return 0;
+}
+
+int tmedia_session_mgr_set_bfcp_cbfn(tmedia_session_mgr_t* self, const void* usrdata, tmedia_session_bfcp_cb_f fun)
+{
+ tmedia_session_t* session;
+ tsk_list_item_t *item;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_list_lock(self->sessions);
+ tsk_list_foreach(item, self->sessions) {
+ if (!(session = item->data)) {
+ continue;
+ }
+ tmedia_session_set_bfcp_cbfn(session, usrdata, fun);
+ }
+ tsk_list_unlock(self->sessions);
+
+ return 0;
+}
+
+int tmedia_session_mgr_lo_apply_changes(tmedia_session_mgr_t* self)
+{
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ _tmedia_session_mgr_get_lo(self, kSkipSessionLoadTrue, kForceUpdateLOTrue);
+ return 0;
+}
+
+static int _tmedia_session_mgr_recv_rtcp_event(tmedia_session_mgr_t* self, tmedia_type_t media_type, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media, uint64_t session_id)
+{
+ tmedia_session_t* session;
+ tsk_list_item_t *item;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invlid parameter");
+ return -1;
+ }
+
+ tsk_list_lock(self->sessions);
+ tsk_list_foreach(item, self->sessions) {
+ if (!(session = item->data) || !((session->type & media_type) || (session->id == session_id))) {
+ continue;
+ }
+ tmedia_session_recv_rtcp_event(session, event_type, ssrc_media);
+ }
+ tsk_list_unlock(self->sessions);
+
+ return 0;
+}
+
+/** internal function used to load sessions */
+static int _tmedia_session_mgr_load_sessions(tmedia_session_mgr_t* self)
+{
+ tsk_size_t i = 0;
+ tmedia_session_t* session;
+ const tmedia_session_plugin_def_t* plugin;
+
+ tsk_list_lock(self->sessions);
+
+#define has_media(media_type) (tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &(media_type)))
+
+ if (TSK_LIST_IS_EMPTY(self->sessions) || self->mediaType_changed) {
+ //static tmedia_type_t __ghost_media_type = tmedia_ghost;
+ //static tmedia_type_t __none_media_type = tmedia_none;
+ // Remove ghost sessions. Up to the
+ //while (tsk_list_remove_item_by_pred(self->sessions, __pred_find_session_by_type, &__ghost_media_type)) ;
+ //while (tsk_list_remove_item_by_pred(self->sessions, __pred_find_session_by_type, &__none_media_type)) ;
+ /* for each registered plugin create a session instance */
+ while ((i < TMED_SESSION_MAX_PLUGINS) && (plugin = __tmedia_session_plugins[i++])) {
+ if ((plugin->type & self->type) == plugin->type) { /* media_type *IS* enabled */
+ if (has_media(plugin->type)) {
+ // we already have a matching media session -> enable it if not already done
+ _tmedia_session_mgr_enable_session_with_type(self, plugin->type);
+ }
+ else {
+ // we don't have a matching media session yet
+ if ((session = tmedia_session_create(plugin->type))) {
+ /* do not call "tmedia_session_mgr_set()" here to avoid applying parms before the creation of all session */
+
+ /* set other default values */
+
+ /* push session */
+ tsk_list_push_back_data(self->sessions, (void**)(&session));
+ }
+ }
+ }
+ else { /* media_type *IS NOT* enabled */
+ if (has_media(plugin->type)) {
+ // do not remove to make sure media indexes match -> see rfc 3264 section 8
+ // tsk_list_remove_item_by_pred(self->sessions, __pred_find_session_by_type, &(plugin->type));
+ _tmedia_session_mgr_disable_session_with_type(self, plugin->type);
+ }
+ }
+ }
+ /* set default values and apply params*/
+ tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_POBJECT(tmedia_audio, "ice-ctx", self->ice.ctx_audio),
+ TMEDIA_SESSION_SET_POBJECT(tmedia_video, "ice-ctx", self->ice.ctx_video),
+ TMEDIA_SESSION_SET_POBJECT(tmedia_bfcp_video, "ice-ctx", self->ice.ctx_bfcpvid),
+
+ TMEDIA_SESSION_SET_STR(self->type, "local-ip", self->addr),
+ TMEDIA_SESSION_SET_STR(self->type, "local-ipver", self->ipv6 ? "ipv6" : "ipv4"),
+ TMEDIA_SESSION_SET_INT32(self->type, "bandwidth-level", self->bl),
+ TMEDIA_SESSION_SET_NULL());
+ // set callback functions
+ tmedia_session_mgr_set_onerror_cbfn(self, self->onerror_cb.usrdata, self->onerror_cb.fun);
+ tmedia_session_mgr_set_rfc5168_cbfn(self, self->rfc5168_cb.usrdata, self->rfc5168_cb.fun);
+ }
+#undef has_media
+
+ tsk_list_unlock(self->sessions);
+ return 0;
+}
+
+//!\ not thread-safe
+static const tmedia_session_t* _tmedia_session_mgr_find_session_at_index(const tmedia_sessions_L_t* list, tsk_size_t index)
+{
+ const tsk_list_item_t *item;
+ tsk_size_t u = 0;
+ tsk_list_foreach(item, list) {
+ if (u++ == index) {
+ return (const tmedia_session_t*)item->data;
+ }
+ }
+ return tsk_null;
+}
+
+/* internal function */
+static int _tmedia_session_mgr_disable_or_enable_session_with_type(tmedia_session_mgr_t* self, tmedia_type_t media_type, tsk_bool_t enable)
+{
+ tsk_list_item_t *item;
+ tmedia_session_t *session;
+ tsk_list_lock(self->sessions);
+
+ tsk_list_foreach(item, self->sessions) {
+ if ((session = (tmedia_session_t*)item->data) && session->plugin && session->plugin->type == media_type) {
+ if (enable) {
+ if (session->M.lo && !session->M.lo->port) {
+ TSK_OBJECT_SAFE_FREE(session->M.ro);
+ TSK_OBJECT_SAFE_FREE(session->M.lo);
+ session->prepared = tsk_false;
+ }
+ }
+ else {
+ if (session->plugin->stop) {
+ session->plugin->stop(session);
+ }
+ if (session->M.lo) {
+ session->M.lo->port = 0;
+ }
+ session->prepared = tsk_false;
+ }
+ }
+ }
+
+ tsk_list_unlock(self->sessions);
+ return 0;
+}
+
+
+/* internal function */
+static int _tmedia_session_mgr_clear_sessions(tmedia_session_mgr_t* self)
+{
+ if (self && self->sessions){
+ tsk_list_clear_items(self->sessions);
+ }
+ return 0;
+}
+
+/* internal function */
+// force_update_lo: means use same sdp version number but update fields
+static const tsdp_message_t* _tmedia_session_mgr_get_lo(tmedia_session_mgr_t* self, tsk_bool_t skip_session_load, tsk_bool_t force_update_lo)
+{
+ const tsk_list_item_t* item;
+ const tmedia_session_t* ms;
+ const tsdp_header_M_t* m;
+ const tsdp_message_t* ret = tsk_null;
+ uint32_t new_ver_num;
+ tsk_bool_t inc_ver = tsk_false;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ tsk_safeobj_lock(self);
+
+ /* prepare the session manager if not already done (create all sessions) */
+ if (TSK_LIST_IS_EMPTY(self->sessions)){
+ if (_tmedia_session_mgr_load_sessions(self)){
+ TSK_DEBUG_ERROR("Failed to prepare the session manager");
+ goto bail;
+ }
+ }
+
+ /* creates local sdp if not already done or update it's value (because of set_ro())*/
+ if ((self->ro_changed || self->state_changed || self->mediaType_changed) && self->sdp.lo) {
+ // delete current lo
+ TSK_OBJECT_SAFE_FREE(self->sdp.lo);
+ if (self->mediaType_changed && !skip_session_load) {
+ // reload session with new medias and keep the old one
+ _tmedia_session_mgr_load_sessions(self);
+ }
+ self->ro_changed = tsk_false;
+ self->ro_provisional = tsk_false;
+ self->state_changed = tsk_false;
+ self->mediaType_changed = tsk_false;
+ }
+ if (force_update_lo && self->sdp.lo) {
+ const tsdp_header_O_t* O;
+
+ if ((O = (const tsdp_header_O_t*)tsdp_message_get_header(self->sdp.lo, tsdp_htype_O))) {
+ tsk_list_item_t *item;
+ tmedia_session_t *session;
+
+ new_ver_num = O->sess_version;
+ tsk_list_lock(self->sessions);
+ tsk_list_foreach(item, self->sessions) {
+ if ((session = (tmedia_session_t*)item->data)) {
+ TSK_OBJECT_SAFE_FREE(session->M.lo);
+ }
+ }
+ tsk_list_unlock(self->sessions);
+ TSK_OBJECT_SAFE_FREE(self->sdp.lo);
+ }
+ else {
+ new_ver_num = (self->sdp.lo_ver + 1);
+ inc_ver = tsk_true;
+ }
+ }
+ else {
+ new_ver_num = (self->sdp.lo_ver + 1);
+ inc_ver = tsk_true;
+ }
+
+ if (self->sdp.lo) {
+ ret = self->sdp.lo;
+ goto bail;
+ }
+ else {
+ if ((self->sdp.lo = tsdp_message_create_empty(self->public_addr ? self->public_addr : self->addr, self->ipv6, new_ver_num))) {
+ /* Set connection "c=" */
+ tsdp_message_add_headers(self->sdp.lo,
+ TSDP_HEADER_C_VA_ARGS("IN", self->ipv6 ? "IP6" : "IP4", self->public_addr ? self->public_addr : self->addr),
+ tsk_null);
+ if (inc_ver) {
+ ++self->sdp.lo_ver;
+ }
+ }
+ else {
+ TSK_DEBUG_ERROR("Failed to create empty SDP message");
+ goto bail;
+ }
+ }
+
+ /* pass complete local sdp to the sessions to allow them to use session-level attributes */
+ tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_POBJECT(self->type, "local-sdp-message", self->sdp.lo),
+ TMEDIA_SESSION_SET_NULL());
+
+ /* gets each "m=" line from the sessions and add them to the local sdp */
+ tsk_list_foreach(item, self->sessions){
+ if (!(ms = item->data) || !ms->plugin){
+ TSK_DEBUG_ERROR("Invalid session");
+ continue;
+ }
+ if ((self->type & ms->plugin->type) || ms->plugin->type == tmedia_ghost) {
+ /* prepare the media session */
+ if (!ms->prepared && (_tmedia_session_prepare(TMEDIA_SESSION(ms)))){
+ TSK_DEBUG_ERROR("Failed to prepare session"); /* should never happen */
+ continue;
+ }
+
+ /* Add QoS lines to our local media */
+ if ((self->qos.type != tmedia_qos_stype_none) && !TMEDIA_SESSION(ms)->qos){
+ TMEDIA_SESSION(ms)->qos = tmedia_qos_tline_create(self->qos.type, self->qos.strength);
+ }
+
+ /* add "m=" line from the session to the local sdp */
+ if ((m = tmedia_session_get_lo(TMEDIA_SESSION(ms)))) {
+ tsdp_message_add_header(self->sdp.lo, TSDP_HEADER(m));
+ }
+ else {
+ TSK_DEBUG_ERROR("Failed to get m= line for [%s] media", ms->plugin->media);
+ }
+ }
+ else if (ms->M.lo) {
+ // media not enabled -> add sdp with port zero
+ tsdp_message_add_header(self->sdp.lo, TSDP_HEADER(ms->M.lo));
+ }
+ }
+
+ self->type = self->sdp.lo ? tmedia_type_from_sdp(self->sdp.lo) : tmedia_none;
+ ret = self->sdp.lo;
+
+bail:
+ tsk_safeobj_unlock(self);
+
+ return ret;
+}
+
+static int _tmedia_session_mgr_start(tmedia_session_mgr_t* self, int session_index)
+{
+ int ret = 0, index = 0;
+ tsk_list_item_t* item;
+ tmedia_session_t* session;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(self);
+
+ tsk_list_foreach(item, self->sessions) {
+ if (session_index == kSessionIndexAll || index++ == session_index) {
+ if (!(session = item->data) || !session->plugin || !session->plugin->start) {
+ TSK_DEBUG_ERROR("Invalid session");
+ ret = -2;
+ goto bail;
+ }
+ if (!session->M.lo || !session->M.lo->port) {
+ continue;
+ }
+ if ((ret = session->plugin->start(session))) {
+ TSK_DEBUG_ERROR("Failed to start %s session", session->plugin->media);
+ continue;
+ }
+ }
+ }
+ if (session_index == kSessionIndexAll) {
+ self->started = tsk_true;
+ }
+
+bail:
+ tsk_safeobj_unlock(self);
+ return ret;
+}
+
+static int _tmedia_session_mgr_stop(tmedia_session_mgr_t* self, int session_index)
+{
+ int ret = 0, index = 0;
+ tsk_list_item_t* item;
+ tmedia_session_t* session;
+
+ TSK_DEBUG_INFO("tmedia_session_mgr_stop()");
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_safeobj_lock(self);
+
+ tsk_list_foreach(item, self->sessions) {
+ if (session_index == kSessionIndexAll || index++ == session_index) {
+ if (!(session = item->data) || !session->plugin || !session->plugin->stop) {
+ TSK_DEBUG_ERROR("Invalid session");
+ ret = -2;
+ goto bail;
+ }
+ if ((ret = session->plugin->stop(session))) {
+ TSK_DEBUG_ERROR("Failed to stop session");
+ continue;
+ }
+ session->prepared = tsk_false;
+ }
+ }
+ if (session_index == kSessionIndexAll) {
+ self->started = tsk_false;
+ }
+
+bail:
+ tsk_safeobj_unlock(self);
+ return ret;
+}
+
+/* internal function */
+static int _tmedia_session_mgr_apply_params(tmedia_session_mgr_t* self)
+{
+ tsk_list_item_t *it1, *it2;
+ tmedia_param_t* param;
+ tmedia_session_t* session;
+
+ if (!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* If no parameters ==> do nothing (not error) */
+ if (TSK_LIST_IS_EMPTY(self->params)){
+ return 0;
+ }
+
+ tsk_list_lock(self->params);
+
+ tsk_list_foreach(it1, self->params){
+ if (!(param = it1->data)){
+ continue;
+ }
+
+ /* For us */
+ if (param->plugin_type == tmedia_ppt_manager){
+ continue;
+ }
+
+ /* For the session (or consumer or producer or codec) */
+ tsk_list_foreach(it2, self->sessions){
+ if (!(session = it2->data) || !session->plugin){
+ continue;
+ }
+ if (session->plugin->set && (session->type & param->media_type) == session->type){
+ session->plugin->set(session, param);
+ }
+ }
+ }
+
+ /* Clean up params */
+ tsk_list_clear_items(self->params);
+
+ tsk_list_unlock(self->params);
+
+ return 0;
+}
+
+//=================================================================================================
+// Media Session Manager object definition
+//
+static tsk_object_t* tmedia_session_mgr_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_session_mgr_t *mgr = self;
+ if (mgr){
+ mgr->sessions = tsk_list_create();
+
+ mgr->sdp.lo_ver = TSDP_HEADER_O_SESS_VERSION_DEFAULT;
+ mgr->sdp.ro_ver = -1;
+
+ mgr->qos.type = tmedia_qos_stype_none;
+ mgr->qos.strength = tmedia_qos_strength_optional;
+ mgr->bl = tmedia_defaults_get_bl();
+
+ tsk_safeobj_init(mgr);
+ }
+ return self;
+}
+
+static tsk_object_t* tmedia_session_mgr_dtor(tsk_object_t * self)
+{
+ tmedia_session_mgr_t *mgr = self;
+ if (mgr){
+ TSK_OBJECT_SAFE_FREE(mgr->sessions);
+
+ TSK_OBJECT_SAFE_FREE(mgr->sdp.lo);
+ TSK_OBJECT_SAFE_FREE(mgr->sdp.ro);
+
+ TSK_OBJECT_SAFE_FREE(mgr->params);
+
+ TSK_OBJECT_SAFE_FREE(mgr->natt_ctx);
+ TSK_FREE(mgr->public_addr);
+
+ TSK_OBJECT_SAFE_FREE(mgr->ice.ctx_audio);
+ TSK_OBJECT_SAFE_FREE(mgr->ice.ctx_video);
+ TSK_OBJECT_SAFE_FREE(mgr->ice.ctx_bfcpvid);
+
+ TSK_FREE(mgr->addr);
+
+ tsk_safeobj_deinit(mgr);
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tmedia_session_mgr_def_s =
+{
+ sizeof(tmedia_session_mgr_t),
+ tmedia_session_mgr_ctor,
+ tmedia_session_mgr_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tmedia_session_mgr_def_t = &tmedia_session_mgr_def_s;
+
diff --git a/tinyMEDIA/src/tmedia_session_dummy.c b/tinyMEDIA/src/tmedia_session_dummy.c
new file mode 100644
index 0000000..dfd141e
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_session_dummy.c
@@ -0,0 +1,490 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_session_dummy.c
+ * @brief Dummy sessions used for test only.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tinymedia/tmedia_session_dummy.h"
+
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+/* ============ Audio Session ================= */
+
+int tmedia_session_daudio_set(tmedia_session_t* self, const tmedia_param_t* param)
+{
+ tmedia_session_daudio_t* daudio;
+
+ daudio = (tmedia_session_daudio_t*)self;
+
+ return 0;
+}
+
+int tmedia_session_daudio_get(tmedia_session_t* self, tmedia_param_t* param)
+{
+ return 0;
+}
+
+int tmedia_session_daudio_prepare(tmedia_session_t* self)
+{
+ tmedia_session_daudio_t* daudio;
+
+ daudio = (tmedia_session_daudio_t*)self;
+
+ /* set local port */
+ daudio->local_port = rand() ^ rand();
+
+ return 0;
+}
+
+int tmedia_session_daudio_start(tmedia_session_t* self)
+{
+ return 0;
+}
+
+int tmedia_session_daudio_stop(tmedia_session_t* self)
+{
+ tmedia_session_daudio_t* daudio;
+
+ daudio = (tmedia_session_daudio_t*)self;
+
+ /* very important */
+ daudio->local_port = 0;
+
+ return 0;
+}
+
+int tmedia_session_daudio_send_dtmf(tmedia_session_t* self, uint8_t event)
+{
+ return 0;
+}
+
+int tmedia_session_daudio_pause(tmedia_session_t* self)
+{
+ return 0;
+}
+
+const tsdp_header_M_t* tmedia_session_daudio_get_lo(tmedia_session_t* self)
+{
+ tmedia_session_daudio_t* daudio;
+ tsk_bool_t changed = tsk_false;
+
+ if(!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ daudio = (tmedia_session_daudio_t*)self;
+
+ if(self->ro_changed && self->M.lo){
+ /* Codecs */
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "fmtp");
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "rtpmap");
+ tsk_list_clear_items(self->M.lo->FMTs);
+
+ /* QoS */
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "curr");
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "des");
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "conf");
+ }
+
+ changed = (self->ro_changed || !self->M.lo);
+
+ if(!self->M.lo && !(self->M.lo = tsdp_header_M_create(self->plugin->media, daudio->local_port, "RTP/AVP"))){
+ TSK_DEBUG_ERROR("Failed to create lo");
+ return tsk_null;
+ }
+
+ if(changed){
+ /* from codecs to sdp */
+ tmedia_codec_to_sdp(self->neg_codecs ? self->neg_codecs : self->codecs, self->M.lo);
+ /* QoS */
+ if(self->qos){
+ tmedia_qos_tline_t* ro_tline;
+ if(self->M.ro && (ro_tline = tmedia_qos_tline_from_sdp(self->M.ro))){
+ tmedia_qos_tline_set_ro(self->qos, ro_tline);
+ TSK_OBJECT_SAFE_FREE(ro_tline);
+ }
+ tmedia_qos_tline_to_sdp(self->qos, self->M.lo);
+ }
+ }
+
+
+ return self->M.lo;
+}
+
+int tmedia_session_daudio_set_ro(tmedia_session_t* self, const tsdp_header_M_t* m)
+{
+ tmedia_codecs_L_t* neg_codecs;
+
+ if((neg_codecs = tmedia_session_match_codec(self, m))){
+ /* update negociated codecs */
+ TSK_OBJECT_SAFE_FREE(self->neg_codecs);
+ self->neg_codecs = neg_codecs;
+ /* update remote offer */
+ TSK_OBJECT_SAFE_FREE(self->M.ro);
+ self->M.ro = tsk_object_ref((void*)m);
+
+ return 0;
+ }
+ return -1;
+}
+
+/* ============ Video Session ================= */
+
+int tmedia_session_dvideo_set(tmedia_session_t* self, const tmedia_param_t* param)
+{
+ tmedia_session_dvideo_t* dvideo;
+
+ dvideo = (tmedia_session_dvideo_t*)self;
+
+ return 0;
+}
+
+int tmedia_session_dvideo_get(tmedia_session_t* self, tmedia_param_t* param)
+{
+ return 0;
+}
+
+int tmedia_session_dvideo_prepare(tmedia_session_t* self)
+{
+ tmedia_session_dvideo_t* dvideo;
+
+ dvideo = (tmedia_session_dvideo_t*)self;
+
+ /* set local port */
+ dvideo->local_port = rand() ^ rand();
+
+ return 0;
+}
+
+int tmedia_session_dvideo_start(tmedia_session_t* self)
+{
+ return -1;
+}
+
+int tmedia_session_dvideo_stop(tmedia_session_t* self)
+{
+ tmedia_session_dvideo_t* dvideo;
+
+ dvideo = (tmedia_session_dvideo_t*)self;
+
+ /* very important */
+ dvideo->local_port = 0;
+
+ return 0;
+}
+
+int tmedia_session_dvideo_pause(tmedia_session_t* self)
+{
+ return -1;
+}
+
+const tsdp_header_M_t* tmedia_session_dvideo_get_lo(tmedia_session_t* self)
+{
+ tmedia_session_dvideo_t* dvideo;
+ tsk_bool_t changed = tsk_false;
+
+ if(!self || !self->plugin){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ dvideo = (tmedia_session_dvideo_t*)self;
+
+ if(self->ro_changed && self->M.lo){
+ /* Codecs */
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "fmtp");
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "rtpmap");
+ tsk_list_clear_items(self->M.lo->FMTs);
+
+ /* QoS */
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "curr");
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "des");
+ tsdp_header_A_removeAll_by_field(self->M.lo->Attributes, "conf");
+ }
+
+ changed = (self->ro_changed || !self->M.lo);
+
+ if(!self->M.lo && !(self->M.lo = tsdp_header_M_create(self->plugin->media, dvideo->local_port, "RTP/AVP"))){
+ TSK_DEBUG_ERROR("Failed to create lo");
+ return tsk_null;
+ }
+
+ if(changed){
+ /* from codecs to sdp */
+ tmedia_codec_to_sdp(self->neg_codecs ? self->neg_codecs : self->codecs, self->M.lo);
+ /* QoS */
+ if(self->qos){
+ tmedia_qos_tline_t* ro_tline;
+ if(self->M.ro && (ro_tline = tmedia_qos_tline_from_sdp(self->M.ro))){
+ tmedia_qos_tline_set_ro(self->qos, ro_tline);
+ TSK_OBJECT_SAFE_FREE(ro_tline);
+ }
+ tmedia_qos_tline_to_sdp(self->qos, self->M.lo);
+ }
+ }
+
+ return self->M.lo;
+}
+
+int tmedia_session_dvideo_set_ro(tmedia_session_t* self, const tsdp_header_M_t* m)
+{
+ tmedia_codecs_L_t* neg_codecs;
+
+ if((neg_codecs = tmedia_session_match_codec(self, m))){
+ /* update negociated codecs */
+ TSK_OBJECT_SAFE_FREE(self->neg_codecs);
+ self->neg_codecs = neg_codecs;
+ /* update remote offer */
+ TSK_OBJECT_SAFE_FREE(self->M.ro);
+ self->M.ro = tsk_object_ref((void*)m);
+
+ return 0;
+ }
+ return -1;
+}
+
+/* ============ Msrp Session ================= */
+
+int tmedia_session_dmsrp_set(tmedia_session_t* self, const tmedia_param_t* param)
+{
+ tmedia_session_dmsrp_t* dmsrp;
+
+ dmsrp = (tmedia_session_dmsrp_t*)self;
+
+ return 0;
+}
+
+int tmedia_session_dmsrp_get(tmedia_session_t* self, tmedia_param_t* param)
+{
+ return 0;
+}
+
+int tmedia_session_dmsrp_prepare(tmedia_session_t* self)
+{
+ return 0;
+}
+
+int tmedia_session_dmsrp_start(tmedia_session_t* self)
+{
+ return 0;
+}
+
+int tmedia_session_dmsrp_stop(tmedia_session_t* self)
+{
+ return 0;
+}
+
+int tmedia_session_dmsrp_pause(tmedia_session_t* self)
+{
+ return 0;
+}
+
+const tsdp_header_M_t* tmedia_session_dmsrp_get_lo(tmedia_session_t* self)
+{
+ if(self->ro_changed){
+ TSK_OBJECT_SAFE_FREE(self->M.lo);
+ }
+
+ return tsk_null;
+}
+
+int tmedia_session_dmsrp_set_ro(tmedia_session_t* self, const tsdp_header_M_t* m)
+{
+ return -1;
+}
+
+//=================================================================================================
+// Dummy Audio session object definition
+//
+/* constructor */
+static tsk_object_t* tmedia_session_daudio_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_session_daudio_t *session = self;
+ if(session){
+ /* init base: called by tmedia_session_create() */
+ /* init self */
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* tmedia_session_daudio_dtor(tsk_object_t * self)
+{
+ tmedia_session_daudio_t *session = self;
+ if(session){
+ /* deinit base */
+ tmedia_session_deinit(self);
+ /* deinit self */
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t tmedia_session_daudio_def_s =
+{
+ sizeof(tmedia_session_daudio_t),
+ tmedia_session_daudio_ctor,
+ tmedia_session_daudio_dtor,
+ tmedia_session_cmp,
+};
+/* plugin definition*/
+static const tmedia_session_plugin_def_t tmedia_session_daudio_plugin_def_s =
+{
+ &tmedia_session_daudio_def_s,
+
+ tmedia_audio,
+ "audio",
+
+ tmedia_session_daudio_set,
+ tmedia_session_daudio_get,
+ tmedia_session_daudio_prepare,
+ tmedia_session_daudio_start,
+ tmedia_session_daudio_pause,
+ tmedia_session_daudio_stop,
+
+ /* Audio part */
+ { tsk_null },
+
+ tmedia_session_daudio_get_lo,
+ tmedia_session_daudio_set_ro
+};
+const tmedia_session_plugin_def_t *tmedia_session_daudio_plugin_def_t = &tmedia_session_daudio_plugin_def_s;
+
+
+//=================================================================================================
+// Dummy Video session object definition
+//
+/* constructor */
+static tsk_object_t* tmedia_session_dvideo_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_session_dvideo_t *session = self;
+ if(session){
+ /* init base: called by tmedia_session_create() */
+ /* init self */
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* tmedia_session_dvideo_dtor(tsk_object_t * self)
+{
+ tmedia_session_dvideo_t *session = self;
+ if(session){
+ /* deinit base */
+ tmedia_session_deinit(self);
+ /* deinit self */
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t tmedia_session_dvideo_def_s =
+{
+ sizeof(tmedia_session_dvideo_t),
+ tmedia_session_dvideo_ctor,
+ tmedia_session_dvideo_dtor,
+ tmedia_session_cmp,
+};
+/* plugin definition*/
+static const tmedia_session_plugin_def_t tmedia_session_dvideo_plugin_def_s =
+{
+ &tmedia_session_dvideo_def_s,
+
+ tmedia_video,
+ "video",
+
+ tmedia_session_dvideo_set,
+ tmedia_session_dvideo_get,
+ tmedia_session_dvideo_prepare,
+ tmedia_session_dvideo_start,
+ tmedia_session_dvideo_pause,
+ tmedia_session_dvideo_stop,
+
+ /* Audio part */
+ { tsk_null },
+
+ tmedia_session_dvideo_get_lo,
+ tmedia_session_dvideo_set_ro
+};
+const tmedia_session_plugin_def_t *tmedia_session_dvideo_plugin_def_t = &tmedia_session_dvideo_plugin_def_s;
+
+
+//=================================================================================================
+// Dummy Msrp session object definition
+//
+/* constructor */
+static tsk_object_t* tmedia_session_dmsrp_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_session_dmsrp_t *session = self;
+ if(session){
+ /* init base: called by tmedia_session_create() */
+ /* init self */
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* tmedia_session_dmsrp_dtor(tsk_object_t * self)
+{
+ tmedia_session_dmsrp_t *session = self;
+ if(session){
+ /* deinit base */
+ tmedia_session_deinit(self);
+ /* deinit self */
+
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t tmedia_session_dmsrp_def_s =
+{
+ sizeof(tmedia_session_dmsrp_t),
+ tmedia_session_dmsrp_ctor,
+ tmedia_session_dmsrp_dtor,
+ tmedia_session_cmp,
+};
+/* plugin definition*/
+static const tmedia_session_plugin_def_t tmedia_session_dmsrp_plugin_def_s =
+{
+ &tmedia_session_dmsrp_def_s,
+
+ tmedia_msrp,
+ "message",
+
+ tmedia_session_dmsrp_set,
+ tmedia_session_dmsrp_get,
+ tmedia_session_dmsrp_prepare,
+ tmedia_session_dmsrp_start,
+ tmedia_session_dmsrp_pause,
+ tmedia_session_dmsrp_stop,
+
+ /* Audio part */
+ { tsk_null },
+
+ tmedia_session_dmsrp_get_lo,
+ tmedia_session_dmsrp_set_ro
+};
+const tmedia_session_plugin_def_t *tmedia_session_dmsrp_plugin_def_t = &tmedia_session_dmsrp_plugin_def_s;
diff --git a/tinyMEDIA/src/tmedia_session_ghost.c b/tinyMEDIA/src/tmedia_session_ghost.c
new file mode 100644
index 0000000..7045e69
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_session_ghost.c
@@ -0,0 +1,154 @@
+/*
+* Copyright (C) 2010-2011 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]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 tmedia_session_ghost.c
+ * @brief Ghost session.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
+ *
+
+ */
+#include "tinymedia/tmedia_session_ghost.h"
+
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+/* ============ Ghost Session ================= */
+
+static int tmedia_session_ghost_prepare(tmedia_session_t* self)
+{
+ return 0;
+}
+
+static int tmedia_session_ghost_start(tmedia_session_t* self)
+{
+ return 0;
+}
+
+static int tmedia_session_ghost_stop(tmedia_session_t* self)
+{
+ TSK_DEBUG_INFO("tmedia_session_ghost_stop");
+ return 0;
+}
+
+static int tmedia_session_ghost_pause(tmedia_session_t* self)
+{
+ return 0;
+}
+
+static const tsdp_header_M_t* tmedia_session_ghost_get_lo(tmedia_session_t* self)
+{
+ tmedia_session_ghost_t* ghost;
+
+ ghost = (tmedia_session_ghost_t*)self;
+
+ if(self->M.lo){
+ return self->M.lo;
+ }
+ else if(!(self->M.lo = tsdp_header_M_create(ghost->media, 0, ghost->proto ? ghost->proto: "RTP/AVP"))){
+ TSK_DEBUG_ERROR("Failed to create lo");
+ return tsk_null;
+ }
+
+ // add format
+ if(!tsk_strnullORempty(ghost->first_format)){
+ tsk_string_t* fmt = tsk_string_create(ghost->first_format);
+ if(!self->M.lo->FMTs){
+ self->M.lo->FMTs = tsk_list_create();
+ }
+ tsk_list_push_back_data(self->M.lo->FMTs, (void**)&fmt);
+ TSK_OBJECT_SAFE_FREE(fmt);
+ }
+
+ return self->M.lo;
+}
+
+static int tmedia_session_ghost_set_ro(tmedia_session_t* self, const tsdp_header_M_t* m)
+{
+ return 0;
+}
+
+
+
+
+
+
+
+//=================================================================================================
+// Ghost session object definition
+//
+/* constructor */
+static tsk_object_t* tmedia_session_ghost_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_session_ghost_t *session = self;
+ if(session){
+ /* init base */
+ tmedia_session_init(TMEDIA_SESSION(session), tmedia_none);
+ /* init self */
+ }
+ return self;
+}
+/* destructor */
+static tsk_object_t* tmedia_session_ghost_dtor(tsk_object_t * self)
+{
+ tmedia_session_ghost_t *session = self;
+ if(session){
+ /* deinit base */
+ tmedia_session_deinit(TMEDIA_SESSION(session));
+ /* deinit self */
+ TSK_FREE(session->media);
+ TSK_FREE(session->proto);
+ TSK_FREE(session->first_format);
+ }
+
+ return self;
+}
+/* object definition */
+static const tsk_object_def_t tmedia_session_ghost_def_s =
+{
+ sizeof(tmedia_session_ghost_t),
+ tmedia_session_ghost_ctor,
+ tmedia_session_ghost_dtor,
+ tmedia_session_cmp,
+};
+/* plugin definition*/
+static const tmedia_session_plugin_def_t tmedia_session_ghost_plugin_def_s =
+{
+ &tmedia_session_ghost_def_s,
+
+ tmedia_ghost,
+ "ghost",
+
+ tsk_null, /* set() */
+ tsk_null, /* get() */
+ tmedia_session_ghost_prepare,
+ tmedia_session_ghost_start,
+ tmedia_session_ghost_stop,
+ tmedia_session_ghost_pause,
+
+ /* Audio part */
+ { tsk_null },
+
+ tmedia_session_ghost_get_lo,
+ tmedia_session_ghost_set_ro
+};
+const tmedia_session_plugin_def_t *tmedia_session_ghost_plugin_def_t = &tmedia_session_ghost_plugin_def_s;
diff --git a/tinyMEDIA/src/tmedia_vad.c b/tinyMEDIA/src/tmedia_vad.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_vad.c
diff --git a/tinyMEDIA/test/droid-makefile b/tinyMEDIA/test/droid-makefile
new file mode 100644
index 0000000..1a0155f
--- /dev/null
+++ b/tinyMEDIA/test/droid-makefile
@@ -0,0 +1,29 @@
+APP := test
+
+CFLAGS := $(CFLAGS_COMMON) -I../include -I../../tinySAK/src -I../../tinyNET/src -I../../tinySDP/include
+LDFLAGS := $(LDFLAGS_COMMON) -Wl,-Bsymbolic,--whole-archive -l$(PROJECT) -ltinySAK -ltinyNET -ltinySDP -Wl,--entry=main
+
+all: $(APP)
+
+OBJS += $(APP).o \
+ dummy.o
+
+$(APP): $(OBJS)
+ $(CC) $(LDFLAGS) -o $@ $^
+
+%.o: %.c
+ $(CC) -c $(INCLUDE) $(CFLAGS) $< -o $@
+
+install: $(APP)
+ $(ANDROID_SDK_ROOT)/tools/adb push $(APP) $(EXEC_DIR)/$(APP)
+ $(ANDROID_SDK_ROOT)/tools/adb shell chmod 777 $(EXEC_DIR)/$(APP)
+
+run:
+ $(ANDROID_SDK_ROOT)/tools/adb shell $(EXEC_DIR)/$(APP)
+
+#dbg:
+# $(MAKE) $(MAKEFILE) DEBUG="-g -DDEBUG"
+# $(MAKE) $(MAKEFILE) install
+
+clean:
+ @rm -f $(OBJS) $(APP) \ No newline at end of file
diff --git a/tinyMEDIA/test/dummy.c b/tinyMEDIA/test/dummy.c
new file mode 100644
index 0000000..5874de5
--- /dev/null
+++ b/tinyMEDIA/test/dummy.c
@@ -0,0 +1,173 @@
+/*
+* Copyright (C) 2009 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)yahoo.fr>
+*
+* 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 "dummy.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+int dummy_start(tmedia_t* self)
+{
+ dummy_t *dummy = DUMMY(self);
+ TSK_DEBUG_INFO("dummy_start");
+
+ return 0;
+}
+
+int dummy_pause(tmedia_t* self)
+{
+ dummy_t *dummy = DUMMY(self);
+ TSK_DEBUG_INFO("dummy_pause");
+
+ return 0;
+}
+
+int dummy_stop(tmedia_t* self)
+{
+ dummy_t *dummy = DUMMY(self);
+ TSK_DEBUG_INFO("dummy_stop");
+
+ return 0;
+}
+
+const tsdp_header_M_t* dummy_get_local_offer(tmedia_t* self, va_list *app)
+{
+ dummy_t *dummy = DUMMY(self);
+ const tsk_object_def_t* objdef;
+ tsdp_header_t* header;
+
+ TSK_DEBUG_INFO("dummy_get_local_offer");
+ while((objdef = va_arg(*app, const tsk_object_def_t*))){
+ header = tsk_object_new_2(objdef, app);
+
+ TSK_OBJECT_SAFE_FREE(header);
+ }
+
+ return tsk_null;
+}
+
+const tsdp_header_M_t* dummy_get_negotiated_offer(tmedia_t* self)
+{
+ dummy_t *dummy = DUMMY(self);
+ TSK_DEBUG_INFO("dummy_get_negotiated_offer");
+
+ return tsk_null;
+}
+
+int dummy_set_remote_offer(tmedia_t* self, const tsdp_message_t* offer)
+{
+ dummy_t *dummy = DUMMY(self);
+ TSK_DEBUG_INFO("dummy_set_remote_offer");
+
+ return 0;
+}
+
+int dummy_perform(tmedia_t* self, tmedia_action_t action, const tsk_params_L_t* params)
+{
+ dummy_t *dummy = DUMMY(self);
+
+ switch(action){
+ case tma_dummy_say_hello:
+ {
+ TSK_DEBUG_INFO("dummy_perform (hello to \"%s\")", tsk_params_get_param_value(params, "to"));
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+//========================================================
+// Dummy media object definition
+//
+static void* dummy_create(tsk_object_t *self, va_list * app)
+{
+ dummy_t *dummy = self;
+ if(dummy)
+ {
+ // Parameters MUST appear in this order
+ const char* name = va_arg(*app, const char*);
+ const char* host = va_arg(*app, const char*);
+ tnet_socket_type_t socket_type = va_arg(*app, tnet_socket_type_t);
+
+ tmedia_init(TMEDIA(dummy), name);
+
+ TMEDIA(dummy)->protocol = tsk_strdup("TCP/DUMMY");
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to create new dummy media.");
+ }
+ return self;
+}
+
+static void* dummy_destroy(tsk_object_t *self)
+{
+ dummy_t *dummy = self;
+ if(dummy){
+ tmedia_deinit(TMEDIA(dummy));
+ TSK_FREE(dummy->local_sdp);
+ TSK_FREE(dummy->remote_sdp);
+ TSK_FREE(dummy->negotiated_sdp);
+ }
+ else{
+ TSK_DEBUG_ERROR("Null dummy media.");
+ }
+
+ return self;
+}
+static int dummy_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2)
+{
+ return -1;
+}
+
+static const tsk_object_def_t dummy_def_s =
+{
+ sizeof(dummy_t),
+ dummy_create,
+ dummy_destroy,
+ dummy_cmp
+};
+
+const tsk_object_def_t *dummy_def_t = &dummy_def_s;
+
+//========================================================
+// Dummy media plugin definition
+//
+static const tmedia_plugin_def_t dummy_plugin_def_s =
+{
+ &dummy_def_s,
+ "dummy plugin",
+ "audio",
+
+ dummy_start,
+ dummy_pause,
+ dummy_stop,
+
+ dummy_get_local_offer,
+ dummy_get_negotiated_offer,
+ dummy_set_remote_offer,
+
+ dummy_perform
+};
+const tmedia_plugin_def_t *dummy_plugin_def_t = &dummy_plugin_def_s;
+
diff --git a/tinyMEDIA/test/dummy.h b/tinyMEDIA/test/dummy.h
new file mode 100644
index 0000000..a916ea6
--- /dev/null
+++ b/tinyMEDIA/test/dummy.h
@@ -0,0 +1,43 @@
+/*
+* Copyright (C) 2009 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)yahoo.fr>
+*
+* 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 TEST_MEDIA_DUMMY_H
+#define TEST_MEDIA_DUMMY_H
+
+#include "tinymedia/tmedia.h"
+
+#define DUMMY(self) ((dummy_t*)(self))
+
+typedef struct dummy_s
+{
+ TMED_DECLARE_MEDIA;
+
+ char* local_sdp;
+ char* remote_sdp;
+ char* negotiated_sdp;
+}
+dummy_t;
+
+const tsk_object_def_t *dummy_def_t;
+const tmedia_plugin_def_t *dummy_plugin_def_t;
+
+
+#endif /* TEST_MEDIA_DUMMY_H */
diff --git a/tinyMEDIA/test/test.c b/tinyMEDIA/test/test.c
new file mode 100644
index 0000000..759a96b
--- /dev/null
+++ b/tinyMEDIA/test/test.c
@@ -0,0 +1,170 @@
+/*
+* Copyright (C) 2009 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)yahoo.fr>
+*
+* 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 "tinymedia/tmedia.h"
+//#include "dummy.h"
+
+#include "tinymedia.h"
+
+#include "test_codecs.h"
+#include "test_sessions.h"
+#include "test_image_attr.h"
+#include "test_qos.h"
+#include "test_contents.h"
+
+#define RUN_TEST_LOOP 1
+
+#define RUN_TEST_ALL 0
+#define RUN_TEST_CODECS 0
+#define RUN_TEST_SESSIONS 0
+#define RUN_TEST_QOS 0
+#define RUN_TEST_IMAGEATTR 1
+#define RUN_TEST_CONTENTS 0
+
+
+static void test_register_dummy_plugins();
+static void test_register_contents_plugins();
+
+
+#ifdef _WIN32_WCE
+int _tmain(int argc, _TCHAR* argv[])
+#else
+int main()
+#endif
+{
+ /* Register dummy plugins */
+ test_register_dummy_plugins();
+ /* Register content plugins */
+ test_register_contents_plugins();
+
+ do {
+
+#if RUN_TEST_ALL || RUN_TEST_CODECS
+ test_codecs();
+#endif
+
+#if RUN_TEST_ALL || RUN_TEST_SESSIONS
+ test_sessions();
+#endif
+
+#if RUN_TEST_ALL || RUN_TEST_QOS
+ test_qos();
+#endif
+
+#if RUN_TEST_ALL || RUN_TEST_IMAGEATTR
+ test_qos_imageattr();
+#endif
+
+#if RUN_TEST_ALL || RUN_TEST_CONTENTS
+ test_contents();
+#endif
+
+ }
+ while(RUN_TEST_LOOP);
+
+ return 0;
+}
+
+
+void test_register_contents_plugins()
+{
+ tmedia_content_plugin_register("text/html", tmedia_content_dummy_plugin_def_t);
+ tmedia_content_plugin_register("text/plain", tmedia_content_dummy_plugin_def_t);
+ tmedia_content_plugin_register("message/CPIM", tmedia_content_cpim_plugin_def_t);
+}
+
+void test_register_dummy_plugins()
+{
+ int ret;
+
+ /* === Sessions === */
+ if((ret = tmedia_session_plugin_register(tmedia_session_daudio_plugin_def_t))){
+ TSK_DEBUG_ERROR("Failed to register audio plugin");
+ }
+ if((ret = tmedia_session_plugin_register(tmedia_session_dvideo_plugin_def_t))){
+ TSK_DEBUG_ERROR("Failed to register video plugin");
+ }
+ if((ret = tmedia_session_plugin_register(tmedia_session_dmsrp_plugin_def_t))){
+ TSK_DEBUG_ERROR("Failed to register msrp plugin");
+ }
+ if((ret = tmedia_session_plugin_register(tmedia_session_ghost_plugin_def_t))){
+ TSK_DEBUG_ERROR("Failed to register ghost plugin");
+ }
+
+ /* === Codecs === */
+ if((ret = tmedia_codec_plugin_register(tmedia_codec_dpcma_plugin_def_t))){
+ TSK_DEBUG_ERROR("Failed to register G.711a plugin");
+ }
+ if((ret = tmedia_codec_plugin_register(tmedia_codec_dpcmu_plugin_def_t))){
+ TSK_DEBUG_ERROR("Failed to register G.711u plugin");
+ }
+ if((ret = tmedia_codec_plugin_register(tmedia_codec_dh263_plugin_def_t))){
+ TSK_DEBUG_ERROR("Failed to register H.263-1996 plugin");
+ }
+ if((ret = tmedia_codec_plugin_register(tmedia_codec_dh264_plugin_def_t))){
+ TSK_DEBUG_ERROR("Failed to register H.264 (Base profile 10) plugin");
+ }
+}
+
+//#ifdef _WIN32_WCE
+//int _tmain(int argc, _TCHAR* argv[])
+//#else
+//int main()
+//#endif
+//{
+// while(1)
+// {
+// tmedia_t* dummy = tsk_null;
+//
+// // Register dummy media
+// tmedia_plugin_register(dummy_plugin_def_t);
+// // ...if you have another one to register
+// // ...and another
+// // ...again and again
+//
+// // Create dummy media
+// if((dummy = tmedia_factory_create("dummy plugin", "127.0.0.1", tnet_socket_type_udp_ipv4))){
+//
+// tmedia_get_local_offer(dummy,
+// TSDP_HEADER_A_VA_ARGS("file-disposition", "attachment"),
+//
+// tsk_null
+// );
+// tmedia_get_negotiated_offer(dummy);
+// tmedia_set_remote_offer(dummy, tsk_null);
+//
+// tmedia_start(dummy);
+// tmedia_pause(dummy);
+//
+// tmedia_perform(dummy, tma_dummy_say_hello,
+// TSK_PARAM_VA_ARGS("to", "doubango"),
+//
+// tsk_null);
+//
+// tmedia_stop(dummy);
+//
+// TSK_OBJECT_SAFE_FREE(dummy);
+// }
+// }
+//
+// return 0;
+//}
+
diff --git a/tinyMEDIA/test/test.vcproj b/tinyMEDIA/test/test.vcproj
new file mode 100644
index 0000000..262e3a2
--- /dev/null
+++ b/tinyMEDIA/test/test.vcproj
@@ -0,0 +1,217 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="test"
+ ProjectGUID="{6ED4F246-C3B7-4DD5-9434-3A3F69CC0AD6}"
+ 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;&quot;$(SolutionDir)\include&quot;;..\..\tinyNET\src;..\..\tinySAK\src;..\..\tinySDP\include"
+ 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)\tinyMEDIA.lib $(OutDir)\tinySDP.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"
+ WarnAsError="true"
+ 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"
+ >
+ <File
+ RelativePath=".\dummy.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="tests"
+ >
+ <File
+ RelativePath=".\test_codecs.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_contents.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_image_attr.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_qos.h"
+ >
+ </File>
+ <File
+ RelativePath=".\test_sessions.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/tinyMEDIA/test/test_codecs.h b/tinyMEDIA/test/test_codecs.h
new file mode 100644
index 0000000..865953c
--- /dev/null
+++ b/tinyMEDIA/test/test_codecs.h
@@ -0,0 +1,37 @@
+/*
+* Copyright (C) 2009 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)yahoo.fr>
+*
+* 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 _TEST_CODECS_H_
+#define _TEST_CODECS_H_
+
+void test_codecs()
+{
+ tmedia_codec_t* pcmu, *pcma;
+
+ /* creates codecs */
+ pcmu = tmedia_codec_create(TMEDIA_CODEC_FORMAT_G711u);
+ pcma = tmedia_codec_create(TMEDIA_CODEC_FORMAT_G711a);
+
+ TSK_OBJECT_SAFE_FREE(pcmu);
+ TSK_OBJECT_SAFE_FREE(pcma);
+}
+
+#endif /* _TEST_CODECS_H_ */
diff --git a/tinyMEDIA/test/test_contents.h b/tinyMEDIA/test/test_contents.h
new file mode 100644
index 0000000..fe33797
--- /dev/null
+++ b/tinyMEDIA/test/test_contents.h
@@ -0,0 +1,89 @@
+/*
+* Copyright (C) 2009 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)yahoo.fr>
+*
+* 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 _TEST_CONTENTS_H_
+#define _TEST_CONTENTS_H_
+
+static void test_content_dummy();
+static void test_content_text_plain();
+static void test_content_cpim();
+
+static void test_contents()
+{
+ test_content_dummy();
+ test_content_text_plain();
+ test_content_cpim();
+}
+
+
+static void test_content_dummy()
+{
+#define CONTENT_DUMMY_DATA "salut"
+#define CONTENT_DUMMY_TYPE "cool/ok"
+ tmedia_content_t* content = tmedia_content_parse(CONTENT_DUMMY_DATA, tsk_strlen(CONTENT_DUMMY_DATA), CONTENT_DUMMY_TYPE);
+ if(content){
+ tsk_buffer_t* data = tmedia_content_get_data(content);
+ TSK_DEBUG_INFO("content-type=%s\n\ncontent=%s", TMEDIA_CONTENT(content)->type, TSK_BUFFER_DATA(data));
+ tsk_object_unref(data);
+ }
+
+ TSK_OBJECT_SAFE_FREE(content);
+}
+
+static void test_content_text_plain()
+{
+#define CONTENT_TEXT_PLAIN_DATA "salut comment tu vas?"
+#define CONTENT_TEXT_PLAIN_TYPE "text/plain"
+ tmedia_content_t* content = tmedia_content_parse(CONTENT_TEXT_PLAIN_DATA, tsk_strlen(CONTENT_TEXT_PLAIN_DATA), CONTENT_TEXT_PLAIN_TYPE);
+ if(content){
+ tsk_buffer_t* data = tmedia_content_get_data(content);
+ TSK_DEBUG_INFO("content-type=%s\n\ncontent=%s", TMEDIA_CONTENT(content)->type, TSK_BUFFER_DATA(data));
+ tsk_object_unref(data);
+ }
+
+ TSK_OBJECT_SAFE_FREE(content);
+}
+
+static void test_content_cpim()
+{
+#define CONTENT_CPIM_DATA "To: <sip:test@doubango.org>\r\n" \
+"From: <sip:test@doubango.org>\r\n" \
+"DateTime: 2010-12-17T09:57:32.562Z\r\n" \
+"Content-Disposition: attachment; filename=\"history.xml\"; creation-date=\"2010-12-17T09:19:56.978Z\"; size=3714\r\n" \
+"\r\n" \
+"Content-Type: application/octet-stream\r\n" \
+"Content-ID: <1234567890@doubango.org>\r\n" \
+"\r\n" \
+"salut comment tu vas?\r\n"
+
+#define CONTENT_CPIM_TYPE "message/CPIM"
+ tmedia_content_t* content = tmedia_content_parse(CONTENT_CPIM_DATA, tsk_strlen(CONTENT_CPIM_DATA), CONTENT_CPIM_TYPE);
+ if(content){
+ tsk_buffer_t* data = tmedia_content_get_data(content);
+ TSK_DEBUG_INFO("content-type=%s\n\ncontent=%s", TMEDIA_CONTENT(content)->type, TSK_BUFFER_DATA(data));
+ tsk_object_unref(data);
+ }
+
+ TSK_OBJECT_SAFE_FREE(content);
+}
+
+#endif /* _TEST_CONTENTS_H_ */
+
diff --git a/tinyMEDIA/test/test_image_attr.h b/tinyMEDIA/test/test_image_attr.h
new file mode 100644
index 0000000..e91d25f
--- /dev/null
+++ b/tinyMEDIA/test/test_image_attr.h
@@ -0,0 +1,54 @@
+/*
+* Copyright (C) 20012 Doubango Telecom <http://www.doubango.org>
+*
+* Contact: Mamadou Diop <diopmamadou(at)yahoo[dot]fr>
+*
+* 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 _TEST_IMG_ATTR_H_
+#define _TEST_IMG_ATTR_H_
+
+static const char* __test_imageattrs[] =
+{
+ "send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]",
+ "recv [x=800,y=640,sar=1.1] send [x=330,y=250]",
+ "recv [x=800,y=640,sar=1.1] send [x=[320:16:640],y=[240:16:480],par=[1.2-1.3]]",
+ "send [x=[480:16:800],y=[320:16:640],par=[1.2-1.3],q=0.6] [x=[176:8:208],y=[144:8:176],par=[1.2-1.3]] recv *",
+ "send [x=176,y=144] [x=224,y=176] [x=272,y=224] [x=320,y=240] recv [x=176,y=144] [x=224,y=176] [x=272,y=224,q=0.6] [x=320,y=240]",
+ "send [x=320,y=240]",
+ "recv [x=320,y=240]",
+ "send [x=[400:16:800],y=[320:16:640],sar=[1.0-1.3],par=[1.2-1.3]] recv [x=800,y=600,sar=1.1]",
+ "recv [x=464,y=384,sar=1.15] send [x=800,y=600,sar=1.1]"
+};
+
+void test_qos_imageattr()
+{
+ tsk_size_t i;
+ tmedia_imageattr_xt imageattr;
+ for(i = 0; i < sizeof(__test_imageattrs)/sizeof(__test_imageattrs[0]); ++i){
+ if(tmedia_imageattr_parse(&imageattr, __test_imageattrs[i], tsk_strlen(__test_imageattrs[i])) == 0){
+ TSK_DEBUG_INFO("image-attr parsed (OK): %s", __test_imageattrs[i]);
+ }
+ else{
+ TSK_DEBUG_ERROR("image-attr parsed (NOK): %s", __test_imageattrs[i]);
+ }
+ }
+}
+
+
+
+#endif /* _TEST_IMG_ATTR_H_ */
diff --git a/tinyMEDIA/test/test_qos.h b/tinyMEDIA/test/test_qos.h
new file mode 100644
index 0000000..3565cc2
--- /dev/null
+++ b/tinyMEDIA/test/test_qos.h
@@ -0,0 +1,267 @@
+/*
+* Copyright (C) 2009 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)yahoo.fr>
+*
+* 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 _TEST_QOS_H_
+#define _TEST_QOS_H_
+
+char* test_qos_tostring(const tmedia_qos_tline_t* tline)
+{
+ char* ret = tsk_null;
+ tsdp_header_M_t* M;
+
+ if(!tline){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ M = tsdp_header_M_create("audio", 20000, "RTP/AVP");
+ tmedia_qos_tline_to_sdp(tline, M);
+
+ ret = tsdp_header_tostring(TSDP_HEADER(M));
+ TSK_OBJECT_SAFE_FREE(M);
+
+ return ret;
+}
+
+void test_qos_parser()
+{
+ tsdp_header_M_t* M;
+ tmedia_qos_tline_e2e_t* e2e;
+ tmedia_qos_tline_segmented_t* segmented;
+ char* temp = tsk_null;
+ tmedia_qos_stype_t type;
+ tsk_bool_t canresume;
+
+ /* test E2E */
+ M = tsdp_header_M_create("audio", 20000, "RTP/AVP");
+ e2e = tmedia_qos_tline_e2e_create(tmedia_qos_strength_mandatory);
+ // to_sdp
+ tmedia_qos_tline_e2e_to_sdp(e2e, M);
+ if((type = tmedia_qos_get_type(M)) != tmedia_qos_stype_e2e){
+ TSK_DEBUG_ERROR("Invalid type");
+ }
+ if((temp = tsdp_header_tostring(TSDP_HEADER(M)))){
+ TSK_DEBUG_INFO("E2E to_sdp: %s", temp);
+ TSK_FREE(temp);
+ }
+ // from_sdp
+ TSK_OBJECT_SAFE_FREE(e2e);
+ e2e = tmedia_qos_tline_e2e_from_sdp(M);
+ canresume = tmedia_qos_tline_e2e_canresume(e2e);
+ tmedia_qos_tline_e2e_to_sdp(e2e, M);
+ if((temp = tsdp_header_tostring(TSDP_HEADER(M)))){
+ TSK_DEBUG_INFO("e2e from_sdp: %s", temp);
+ TSK_FREE(temp);
+ }
+
+
+ TSK_OBJECT_SAFE_FREE(e2e);
+ TSK_OBJECT_SAFE_FREE(M);
+
+ /* test Segmented */
+ M = tsdp_header_M_create("video", 20002, "RTP/AVP");
+ segmented = tmedia_qos_tline_segmented_create(tmedia_qos_strength_none);
+ segmented->remote_send.strength = tmedia_qos_strength_optional;
+ // to_sdp
+ tmedia_qos_tline_segmented_to_sdp(segmented, M);
+ if((type = tmedia_qos_get_type(M)) != tmedia_qos_stype_segmented){
+ TSK_DEBUG_ERROR("Invalid type");
+ }
+ if((temp = tsdp_header_tostring(TSDP_HEADER(M)))){
+ TSK_DEBUG_INFO("Segmented to_sdp: %s", temp);
+ TSK_FREE(temp);
+ }
+ // from_sdp
+ TSK_OBJECT_SAFE_FREE(segmented);
+ segmented = tmedia_qos_tline_segmented_from_sdp(M);
+ canresume = tmedia_qos_tline_segmented_canresume(segmented);
+ tmedia_qos_tline_segmented_to_sdp(segmented, M);
+ if((temp = tsdp_header_tostring(TSDP_HEADER(M)))){
+ TSK_DEBUG_INFO("Segmented from_sdp: %s", temp);
+ TSK_FREE(temp);
+ }
+
+
+
+ TSK_OBJECT_SAFE_FREE(segmented);
+ TSK_OBJECT_SAFE_FREE(M);
+}
+
+
+void test_qos_e2e_neg()
+{
+ tmedia_qos_tline_e2e_t *e2eA = tsk_null, *e2eB = tsk_null;
+ char* temp = tsk_null;
+
+ /* SDP1: A includes end-to-end quality of service preconditions in the
+ initial offer.
+
+ m=audio 20000 RTP/AVP 0
+ c=IN IP4 192.0.2.1
+ a=curr:qos e2e none
+ a=des:qos mandatory e2e sendrecv
+ */
+ e2eA = tmedia_qos_tline_e2e_create(tmedia_qos_strength_mandatory);
+ if((temp = test_qos_tostring((const tmedia_qos_tline_t*)e2eA))){
+ TSK_DEBUG_INFO("SDP1=\n%s", temp);
+ TSK_FREE(temp);
+ }
+
+ /* SDP2: Since B uses RSVP, it can know when resources in its "send"
+ direction are available, because it will receive RESV messages from
+ the network. However, it does not know the status of the
+ reservations in the other direction. B requests confirmation for
+ resource reservations in its "recv" direction to the peer user agent
+ A in its answer.
+
+ m=audio 30000 RTP/AVP 0
+ c=IN IP4 192.0.2.4
+ a=curr:qos e2e none
+ a=des:qos mandatory e2e sendrecv
+ a=conf:qos e2e recv
+ */
+ e2eB = tmedia_qos_tline_e2e_create(tmedia_qos_strength_mandatory);
+ tmedia_qos_tline_e2e_set_ro(e2eB, e2eA);
+ if((temp = test_qos_tostring((const tmedia_qos_tline_t*)e2eB))){
+ TSK_DEBUG_INFO("SDP2=\n%s", temp);
+ TSK_FREE(temp);
+ }
+
+ /* SDP3: When A receives RESV messages, it sends an updated offer (5) to B:
+
+ m=audio 20000 RTP/AVP 0
+ c=IN IP4 192.0.2.1
+ a=curr:qos e2e send
+ a=des:qos mandatory e2e sendrecv
+ */
+ tmedia_qos_tline_e2e_set_ro(e2eA, e2eB);
+ if((temp = test_qos_tostring((const tmedia_qos_tline_t*)e2eA))){
+ TSK_DEBUG_INFO("SDP3=\n%s", temp);
+ TSK_FREE(temp);
+ }
+
+ /* SDP4: B responds with an answer (6) which contains the current status
+ of the resource reservation (i.e., sendrecv):
+
+ m=audio 30000 RTP/AVP 0
+ c=IN IP4 192.0.2.4
+ a=curr:qos e2e sendrecv
+ a=des:qos mandatory e2e sendrecv
+ */
+ tmedia_qos_tline_e2e_set_ro(e2eB, e2eA);
+ if((temp = test_qos_tostring((const tmedia_qos_tline_t*)e2eB))){
+ TSK_DEBUG_INFO("SDP4=\n%s", temp);
+ TSK_FREE(temp);
+ }
+
+ /* A receive B's response */
+ tmedia_qos_tline_e2e_set_ro(e2eA, e2eB);
+ if((temp = test_qos_tostring((const tmedia_qos_tline_t*)e2eA))){
+ TSK_DEBUG_INFO("SDP5=\n%s", temp);
+ TSK_FREE(temp);
+ }
+
+ if(tmedia_qos_tline_e2e_canresume(e2eA)){
+ TSK_DEBUG_INFO("A can resume");
+ }
+ else{
+ TSK_DEBUG_ERROR("A can't resume");
+ }
+
+ if(tmedia_qos_tline_e2e_canresume(e2eB)){
+ TSK_DEBUG_INFO("B can resume");
+ }
+ else{
+ TSK_DEBUG_ERROR("B can't resume");
+ }
+
+ TSK_OBJECT_SAFE_FREE(e2eB);
+ TSK_OBJECT_SAFE_FREE(e2eA);
+}
+
+
+void test_qos_segmented_neg()
+{
+ tmedia_qos_tline_segmented_t *segA = tsk_null, *segB = tsk_null;
+ char* temp = tsk_null;
+
+ /* INVITE
+ a=curr:qos local none
+ a=curr:qos remote none
+ a=des:qos mandatory local sendrecv
+ a=des:qos mandatory remote sendrecv
+ */
+ segA = tmedia_qos_tline_segmented_create(tmedia_qos_strength_mandatory);
+ if((temp = test_qos_tostring((const tmedia_qos_tline_t*)segA))){
+ TSK_DEBUG_INFO("INVITE=\n%s", temp);
+ TSK_FREE(temp);
+ }
+
+ /* 183 Sesson progress
+ a=curr:qos local none
+ a=curr:qos remote none
+ a=des:qos mandatory local sendrecv
+ a=des:qos mandatory remote sendrecv
+ a=conf:qos remote sendrecv
+ */
+ segB = tmedia_qos_tline_segmented_create(tmedia_qos_strength_mandatory);
+ tmedia_qos_tline_segmented_set_ro(segB, segA);
+ if((temp = test_qos_tostring((const tmedia_qos_tline_t*)segB))){
+ TSK_DEBUG_INFO("183=\n%s", temp);
+ TSK_FREE(temp);
+ }
+
+ /* UPDATE
+ a=curr:qos local sendrecv
+ a=curr:qos remote none
+ a=des:qos mandatory local sendrecv
+ a=des:qos mandatory remote sendrecv
+ */
+ tmedia_qos_tline_segmented_set_ro(segA, segB);
+ if((temp = test_qos_tostring((const tmedia_qos_tline_t*)segA))){
+ TSK_DEBUG_INFO("UPDATE=\n%s", temp);
+ TSK_FREE(temp);
+ }
+
+ /* 200 OK
+ a=curr:qos local sendrecv
+ a=curr:qos remote sendrecv
+ a=des:qos mandatory local sendrecv
+ a=des:qos mandatory remote sendrecv
+ */
+ tmedia_qos_tline_segmented_set_ro(segB, segA);
+ if((temp = test_qos_tostring((const tmedia_qos_tline_t*)segB))){
+ TSK_DEBUG_INFO("200OK=\n%s", temp);
+ TSK_FREE(temp);
+ }
+
+ TSK_OBJECT_SAFE_FREE(segA);
+ TSK_OBJECT_SAFE_FREE(segB);
+}
+
+void test_qos()
+{
+ //test_qos_parser();
+ //test_qos_e2e_neg();
+ test_qos_segmented_neg();
+}
+
+#endif /* _TEST_QOS_H_ */
diff --git a/tinyMEDIA/test/test_sessions.h b/tinyMEDIA/test/test_sessions.h
new file mode 100644
index 0000000..97f5d56
--- /dev/null
+++ b/tinyMEDIA/test/test_sessions.h
@@ -0,0 +1,246 @@
+/*
+* Copyright (C) 2009 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)yahoo.fr>
+*
+* 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 _TEST_SESSIONS_H_
+#define _TEST_SESSIONS_H_
+
+#define SDP_RO \
+ "v=0\r\n" \
+ "o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com\r\n" \
+ "s=\r\n" \
+ "i=A Seminar on the session description protocol\r\n" \
+ "u=http://www.example.com/seminars/sdp.pdf\r\n" \
+ "e=j.doe@example.com (Jane Doe)\r\n" \
+ "p=+1 617 555-6011\r\n" \
+ "c=IN IP4 host.atlanta.example.com\r\n" \
+ "b=X-YZ:128\r\n" \
+ "z=2882844526 -1h 2898848070 0\r\n" \
+ "k=base64:ZWFzdXJlLg==\r\n" \
+ "t=3034423619 3042462419\r\n" \
+ "r=7d 1h 0 25h\r\n" \
+ "r=604800 3600 0 90000\r\n" \
+ "w=my dummy header\r\n" \
+ "m=audio 49170 RTP/AVP 8 0 97 98\r\n" \
+ "i=Audio line\r\n" \
+ "c=IN IP4 otherhost.biloxi.example.com\r\n" \
+ "k=base64:ZWFzdXJlLgdddddddddddddddddddddd==\r\n" \
+ "a=rtpmap:8 PCMA/8000\r\n" \
+ "a=rtpmap:0 PCMU/8000\r\n" \
+ "a=rtpmap:97 iLBC/8000\r\n" \
+ "a=rtpmap:98 AMR-WB/16000\r\n" \
+ "a=curr:qos local none\r\n" \
+ "a=curr:qos remote none\r\n" \
+ "a=des:qos mandatory local sendrecv\r\n" \
+ "a=des:qos mandatory remote sendrecv\r\n" \
+ "a=conf:qos remote sendrecv\r\n" \
+ "a=fmtp:98 octet-align=1\r\n" \
+ "m=video 51372 RTP/AVP 31 32 98\r\n" \
+ "i=Video line\r\n" \
+ "b=A-YZ:92\r\n" \
+ "b=B-YZ:256\r\n" \
+ "a=rtpmap:31 H261/90000\r\n" \
+ "a=rtpmap:32 MPV/90000\r\n" \
+ "a=rtpmap:98 H264/90000\r\n" \
+ "a=fmtp:98 profile-level-id=42A01E\r\n" \
+ "a=recvonly\r\n" \
+ "m=toto 51372 RTP/AVP 31 32\r\n" \
+ "i=Video line\r\n" \
+ "b=A-YZ:92\r\n" \
+ "b=B-YZ:256\r\n" \
+ "a=rtpmap:31 H261/90000\r\n" \
+ "a=rtpmap:32 MPV/90000\r\n" \
+ "a=recvonly\r\n"
+
+void test_sessions_client()
+{
+ tmedia_session_mgr_t* mgr;
+ const tsdp_message_t* sdp_lo;
+ tsdp_message_t* sdp_ro;
+ char* temp;
+ tsk_bool_t canresume;
+ tmedia_type_t media_type = (tmedia_audio | tmedia_video | tmedia_msrp | tmedia_t38);
+
+ int32_t width = 176;
+ int64_t height = 144LL;
+
+
+ /* create manager */
+ mgr = tmedia_session_mgr_create((tmedia_audio | tmedia_video | tmedia_msrp | tmedia_t38),
+ "0.0.0.0", tsk_false, tsk_true);
+ tmedia_session_mgr_set_qos(mgr, tmedia_qos_stype_segmented, tmedia_qos_strength_mandatory);
+
+ tmedia_session_mgr_set(mgr,
+ TMEDIA_SESSION_VIDEO_SET_INT32("width", width),
+ TMEDIA_SESSION_VIDEO_SET_INT64("height", height),
+ TMEDIA_SESSION_VIDEO_SET_STR("description", "This is my session"),
+ TMEDIA_SESSION_AUDIO_SET_INT32("rate", "8000"),
+ TMEDIA_SESSION_SET_STR(tmedia_audio | tmedia_video, "hello", "world"),
+ TMEDIA_SESSION_SET_NULL());
+
+ /* get lo */
+ sdp_lo = tmedia_session_mgr_get_lo(mgr);
+ if((temp = tsdp_message_tostring(sdp_lo))){
+ TSK_DEBUG_INFO("sdp_lo=%s", temp);
+ TSK_FREE(temp);
+ }
+
+ /* set ro */
+ if((sdp_ro = tsdp_message_parse(SDP_RO, tsk_strlen(SDP_RO)))){
+ tmedia_session_mgr_set_ro(mgr, sdp_ro);
+ TSK_OBJECT_SAFE_FREE(sdp_ro);
+ }
+
+ /* get lo */
+ sdp_lo = tmedia_session_mgr_get_lo(mgr);
+ if((temp = tsdp_message_tostring(sdp_lo))){
+ TSK_DEBUG_INFO("sdp_lo=%s", temp);
+ TSK_FREE(temp);
+ }
+
+ tmedia_session_mgr_start(mgr);
+
+ canresume = tmedia_session_mgr_canresume(mgr);
+
+ TSK_OBJECT_SAFE_FREE(mgr);
+}
+
+void test_sessions_server()
+{
+ tmedia_session_mgr_t* mgr = tsk_null;
+ const tsdp_message_t* sdp_lo;
+ tsdp_message_t* sdp_ro = tsk_null;
+ char* temp;
+ tmedia_type_t type;
+
+ /* parse ro */
+ if(!(sdp_ro = tsdp_message_parse(SDP_RO, tsk_strlen(SDP_RO)))){
+ TSK_DEBUG_ERROR("Failed to parse ro");
+ return;
+ }
+ else{
+ /* get ro media type */
+ type = tmedia_type_from_sdp(sdp_ro);
+ }
+
+ /* create manager */
+ mgr = tmedia_session_mgr_create(type, "192.168.16.82", tsk_false, tsk_false);
+
+ /* set ro */
+ tmedia_session_mgr_set_ro(mgr, sdp_ro);
+
+ /* get lo */
+ sdp_lo = tmedia_session_mgr_get_lo(mgr);
+ if((temp = tsdp_message_tostring(sdp_lo))){
+ TSK_DEBUG_INFO("sdp_lo=%s", temp);
+ TSK_FREE(temp);
+ }
+
+ TSK_OBJECT_SAFE_FREE(sdp_ro);
+ TSK_OBJECT_SAFE_FREE(mgr);
+}
+
+void test_sessions_hold_resume()
+{
+ tmedia_session_mgr_t* mgr;
+ const tsdp_message_t* sdp_lo;
+ char* temp;
+ tmedia_type_t type = tmedia_audio | tmedia_video | tmedia_msrp | tmedia_t38;
+
+ /* create manager */
+ mgr = tmedia_session_mgr_create(type, "192.168.16.82", tsk_false, tsk_true);
+
+ /* get lo */
+ sdp_lo = tmedia_session_mgr_get_lo(mgr);
+ if((temp = tsdp_message_tostring(sdp_lo))){
+ TSK_DEBUG_INFO("sdp_lo=%s", temp);
+ TSK_FREE(temp);
+ }
+
+ /* hold */
+ tmedia_session_mgr_hold(mgr, type);
+ sdp_lo = tmedia_session_mgr_get_lo(mgr);
+ if((temp = tsdp_message_tostring(sdp_lo))){
+ TSK_DEBUG_INFO("sdp_lo(hold)=%s", temp);
+ TSK_FREE(temp);
+ }
+ TSK_DEBUG_INFO("Hold local=%s and remote=%s",
+ tmedia_session_mgr_is_held(mgr, type, tsk_true) ? "yes" : "no",
+ tmedia_session_mgr_is_held(mgr, type, tsk_false) ? "yes" : "no"
+ );
+
+ /* resume */
+ tmedia_session_mgr_resume(mgr, type, tsk_true);
+ sdp_lo = tmedia_session_mgr_get_lo(mgr);
+ if((temp = tsdp_message_tostring(sdp_lo))){
+ TSK_DEBUG_INFO("sdp_lo(resume)=%s", temp);
+ TSK_FREE(temp);
+ }
+ TSK_DEBUG_INFO("Hold local=%s and remote=%s",
+ tmedia_session_mgr_is_held(mgr, type, tsk_true) ? "yes" : "no",
+ tmedia_session_mgr_is_held(mgr, type, tsk_false) ? "yes" : "no"
+ );
+
+ TSK_OBJECT_SAFE_FREE(mgr);
+}
+
+void test_sessions_add_remove()
+{
+ tmedia_session_mgr_t* mgr = tsk_null;
+ const tsdp_message_t* sdp_lo;
+ tsdp_message_t* sdp_ro = tsk_null;
+ char* temp;
+ tmedia_type_t type;
+
+ /* parse ro */
+ if(!(sdp_ro = tsdp_message_parse(SDP_RO, tsk_strlen(SDP_RO)))){
+ TSK_DEBUG_ERROR("Failed to parse ro");
+ return;
+ }
+ else{
+ /* get ro media type */
+ type = tmedia_type_from_sdp(sdp_ro);
+ }
+
+ /* create manager */
+ mgr = tmedia_session_mgr_create(type, "192.168.16.82", tsk_false, tsk_false);
+
+ /* set ro */
+ tmedia_session_mgr_set_ro(mgr, sdp_ro);
+
+ /* get lo */
+ sdp_lo = tmedia_session_mgr_get_lo(mgr);
+ if((temp = tsdp_message_tostring(sdp_lo))){
+ TSK_DEBUG_INFO("sdp_lo=%s", temp);
+ TSK_FREE(temp);
+ }
+
+ TSK_OBJECT_SAFE_FREE(sdp_ro);
+ TSK_OBJECT_SAFE_FREE(mgr);
+}
+
+void test_sessions()
+{
+ test_sessions_client();
+ //test_sessions_server();
+ //test_sessions_hold_resume();
+}
+
+#endif /* _TEST_SESSIONS_H_ */
diff --git a/tinyMEDIA/tinyMEDIA.pc.in b/tinyMEDIA/tinyMEDIA.pc.in
new file mode 100644
index 0000000..caaa004
--- /dev/null
+++ b/tinyMEDIA/tinyMEDIA.pc.in
@@ -0,0 +1,15 @@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+libdir = @libdir@
+includedir = @includedir@
+
+Name : libtinyMEDIA
+Description : Doubango Telecom tinyMEDIA (Plugins definition) library
+Version : @PACKAGE_VERSION@
+Requires:
+Requires.private: tinySAK = @PACKAGE_VERSION@ tinyNET = @PACKAGE_VERSION@ tinySDP = @PACKAGE_VERSION@
+Conflicts:
+Cflags : -I${includedir}/tinymedia
+Libs : -L${libdir} -ltinyMEDIA
+Libs.private:
+
diff --git a/tinyMEDIA/tinyMEDIA.sln b/tinyMEDIA/tinyMEDIA.sln
new file mode 100644
index 0000000..6303126
--- /dev/null
+++ b/tinyMEDIA/tinyMEDIA.sln
@@ -0,0 +1,64 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinyMEDIA", "tinyMEDIA.vcproj", "{52814B0D-7DCA-45B8-9A16-8B147040D619}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinySAK", "..\tinySAK\tinySAK.vcproj", "{6BC9B796-10C6-4CF7-A6E4-E2DACCDA84DA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcproj", "{6ED4F246-C3B7-4DD5-9434-3A3F69CC0AD6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinySDP", "..\tinySDP\tinySDP.vcproj", "{E45DB518-6562-4033-80E8-60030F0B169F}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinyNET", "..\tinyNET\tinyNET.vcproj", "{7522A458-92F4-4259-B906-E84C2A65D9F1}"
+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)
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {52814B0D-7DCA-45B8-9A16-8B147040D619}.Debug|Win32.ActiveCfg = Debug|Win32
+ {52814B0D-7DCA-45B8-9A16-8B147040D619}.Debug|Win32.Build.0 = Debug|Win32
+ {52814B0D-7DCA-45B8-9A16-8B147040D619}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32
+ {52814B0D-7DCA-45B8-9A16-8B147040D619}.Release|Win32.ActiveCfg = Release|Win32
+ {52814B0D-7DCA-45B8-9A16-8B147040D619}.Release|Win32.Build.0 = Release|Win32
+ {52814B0D-7DCA-45B8-9A16-8B147040D619}.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)
+ {6ED4F246-C3B7-4DD5-9434-3A3F69CC0AD6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6ED4F246-C3B7-4DD5-9434-3A3F69CC0AD6}.Debug|Win32.Build.0 = Debug|Win32
+ {6ED4F246-C3B7-4DD5-9434-3A3F69CC0AD6}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32
+ {6ED4F246-C3B7-4DD5-9434-3A3F69CC0AD6}.Release|Win32.ActiveCfg = Release|Win32
+ {6ED4F246-C3B7-4DD5-9434-3A3F69CC0AD6}.Release|Win32.Build.0 = Release|Win32
+ {6ED4F246-C3B7-4DD5-9434-3A3F69CC0AD6}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32
+ {E45DB518-6562-4033-80E8-60030F0B169F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E45DB518-6562-4033-80E8-60030F0B169F}.Debug|Win32.Build.0 = Debug|Win32
+ {E45DB518-6562-4033-80E8-60030F0B169F}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Win32
+ {E45DB518-6562-4033-80E8-60030F0B169F}.Release|Win32.ActiveCfg = Release|Win32
+ {E45DB518-6562-4033-80E8-60030F0B169F}.Release|Win32.Build.0 = Release|Win32
+ {E45DB518-6562-4033-80E8-60030F0B169F}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Win32
+ {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)
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/tinyMEDIA/tinyMEDIA.vcproj b/tinyMEDIA/tinyMEDIA.vcproj
new file mode 100644
index 0000000..5cc2ed6
--- /dev/null
+++ b/tinyMEDIA/tinyMEDIA.vcproj
@@ -0,0 +1,408 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="tinyMEDIA"
+ ProjectGUID="{52814B0D-7DCA-45B8-9A16-8B147040D619}"
+ RootNamespace="tinyMEDIA"
+ 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="&quot;..\thirdparties\win32\include&quot;;include;&quot;..\tinySAK\src&quot;;&quot;..\tinySDP\include&quot;;&quot;..\tinyNET\src&quot;"
+ PreprocessorDefinitions="DEBUG_LEVEL=DEBUG_LEVEL_INFO;WIN32;_DEBUG;_WINDOWS;_USRDLL;TINYMEDIA_EXPORTS;FLIP_ENCODED_PICT=1;FLIP_DECODED_PICT=0"
+ 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)\tinySDP.lib $(OutDir)\tinyNET.lib"
+ 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="&quot;..\thirdparties\win32\include&quot;;include;&quot;..\tinySAK\src&quot;;&quot;..\tinySDP\include&quot;;&quot;..\tinyNET\src&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;TINYMEDIA_EXPORTS;FLIP_ENCODED_PICT=1;FLIP_DECODED_PICT=0"
+ 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="$(OutDir)\tinySAK.lib $(OutDir)\tinySDP.lib $(OutDir)\tinyNET.lib"
+ LinkIncremental="1"
+ IgnoreDefaultLibraryNames=""
+ 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="headers(*.h)"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\include\tinymedia.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia_config.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_codec.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_codec_dummy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_common.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_consumer.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_converter_video.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_defaults.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_denoise.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_imageattr.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_jitterbuffer.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_params.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_producer.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_qos.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_resampler.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_session.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_session_dummy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_session_ghost.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\tmedia_vad.h"
+ >
+ </File>
+ <Filter
+ Name="content"
+ >
+ <File
+ RelativePath=".\include\tinymedia\content\tmedia_content.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\content\tmedia_content_cpim.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\content\tmedia_content_multipart.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\tinymedia\content\tmedia_content_sip_frag.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="source(*.c)"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\src\tmedia.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_codec.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_codec_dummy.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_common.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_consumer.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_converter_video.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_defaults.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_denoise.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_imageattr.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_jitterbuffer.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_params.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_producer.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_qos.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_resampler.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_session.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_session_dummy.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_session_ghost.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\tmedia_vad.c"
+ >
+ </File>
+ <Filter
+ Name="content"
+ >
+ <File
+ RelativePath=".\src\content\tmedia_content.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\content\tmedia_content_cpim.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\content\tmedia_content_multipart.c"
+ >
+ </File>
+ <File
+ RelativePath=".\src\content\tmedia_content_sip_frag.c"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="ragel(.*rl)"
+ >
+ <File
+ RelativePath=".\ragel\tmedia_content_cpim.rl"
+ >
+ </File>
+ <File
+ RelativePath=".\ragel\tmedia_imageattr.rl"
+ >
+ </File>
+ <File
+ RelativePath=".\ragel\tmedia_machine_utils.rl"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="resources(*.rc)"
+ >
+ <File
+ RelativePath=".\version.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/tinyMEDIA/version.rc b/tinyMEDIA/version.rc
new file mode 100644
index 0000000..6453bb3
--- /dev/null
+++ b/tinyMEDIA/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", "tinymedia.dll"
+ VALUE "LegalCopyright", "(c) 2010-2013 Doubango Telecom. All rights reserved."
+ VALUE "OriginalFilename", "tinymedia.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
+
diff --git a/tinyMEDIA/winrt/tinyMEDIA.sln b/tinyMEDIA/winrt/tinyMEDIA.sln
new file mode 100644
index 0000000..1b4f892
--- /dev/null
+++ b/tinyMEDIA/winrt/tinyMEDIA.sln
@@ -0,0 +1,67 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Express 2012 for Windows Phone
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinyMEDIA", "tinyMEDIA.vcxproj", "{52E43EEB-A549-4159-B254-DCA225D7638B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {19279F5B-CDAF-4187-9F09-2A896A828B05} = {19279F5B-CDAF-4187-9F09-2A896A828B05}
+ {982D737A-0649-4C32-A00E-08992A0B7673} = {982D737A-0649-4C32-A00E-08992A0B7673}
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC} = {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinySAK", "..\..\tinySAK\winrt\tinySAK.vcxproj", "{19279F5B-CDAF-4187-9F09-2A896A828B05}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinySDP", "..\..\tinySDP\winrt\tinySDP.vcxproj", "{982D737A-0649-4C32-A00E-08992A0B7673}"
+ ProjectSection(ProjectDependencies) = postProject
+ {19279F5B-CDAF-4187-9F09-2A896A828B05} = {19279F5B-CDAF-4187-9F09-2A896A828B05}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinyNET", "..\..\tinyNET\winrt\tinyNET.vcxproj", "{06E58F9D-28A1-4DD4-AF11-2F5239222CCC}"
+ ProjectSection(ProjectDependencies) = postProject
+ {19279F5B-CDAF-4187-9F09-2A896A828B05} = {19279F5B-CDAF-4187-9F09-2A896A828B05}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|Win32 = Debug|Win32
+ Release|ARM = Release|ARM
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {52E43EEB-A549-4159-B254-DCA225D7638B}.Debug|ARM.ActiveCfg = Debug|ARM
+ {52E43EEB-A549-4159-B254-DCA225D7638B}.Debug|ARM.Build.0 = Debug|ARM
+ {52E43EEB-A549-4159-B254-DCA225D7638B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {52E43EEB-A549-4159-B254-DCA225D7638B}.Debug|Win32.Build.0 = Debug|Win32
+ {52E43EEB-A549-4159-B254-DCA225D7638B}.Release|ARM.ActiveCfg = Release|ARM
+ {52E43EEB-A549-4159-B254-DCA225D7638B}.Release|ARM.Build.0 = Release|ARM
+ {52E43EEB-A549-4159-B254-DCA225D7638B}.Release|Win32.ActiveCfg = Release|Win32
+ {52E43EEB-A549-4159-B254-DCA225D7638B}.Release|Win32.Build.0 = Release|Win32
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Debug|ARM.ActiveCfg = Debug|ARM
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Debug|ARM.Build.0 = Debug|ARM
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Debug|Win32.ActiveCfg = Debug|Win32
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Debug|Win32.Build.0 = Debug|Win32
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Release|ARM.ActiveCfg = Release|ARM
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Release|ARM.Build.0 = Release|ARM
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Release|Win32.ActiveCfg = Release|Win32
+ {19279F5B-CDAF-4187-9F09-2A896A828B05}.Release|Win32.Build.0 = Release|Win32
+ {982D737A-0649-4C32-A00E-08992A0B7673}.Debug|ARM.ActiveCfg = Debug|ARM
+ {982D737A-0649-4C32-A00E-08992A0B7673}.Debug|ARM.Build.0 = Debug|ARM
+ {982D737A-0649-4C32-A00E-08992A0B7673}.Debug|Win32.ActiveCfg = Debug|Win32
+ {982D737A-0649-4C32-A00E-08992A0B7673}.Debug|Win32.Build.0 = Debug|Win32
+ {982D737A-0649-4C32-A00E-08992A0B7673}.Release|ARM.ActiveCfg = Release|ARM
+ {982D737A-0649-4C32-A00E-08992A0B7673}.Release|ARM.Build.0 = Release|ARM
+ {982D737A-0649-4C32-A00E-08992A0B7673}.Release|Win32.ActiveCfg = Release|Win32
+ {982D737A-0649-4C32-A00E-08992A0B7673}.Release|Win32.Build.0 = Release|Win32
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Debug|ARM.ActiveCfg = Debug|ARM
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Debug|ARM.Build.0 = Debug|ARM
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Debug|Win32.Build.0 = Debug|Win32
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Release|ARM.ActiveCfg = Release|ARM
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Release|ARM.Build.0 = Release|ARM
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Release|Win32.ActiveCfg = Release|Win32
+ {06E58F9D-28A1-4DD4-AF11-2F5239222CCC}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/tinyMEDIA/winrt/tinyMEDIA.vcxproj b/tinyMEDIA/winrt/tinyMEDIA.vcxproj
new file mode 100644
index 0000000..02d59a5
--- /dev/null
+++ b/tinyMEDIA/winrt/tinyMEDIA.vcxproj
@@ -0,0 +1,208 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|ARM">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM">
+ <Configuration>Release</Configuration>
+ <Platform>ARM</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{52e43eeb-a549-4159-b254-dca225d7638b}</ProjectGuid>
+ <RootNamespace>tinyMEDIA</RootNamespace>
+ <DefaultLanguage>en-US</DefaultLanguage>
+ <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v110_wp80</PlatformToolset>
+ <IgnoreImportLibrary>false</IgnoreImportLibrary>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v110_wp80</PlatformToolset>
+ <IgnoreImportLibrary>false</IgnoreImportLibrary>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v110_wp80</PlatformToolset>
+ <IgnoreImportLibrary>false</IgnoreImportLibrary>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <PlatformToolset>v110_wp80</PlatformToolset>
+ <IgnoreImportLibrary>false</IgnoreImportLibrary>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <GenerateManifest>false</GenerateManifest>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>$(SolutionDir)$(Configuration)\$(MSBuildProjectName)\</OutDir>
+ <IntDir>$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>$(SolutionDir)$(Configuration)\$(MSBuildProjectName)\</OutDir>
+ <IntDir>$(Platform)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
+ <OutDir>$(SolutionDir)$(Configuration)\$(MSBuildProjectName)\</OutDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
+ <OutDir>$(SolutionDir)$(Configuration)\$(MSBuildProjectName)\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>DEBUG_LEVEL=DEBUG_LEVEL_INFO;_USRDLL;TINYMEDIA_EXPORTS;FLIP_ENCODED_PICT=1;FLIP_DECODED_PICT=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <CompileAsWinRT>false</CompileAsWinRT>
+ <AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ <AdditionalIncludeDirectories>..\..\thirdparties\winrt\include;..\include;..\..\tinySAK\src;..\..\tinySDP\include;..\..\tinyNET\src</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>"$(SolutionDir)$(Configuration)\tinySAK\tinySAK.lib";"$(SolutionDir)$(Configuration)\tinyNET\tinyNET.lib";"$(SolutionDir)$(Configuration)\tinySDP\tinySDP.lib";%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>DEBUG_LEVEL=DEBUG_LEVEL_INFO;_USRDLL;TINYMEDIA_EXPORTS;FLIP_ENCODED_PICT=1;FLIP_DECODED_PICT=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <CompileAsWinRT>false</CompileAsWinRT>
+ <AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ <AdditionalIncludeDirectories>..\..\thirdparties\winrt\include;..\include;..\..\tinySAK\src;..\..\tinySDP\include;..\..\tinyNET\src</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>"$(SolutionDir)$(Configuration)\tinySAK\tinySAK.lib";"$(SolutionDir)$(Configuration)\tinyNET\tinyNET.lib";"$(SolutionDir)$(Configuration)\tinySDP\tinySDP.lib";%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
+ <ClCompile>
+ <PreprocessorDefinitions>DEBUG_LEVEL=DEBUG_LEVEL_INFO;_USRDLL;TINYMEDIA_EXPORTS;FLIP_ENCODED_PICT=1;FLIP_DECODED_PICT=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>
+ </PrecompiledHeaderFile>
+ <CompileAsWinRT>false</CompileAsWinRT>
+ <AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ <AdditionalIncludeDirectories>..\..\thirdparties\winrt\include;..\include;..\..\tinySAK\src;..\..\tinySDP\include;..\..\tinyNET\src</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>"$(SolutionDir)$(Configuration)\tinySAK\tinySAK.lib";"$(SolutionDir)$(Configuration)\tinyNET\tinyNET.lib";"$(SolutionDir)$(Configuration)\tinySDP\tinySDP.lib";%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
+ <ClCompile>
+ <PreprocessorDefinitions>DEBUG_LEVEL=DEBUG_LEVEL_INFO;_USRDLL;TINYMEDIA_EXPORTS;FLIP_ENCODED_PICT=1;FLIP_DECODED_PICT=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <CompileAsWinRT>false</CompileAsWinRT>
+ <AdditionalUsingDirectories>$(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)</AdditionalUsingDirectories>
+ <AdditionalIncludeDirectories>..\..\thirdparties\winrt\include;..\include;..\..\tinySAK\src;..\..\tinySDP\include;..\..\tinyNET\src</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <GenerateWindowsMetadata>false</GenerateWindowsMetadata>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>"$(SolutionDir)$(Configuration)\tinySAK\tinySAK.lib";"$(SolutionDir)$(Configuration)\tinyNET\tinyNET.lib";"$(SolutionDir)$(Configuration)\tinySDP\tinySDP.lib";%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Reference Include="Windows">
+ <IsWinMDFile>true</IsWinMDFile>
+ </Reference>
+ <Reference Include="platform.winmd">
+ <IsWinMDFile>true</IsWinMDFile>
+ <Private>false</Private>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\include\tinymedia.h" />
+ <ClInclude Include="..\include\tinymedia\content\tmedia_content.h" />
+ <ClInclude Include="..\include\tinymedia\content\tmedia_content_cpim.h" />
+ <ClInclude Include="..\include\tinymedia\content\tmedia_content_multipart.h" />
+ <ClInclude Include="..\include\tinymedia\content\tmedia_content_sip_frag.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_codec.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_codec_dummy.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_common.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_consumer.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_converter_video.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_defaults.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_denoise.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_imageattr.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_jitterbuffer.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_params.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_producer.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_qos.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_resampler.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_session.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_session_dummy.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_session_ghost.h" />
+ <ClInclude Include="..\include\tinymedia\tmedia_vad.h" />
+ <ClInclude Include="..\include\tinymedia_config.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\src\content\tmedia_content.c" />
+ <ClCompile Include="..\src\content\tmedia_content_cpim.c" />
+ <ClCompile Include="..\src\content\tmedia_content_multipart.c" />
+ <ClCompile Include="..\src\content\tmedia_content_sip_frag.c" />
+ <ClCompile Include="..\src\tmedia.c" />
+ <ClCompile Include="..\src\tmedia_codec.c" />
+ <ClCompile Include="..\src\tmedia_codec_dummy.c" />
+ <ClCompile Include="..\src\tmedia_common.c" />
+ <ClCompile Include="..\src\tmedia_consumer.c" />
+ <ClCompile Include="..\src\tmedia_converter_video.c" />
+ <ClCompile Include="..\src\tmedia_defaults.c" />
+ <ClCompile Include="..\src\tmedia_denoise.c" />
+ <ClCompile Include="..\src\tmedia_imageattr.c" />
+ <ClCompile Include="..\src\tmedia_jitterbuffer.c" />
+ <ClCompile Include="..\src\tmedia_params.c" />
+ <ClCompile Include="..\src\tmedia_producer.c" />
+ <ClCompile Include="..\src\tmedia_qos.c" />
+ <ClCompile Include="..\src\tmedia_resampler.c" />
+ <ClCompile Include="..\src\tmedia_session.c" />
+ <ClCompile Include="..\src\tmedia_session_dummy.c" />
+ <ClCompile Include="..\src\tmedia_session_ghost.c" />
+ <ClCompile Include="..\src\tmedia_vad.c" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsPhone\v$(TargetPlatformVersion)\Microsoft.Cpp.WindowsPhone.$(TargetPlatformVersion).targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/tinyMEDIA/winrt/tinyMEDIA.vcxproj.filters b/tinyMEDIA/winrt/tinyMEDIA.vcxproj.filters
new file mode 100644
index 0000000..2a1e3e7
--- /dev/null
+++ b/tinyMEDIA/winrt/tinyMEDIA.vcxproj.filters
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ <Filter Include="include">
+ <UniqueIdentifier>{c89a9764-c625-4c3b-9980-30c97b440ea3}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src">
+ <UniqueIdentifier>{8f205ba6-84f7-4863-bd40-9d93b94228d5}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="include\tinymedia">
+ <UniqueIdentifier>{1224fd1c-e1b6-4ced-94e1-03465211556c}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="include\tinymedia\content">
+ <UniqueIdentifier>{c4c0550e-c464-4135-a8a5-502a39b79795}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="src\content">
+ <UniqueIdentifier>{19e7973f-0178-4b2a-98e2-7b8f0f41672d}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\include\tinymedia.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia_config.h">
+ <Filter>include</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_codec.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_codec_dummy.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_common.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_consumer.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_converter_video.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_defaults.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_denoise.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_imageattr.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_jitterbuffer.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_params.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_producer.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_qos.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_resampler.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_session.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_session_dummy.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_session_ghost.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\tmedia_vad.h">
+ <Filter>include\tinymedia</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\content\tmedia_content.h">
+ <Filter>include\tinymedia\content</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\content\tmedia_content_cpim.h">
+ <Filter>include\tinymedia\content</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\content\tmedia_content_multipart.h">
+ <Filter>include\tinymedia\content</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\tinymedia\content\tmedia_content_sip_frag.h">
+ <Filter>include\tinymedia\content</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\src\tmedia.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_codec.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_codec_dummy.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_common.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_consumer.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_converter_video.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_defaults.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_denoise.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_imageattr.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_jitterbuffer.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_params.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_producer.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_qos.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_resampler.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_session.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_session_dummy.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_session_ghost.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\tmedia_vad.c">
+ <Filter>src</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\content\tmedia_content.c">
+ <Filter>src\content</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\content\tmedia_content_cpim.c">
+ <Filter>src\content</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\content\tmedia_content_multipart.c">
+ <Filter>src\content</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\content\tmedia_content_sip_frag.c">
+ <Filter>src\content</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
OpenPOWER on IntegriCloud