From 631fffee8a28b1bec5ed1f1d26a20e0135967f99 Mon Sep 17 00:00:00 2001 From: Mamadou DIOP Date: Mon, 17 Aug 2015 01:56:35 +0200 Subject: - --- tinyMEDIA/Makefile.am | 44 + tinyMEDIA/droid-makefile | 49 + tinyMEDIA/include/tinymedia.h | 60 + .../include/tinymedia/content/tmedia_content.h | 126 + .../tinymedia/content/tmedia_content_cpim.h | 59 + .../tinymedia/content/tmedia_content_multipart.h | 0 .../tinymedia/content/tmedia_content_sip_frag.h | 0 tinyMEDIA/include/tinymedia/tmedia.h | 121 + tinyMEDIA/include/tinymedia/tmedia_codec.h | 468 ++++ tinyMEDIA/include/tinymedia/tmedia_codec_dummy.h | 78 + tinyMEDIA/include/tinymedia/tmedia_common.h | 285 +++ tinyMEDIA/include/tinymedia/tmedia_consumer.h | 147 ++ .../include/tinymedia/tmedia_converter_video.h | 114 + tinyMEDIA/include/tinymedia/tmedia_defaults.h | 146 ++ tinyMEDIA/include/tinymedia/tmedia_denoise.h | 97 + tinyMEDIA/include/tinymedia/tmedia_imageattr.h | 108 + tinyMEDIA/include/tinymedia/tmedia_jitterbuffer.h | 102 + tinyMEDIA/include/tinymedia/tmedia_params.h | 119 + tinyMEDIA/include/tinymedia/tmedia_producer.h | 144 ++ tinyMEDIA/include/tinymedia/tmedia_qos.h | 194 ++ tinyMEDIA/include/tinymedia/tmedia_resampler.h | 86 + tinyMEDIA/include/tinymedia/tmedia_session.h | 578 +++++ tinyMEDIA/include/tinymedia/tmedia_session_dummy.h | 76 + tinyMEDIA/include/tinymedia/tmedia_session_ghost.h | 55 + tinyMEDIA/include/tinymedia/tmedia_vad.h | 0 tinyMEDIA/include/tinymedia_config.h | 98 + tinyMEDIA/ragel.sh | 11 + tinyMEDIA/ragel/tmedia_content_cpim.rl | 244 ++ tinyMEDIA/ragel/tmedia_imageattr.rl | 183 ++ tinyMEDIA/ragel/tmedia_machine_utils.rl | 78 + tinyMEDIA/src/content/tmedia_content.c | 357 +++ tinyMEDIA/src/content/tmedia_content_cpim.c | 449 ++++ tinyMEDIA/src/content/tmedia_content_multipart.c | 0 tinyMEDIA/src/content/tmedia_content_sip_frag.c | 0 tinyMEDIA/src/tmedia.c | 289 +++ tinyMEDIA/src/tmedia_codec.c | 833 +++++++ tinyMEDIA/src/tmedia_codec_dummy.c | 369 +++ tinyMEDIA/src/tmedia_common.c | 442 ++++ tinyMEDIA/src/tmedia_consumer.c | 288 +++ tinyMEDIA/src/tmedia_converter_video.c | 126 + tinyMEDIA/src/tmedia_defaults.c | 618 +++++ tinyMEDIA/src/tmedia_denoise.c | 242 ++ tinyMEDIA/src/tmedia_imageattr.c | 954 ++++++++ tinyMEDIA/src/tmedia_jitterbuffer.c | 281 +++ tinyMEDIA/src/tmedia_params.c | 197 ++ tinyMEDIA/src/tmedia_producer.c | 304 +++ tinyMEDIA/src/tmedia_qos.c | 862 +++++++ tinyMEDIA/src/tmedia_resampler.c | 152 ++ tinyMEDIA/src/tmedia_session.c | 2524 ++++++++++++++++++++ tinyMEDIA/src/tmedia_session_dummy.c | 490 ++++ tinyMEDIA/src/tmedia_session_ghost.c | 154 ++ tinyMEDIA/src/tmedia_vad.c | 0 tinyMEDIA/test/droid-makefile | 29 + tinyMEDIA/test/dummy.c | 173 ++ tinyMEDIA/test/dummy.h | 43 + tinyMEDIA/test/test.c | 170 ++ tinyMEDIA/test/test.vcproj | 217 ++ tinyMEDIA/test/test_codecs.h | 37 + tinyMEDIA/test/test_contents.h | 89 + tinyMEDIA/test/test_image_attr.h | 54 + tinyMEDIA/test/test_qos.h | 267 +++ tinyMEDIA/test/test_sessions.h | 246 ++ tinyMEDIA/tinyMEDIA.pc.in | 15 + tinyMEDIA/tinyMEDIA.sln | 64 + tinyMEDIA/tinyMEDIA.vcproj | 408 ++++ tinyMEDIA/version.rc | 102 + tinyMEDIA/winrt/tinyMEDIA.sln | 67 + tinyMEDIA/winrt/tinyMEDIA.vcxproj | 208 ++ tinyMEDIA/winrt/tinyMEDIA.vcxproj.filters | 166 ++ 69 files changed, 16156 insertions(+) create mode 100644 tinyMEDIA/Makefile.am create mode 100644 tinyMEDIA/droid-makefile create mode 100644 tinyMEDIA/include/tinymedia.h create mode 100644 tinyMEDIA/include/tinymedia/content/tmedia_content.h create mode 100644 tinyMEDIA/include/tinymedia/content/tmedia_content_cpim.h create mode 100644 tinyMEDIA/include/tinymedia/content/tmedia_content_multipart.h create mode 100644 tinyMEDIA/include/tinymedia/content/tmedia_content_sip_frag.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_codec.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_codec_dummy.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_common.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_consumer.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_converter_video.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_defaults.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_denoise.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_imageattr.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_jitterbuffer.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_params.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_producer.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_qos.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_resampler.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_session.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_session_dummy.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_session_ghost.h create mode 100644 tinyMEDIA/include/tinymedia/tmedia_vad.h create mode 100644 tinyMEDIA/include/tinymedia_config.h create mode 100644 tinyMEDIA/ragel.sh create mode 100644 tinyMEDIA/ragel/tmedia_content_cpim.rl create mode 100644 tinyMEDIA/ragel/tmedia_imageattr.rl create mode 100644 tinyMEDIA/ragel/tmedia_machine_utils.rl create mode 100644 tinyMEDIA/src/content/tmedia_content.c create mode 100644 tinyMEDIA/src/content/tmedia_content_cpim.c create mode 100644 tinyMEDIA/src/content/tmedia_content_multipart.c create mode 100644 tinyMEDIA/src/content/tmedia_content_sip_frag.c create mode 100644 tinyMEDIA/src/tmedia.c create mode 100644 tinyMEDIA/src/tmedia_codec.c create mode 100644 tinyMEDIA/src/tmedia_codec_dummy.c create mode 100644 tinyMEDIA/src/tmedia_common.c create mode 100644 tinyMEDIA/src/tmedia_consumer.c create mode 100644 tinyMEDIA/src/tmedia_converter_video.c create mode 100644 tinyMEDIA/src/tmedia_defaults.c create mode 100644 tinyMEDIA/src/tmedia_denoise.c create mode 100644 tinyMEDIA/src/tmedia_imageattr.c create mode 100644 tinyMEDIA/src/tmedia_jitterbuffer.c create mode 100644 tinyMEDIA/src/tmedia_params.c create mode 100644 tinyMEDIA/src/tmedia_producer.c create mode 100644 tinyMEDIA/src/tmedia_qos.c create mode 100644 tinyMEDIA/src/tmedia_resampler.c create mode 100644 tinyMEDIA/src/tmedia_session.c create mode 100644 tinyMEDIA/src/tmedia_session_dummy.c create mode 100644 tinyMEDIA/src/tmedia_session_ghost.c create mode 100644 tinyMEDIA/src/tmedia_vad.c create mode 100644 tinyMEDIA/test/droid-makefile create mode 100644 tinyMEDIA/test/dummy.c create mode 100644 tinyMEDIA/test/dummy.h create mode 100644 tinyMEDIA/test/test.c create mode 100644 tinyMEDIA/test/test.vcproj create mode 100644 tinyMEDIA/test/test_codecs.h create mode 100644 tinyMEDIA/test/test_contents.h create mode 100644 tinyMEDIA/test/test_image_attr.h create mode 100644 tinyMEDIA/test/test_qos.h create mode 100644 tinyMEDIA/test/test_sessions.h create mode 100644 tinyMEDIA/tinyMEDIA.pc.in create mode 100644 tinyMEDIA/tinyMEDIA.sln create mode 100644 tinyMEDIA/tinyMEDIA.vcproj create mode 100644 tinyMEDIA/version.rc create mode 100644 tinyMEDIA/winrt/tinyMEDIA.sln create mode 100644 tinyMEDIA/winrt/tinyMEDIA.vcxproj create mode 100644 tinyMEDIA/winrt/tinyMEDIA.vcxproj.filters (limited to 'tinyMEDIA') 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 +* +* 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 + * + + */ +#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 +* +* 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 + * + */ +#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 +* +* 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 + * + */ +#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 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 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 +* +* 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 + * + + */ +#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 +* +* 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 + * + + */ +#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 +* +* 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 + * + + */ +#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 +* +* 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 + * + */ +#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 +* +* 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 + * + */ +#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 + * + * 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 +* +* Contact: Mamadou Diop +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ + +/**@file tmedia_imageattr.h + * @brief 'image-attr' parser as per RFC 6236 + * + * @author Mamadou Diop + * + */ +#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 +* +* 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 + */ +#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 +* +* 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 + * + + */ +#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 +* +* 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 + * + + */ +#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 +* +* 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 + * + + */ +#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 +* +* 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 + */ +#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 +* +* 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 + * + + */ +#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 +* +* 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 + * + + */ +#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 +* +* 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 + * + + */ +#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 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 +* +* 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 +# include +#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 +#ifdef __SYMBIAN32__ +#include +#endif + +#if HAVE_CONFIG_H + #include +#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 + +/* 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 +* +* 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 + +/*********************************** +* 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 +* +* 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 + * + + */ +%%{ + + 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 + +/**@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 + +/* 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 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 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 +* +* 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 + * + */ +#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; iobjdef && 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(¶ms, 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 +* +* 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 + * + + */ +#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 /* 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.
+* 0 : @a codec1 identical to @a codec2.
+* >0 : @a codec1 greater than @a codec2.
+*/ +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; iname, 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; iname, 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.
+* 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 +* +* 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 + * + + */ +#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 +* +* 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 + * + + */ +#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 /* 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= 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= (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; itype & 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 +* +* 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 + * + */ +#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 + * + * 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 /* 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 +* +* 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 +* + +*/ +#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 +* +* 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 + +/*********************************** +* 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 +* +* 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 + */ +#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; itype & 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 +* +* 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 + * + + */ +#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(¶ms, (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**)¶m); + } + 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; itype & 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 +* +* 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 + * + + */ +#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 +* +* 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 + */ +#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.
+* 0 : @a sess1 identical to @a sess2.
+* >0 : @a sess1 greater than @a sess2.
+*/ +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**)©); + + 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 +* +* 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 + * + + */ +#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 +* +* 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 + * + + */ +#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 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 +* +* 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 +* +* 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 +* +* 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 +* +* 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 +* +* 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: \r\n" \ +"From: \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 +* +* Contact: Mamadou Diop +* +* This file is part of Open Source Doubango Framework. +* +* DOUBANGO is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* DOUBANGO is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#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 +* +* 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 +* +* 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + Debug + Win32 + + + Debug + ARM + + + Release + Win32 + + + Release + ARM + + + + {52e43eeb-a549-4159-b254-dca225d7638b} + tinyMEDIA + en-US + 11.0 + + + + DynamicLibrary + true + v110_wp80 + false + + + DynamicLibrary + true + v110_wp80 + false + + + DynamicLibrary + false + true + v110_wp80 + false + + + DynamicLibrary + false + true + v110_wp80 + false + + + + + + + + false + + + $(SolutionDir)$(Configuration)\$(MSBuildProjectName)\ + $(Platform)\$(Configuration)\ + + + $(SolutionDir)$(Configuration)\$(MSBuildProjectName)\ + $(Platform)\$(Configuration)\ + + + $(SolutionDir)$(Configuration)\$(MSBuildProjectName)\ + + + $(SolutionDir)$(Configuration)\$(MSBuildProjectName)\ + + + + DEBUG_LEVEL=DEBUG_LEVEL_INFO;_USRDLL;TINYMEDIA_EXPORTS;FLIP_ENCODED_PICT=1;FLIP_DECODED_PICT=1;%(PreprocessorDefinitions) + NotUsing + pch.h + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + ..\..\thirdparties\winrt\include;..\include;..\..\tinySAK\src;..\..\tinySDP\include;..\..\tinyNET\src + + + Console + false + false + true + "$(SolutionDir)$(Configuration)\tinySAK\tinySAK.lib";"$(SolutionDir)$(Configuration)\tinyNET\tinyNET.lib";"$(SolutionDir)$(Configuration)\tinySDP\tinySDP.lib";%(AdditionalDependencies) + + + + + DEBUG_LEVEL=DEBUG_LEVEL_INFO;_USRDLL;TINYMEDIA_EXPORTS;FLIP_ENCODED_PICT=1;FLIP_DECODED_PICT=1;%(PreprocessorDefinitions) + NotUsing + pch.h + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + ..\..\thirdparties\winrt\include;..\include;..\..\tinySAK\src;..\..\tinySDP\include;..\..\tinyNET\src + + + Console + false + false + true + "$(SolutionDir)$(Configuration)\tinySAK\tinySAK.lib";"$(SolutionDir)$(Configuration)\tinyNET\tinyNET.lib";"$(SolutionDir)$(Configuration)\tinySDP\tinySDP.lib";%(AdditionalDependencies) + + + + + DEBUG_LEVEL=DEBUG_LEVEL_INFO;_USRDLL;TINYMEDIA_EXPORTS;FLIP_ENCODED_PICT=1;FLIP_DECODED_PICT=1;%(PreprocessorDefinitions) + NotUsing + + + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + ..\..\thirdparties\winrt\include;..\include;..\..\tinySAK\src;..\..\tinySDP\include;..\..\tinyNET\src + + + Console + false + false + true + "$(SolutionDir)$(Configuration)\tinySAK\tinySAK.lib";"$(SolutionDir)$(Configuration)\tinyNET\tinyNET.lib";"$(SolutionDir)$(Configuration)\tinySDP\tinySDP.lib";%(AdditionalDependencies) + + + + + DEBUG_LEVEL=DEBUG_LEVEL_INFO;_USRDLL;TINYMEDIA_EXPORTS;FLIP_ENCODED_PICT=1;FLIP_DECODED_PICT=1;%(PreprocessorDefinitions) + NotUsing + pch.h + false + $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) + ..\..\thirdparties\winrt\include;..\include;..\..\tinySAK\src;..\..\tinySDP\include;..\..\tinyNET\src + + + Console + false + false + true + "$(SolutionDir)$(Configuration)\tinySAK\tinySAK.lib";"$(SolutionDir)$(Configuration)\tinyNET\tinyNET.lib";"$(SolutionDir)$(Configuration)\tinySDP\tinySDP.lib";%(AdditionalDependencies) + + + + + true + + + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {c89a9764-c625-4c3b-9980-30c97b440ea3} + + + {8f205ba6-84f7-4863-bd40-9d93b94228d5} + + + {1224fd1c-e1b6-4ced-94e1-03465211556c} + + + {c4c0550e-c464-4135-a8a5-502a39b79795} + + + {19e7973f-0178-4b2a-98e2-7b8f0f41672d} + + + + + include + + + include + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia + + + include\tinymedia\content + + + include\tinymedia\content + + + include\tinymedia\content + + + include\tinymedia\content + + + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src + + + src\content + + + src\content + + + src\content + + + src\content + + + \ No newline at end of file -- cgit v1.1