1 /*
2 mediastreamer2 library - modular sound and video processing and streaming
3 Copyright (C) 2014 Belledonne Communications SARL
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "mediastreamer-config.h"
22 #include "gitversion.h"
23 #endif
24 # ifndef MEDIASTREAMER_VERSION
25 # define MEDIASTREAMER_VERSION "unknown"
26 # endif
27 # ifndef MS2_GIT_VERSION
28 # define MS2_GIT_VERSION "unknown"
29 # endif
30
31 #include "mediastreamer2/msfilter.h"
32 #include "mediastreamer2/mseventqueue.h"
33 #include "basedescs.h"
34
35 #if !defined(_WIN32_WCE)
36 #include <sys/types.h>
37 #endif
38 #ifndef _WIN32
39 #include <dirent.h>
40 #else
41 #ifndef PACKAGE_PLUGINS_DIR
42 #if defined(_WIN32) || defined(_WIN32_WCE)
43 #ifdef MS2_WINDOWS_DESKTOP
44 #define PACKAGE_PLUGINS_DIR "lib\\mediastreamer\\plugins\\"
45 #else
46 #define PACKAGE_PLUGINS_DIR "."
47 #endif
48 #else
49 #define PACKAGE_PLUGINS_DIR "."
50 #endif
51 #endif
52 #endif
53
54 #ifndef PACKAGE_DATA_DIR
55 #define PACKAGE_DATA_DIR "share"
56 #endif
57
58 #ifdef HAVE_DLOPEN
59 #include <dlfcn.h>
60 #endif
61
62 #ifdef __APPLE__
63 #include "TargetConditionals.h"
64 #endif
65
66 #ifdef __QNX__
67 #include <sys/syspage.h>
68 #endif
69
70
71 MS2_DEPRECATED static MSFactory *fallback_factory=NULL;
72
73 static void ms_fmt_descriptor_destroy(MSFmtDescriptor *obj);
74
75 #define DEFAULT_MAX_PAYLOAD_SIZE 1440
76
ms_factory_get_payload_max_size(MSFactory * factory)77 int ms_factory_get_payload_max_size(MSFactory *factory){
78 return factory->max_payload_size;
79 }
80
ms_factory_set_payload_max_size(MSFactory * obj,int size)81 void ms_factory_set_payload_max_size(MSFactory *obj, int size){
82 if (size<=0) size=DEFAULT_MAX_PAYLOAD_SIZE;
83 obj->max_payload_size=size;
84 }
85
86 #define MS_MTU_DEFAULT 1500
87
ms_factory_set_mtu(MSFactory * obj,int mtu)88 void ms_factory_set_mtu(MSFactory *obj, int mtu){
89 /*60= IPv6+UDP+RTP overhead */
90 if (mtu>60){
91 obj->mtu=mtu;
92 ms_factory_set_payload_max_size(obj,mtu-60);
93 }else {
94 if (mtu>0){
95 ms_warning("MTU is too short: %i bytes, using default value instead.",mtu);
96 }
97 ms_factory_set_mtu(obj,MS_MTU_DEFAULT);
98 }
99 }
100
ms_factory_get_mtu(MSFactory * obj)101 int ms_factory_get_mtu(MSFactory *obj){
102 return obj->mtu;
103 }
104
ms_factory_set_echo_canceller_filter_name(MSFactory * obj,const char * filtername)105 void ms_factory_set_echo_canceller_filter_name(MSFactory *obj, const char *filtername) {
106 if (obj->echo_canceller_filtername != NULL) ms_free(obj->echo_canceller_filtername);
107 obj->echo_canceller_filtername = ms_strdup(filtername);
108 }
109
ms_factory_get_echo_canceller_filter_name(const MSFactory * obj)110 const char * ms_factory_get_echo_canceller_filter_name(const MSFactory *obj) {
111 return obj->echo_canceller_filtername;
112 }
113
ms_factory_get_cpu_count(MSFactory * obj)114 unsigned int ms_factory_get_cpu_count(MSFactory *obj) {
115 return obj->cpu_count;
116 }
117
ms_factory_set_cpu_count(MSFactory * obj,unsigned int c)118 void ms_factory_set_cpu_count(MSFactory *obj, unsigned int c) {
119 ms_message("CPU count set to %d", c);
120 obj->cpu_count = c;
121 }
122
ms_factory_add_platform_tag(MSFactory * obj,const char * tag)123 void ms_factory_add_platform_tag(MSFactory *obj, const char *tag) {
124 if ((tag == NULL) || (tag[0] == '\0')) return;
125 if (bctbx_list_find_custom(obj->platform_tags, (bctbx_compare_func)strcasecmp, tag) == NULL) {
126 obj->platform_tags = bctbx_list_append(obj->platform_tags, ms_strdup(tag));
127 }
128 }
129
ms_factory_get_platform_tags(MSFactory * obj)130 bctbx_list_t * ms_factory_get_platform_tags(MSFactory *obj) {
131 return obj->platform_tags;
132 }
133
ms_factory_get_platform_tags_as_string(MSFactory * obj)134 char * ms_factory_get_platform_tags_as_string(MSFactory *obj) {
135 return ms_tags_list_as_string(obj->platform_tags);
136 }
137
ms_factory_get_video_presets_manager(MSFactory * factory)138 struct _MSVideoPresetsManager * ms_factory_get_video_presets_manager(MSFactory *factory) {
139 return factory->video_presets_manager;
140 }
141
compare_stats_with_name(const MSFilterStats * stat,const char * name)142 static int compare_stats_with_name(const MSFilterStats *stat, const char *name){
143 return strcmp(stat->name,name);
144 }
145
find_or_create_stats(MSFactory * factory,MSFilterDesc * desc)146 static MSFilterStats *find_or_create_stats(MSFactory *factory, MSFilterDesc *desc){
147 bctbx_list_t *elem=bctbx_list_find_custom(factory->stats_list,(bctbx_compare_func)compare_stats_with_name,desc->name);
148 MSFilterStats *ret=NULL;
149 if (elem==NULL){
150 ret=ms_new0(MSFilterStats,1);
151 ret->name=desc->name;
152 factory->stats_list=bctbx_list_append(factory->stats_list,ret);
153 }else ret=(MSFilterStats*)elem->data;
154 return ret;
155 }
156
ms_factory_init(MSFactory * obj)157 void ms_factory_init(MSFactory *obj){
158 int i;
159 long num_cpu=1;
160 char *debug_log_enabled = NULL;
161 char *tags;
162 #ifdef _WIN32
163 SYSTEM_INFO sysinfo;
164 #endif
165
166 #if defined(ENABLE_NLS)
167 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
168 #endif
169 #ifndef MS2_WINDOWS_UNIVERSAL
170 debug_log_enabled=getenv("MEDIASTREAMER_DEBUG");
171 #endif
172 if (debug_log_enabled!=NULL && (strcmp("1",debug_log_enabled)==0) ){
173 ortp_set_log_level_mask(ORTP_LOG_DOMAIN, ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR|ORTP_FATAL);
174 }
175
176 ms_message("Mediastreamer2 factory " MEDIASTREAMER_VERSION " (git: " MS2_GIT_VERSION ") initialized.");
177 /* register builtin MSFilter's */
178 for (i=0;ms_base_filter_descs[i]!=NULL;i++){
179 ms_factory_register_filter(obj,ms_base_filter_descs[i]);
180 }
181
182 #ifdef _WIN32 /*fixme to be tested*/
183 GetNativeSystemInfo( &sysinfo );
184
185 num_cpu = sysinfo.dwNumberOfProcessors;
186 #elif __APPLE__ || __linux || __DragonFly__ || __FreeBSD__
187 num_cpu = sysconf( _SC_NPROCESSORS_CONF); /*check the number of processors configured, not just the one that are currently active.*/
188 #elif __QNX__
189 num_cpu = _syspage_ptr->num_cpu;
190 #else
191 #warning "There is no code that detects the number of CPU for this platform."
192 #endif
193 ms_factory_set_cpu_count(obj,num_cpu);
194 ms_factory_set_mtu(obj,MS_MTU_DEFAULT);
195 #ifdef _WIN32
196 ms_factory_add_platform_tag(obj, "win32");
197 #ifdef MS2_WINDOWS_PHONE
198 ms_factory_add_platform_tag(obj, "windowsphone");
199 #endif
200 #ifdef MS2_WINDOWS_UNIVERSAL
201 ms_factory_add_platform_tag(obj, "windowsuniversal");
202 #endif
203 #endif
204 #ifdef __APPLE__
205 ms_factory_add_platform_tag(obj, "apple");
206 #endif
207 #ifdef __linux
208 ms_factory_add_platform_tag(obj, "linux");
209 #endif
210 #ifdef __QNX__
211 ms_factory_add_platform_tag(obj, "qnx");
212 #endif
213 #ifdef __ANDROID__
214 ms_factory_add_platform_tag(obj, "android");
215 #endif
216 #ifdef TARGET_OS_IPHONE
217 ms_factory_add_platform_tag(obj, "ios");
218 #endif
219 #if defined(__arm__) || defined(_M_ARM)
220 ms_factory_add_platform_tag(obj, "arm");
221 #else
222 ms_factory_add_platform_tag(obj, "x86");
223 #endif
224 #if defined(__ANDROID__) || (TARGET_OS_IPHONE == 1) || defined(__arm__) || defined(_M_ARM)
225 ms_factory_add_platform_tag(obj, "embedded");
226 #else
227 ms_factory_add_platform_tag(obj, "desktop");
228 #endif
229 tags = ms_factory_get_platform_tags_as_string(obj);
230 ms_message("ms_factory_init() done: platform_tags=%s", tags);
231 ms_free(tags);
232 obj->echo_canceller_filtername = ms_strdup("MSWebRTCAECM");
233 obj->image_resources_dir = bctbx_strdup_printf("%s/images", PACKAGE_DATA_DIR);
234 }
235
236
237
ms_factory_new(void)238 MSFactory *ms_factory_new(void){
239 MSFactory *obj=ms_new0(MSFactory,1);
240 ms_factory_init(obj);
241 return obj;
242 }
243
244
ms_factory_register_filter(MSFactory * factory,MSFilterDesc * desc)245 void ms_factory_register_filter(MSFactory* factory, MSFilterDesc* desc ) {
246 if (desc->id==MS_FILTER_NOT_SET_ID){
247 ms_fatal("MSFilterId for %s not set !",desc->name);
248 }
249 desc->flags|=MS_FILTER_IS_ENABLED; /*by default a registered filter is enabled*/
250
251 /*lastly registered encoder/decoders may replace older ones*/
252 factory->desc_list=bctbx_list_prepend(factory->desc_list,desc);
253 }
254
ms_factory_codec_supported(MSFactory * factory,const char * mime)255 bool_t ms_factory_codec_supported(MSFactory* factory, const char *mime){
256 MSFilterDesc *enc = ms_factory_get_encoding_capturer(factory, mime);
257 MSFilterDesc *dec = ms_factory_get_decoding_renderer(factory, mime);
258
259 if (enc == NULL) enc = ms_factory_get_encoder(factory, mime);
260 if (dec == NULL) dec = ms_factory_get_decoder(factory, mime);
261
262 if(enc!=NULL && dec!=NULL) return TRUE;
263
264 if(enc==NULL) ms_message("Could not find encoder for %s", mime);
265 if(dec==NULL) ms_message("Could not find decoder for %s", mime);
266 return FALSE;
267 }
268
ms_factory_get_encoding_capturer(MSFactory * factory,const char * mime)269 MSFilterDesc * ms_factory_get_encoding_capturer(MSFactory* factory, const char *mime) {
270 bctbx_list_t *elem;
271
272 for (elem = factory->desc_list; elem != NULL; elem = bctbx_list_next(elem)) {
273 MSFilterDesc *desc = (MSFilterDesc *)elem->data;
274 if (desc->category == MS_FILTER_ENCODING_CAPTURER) {
275 char *saveptr=NULL;
276 char *enc_fmt = ms_strdup(desc->enc_fmt);
277 char *token = strtok_r(enc_fmt, " ", &saveptr);
278 while (token != NULL) {
279 if (strcasecmp(token, mime) == 0) {
280 break;
281 }
282 token = strtok_r(NULL, " ", &saveptr);
283 }
284 ms_free(enc_fmt);
285 if (token != NULL) return desc;
286 }
287 }
288 return NULL;
289 }
290
ms_factory_get_decoding_renderer(MSFactory * factory,const char * mime)291 MSFilterDesc * ms_factory_get_decoding_renderer(MSFactory* factory, const char *mime) {
292 bctbx_list_t *elem;
293
294 for (elem = factory->desc_list; elem != NULL; elem = bctbx_list_next(elem)) {
295 MSFilterDesc *desc = (MSFilterDesc *)elem->data;
296 if (desc->category == MS_FILTER_DECODER_RENDERER) {
297 char *saveptr=NULL;
298 char *enc_fmt = ms_strdup(desc->enc_fmt);
299 char *token = strtok_r(enc_fmt, " ", &saveptr);
300 while (token != NULL) {
301 if (strcasecmp(token, mime) == 0) {
302 break;
303 }
304 token = strtok_r(NULL, " ", &saveptr);
305 }
306 ms_free(enc_fmt);
307 if (token != NULL) return desc;
308 }
309 }
310 return NULL;
311 }
312
ms_factory_get_encoder(MSFactory * factory,const char * mime)313 MSFilterDesc * ms_factory_get_encoder(MSFactory* factory, const char *mime){
314 bctbx_list_t *elem;
315 for (elem=factory->desc_list;elem!=NULL;elem=bctbx_list_next(elem)){
316 MSFilterDesc *desc=(MSFilterDesc*)elem->data;
317 if ((desc->flags & MS_FILTER_IS_ENABLED)
318 && (desc->category==MS_FILTER_ENCODER || desc->category==MS_FILTER_ENCODING_CAPTURER)
319 && strcasecmp(desc->enc_fmt,mime)==0){
320 return desc;
321 }
322 }
323 return NULL;
324 }
325
ms_factory_get_decoder(MSFactory * factory,const char * mime)326 MSFilterDesc * ms_factory_get_decoder(MSFactory* factory, const char *mime){
327 bctbx_list_t *elem;
328 for (elem=factory->desc_list;elem!=NULL;elem=bctbx_list_next(elem)){
329 MSFilterDesc *desc=(MSFilterDesc*)elem->data;
330 if ((desc->flags & MS_FILTER_IS_ENABLED)
331 && (desc->category==MS_FILTER_DECODER || desc->category==MS_FILTER_DECODER_RENDERER)
332 && strcasecmp(desc->enc_fmt,mime)==0){
333 return desc;
334 }
335 }
336 return NULL;
337 }
338
ms_factory_create_encoder(MSFactory * factory,const char * mime)339 MSFilter * ms_factory_create_encoder(MSFactory* factory, const char *mime){
340 MSFilterDesc *desc=ms_factory_get_encoder(factory,mime);
341 if (desc!=NULL) return ms_factory_create_filter_from_desc(factory,desc);
342 return NULL;
343 }
344
ms_factory_create_decoder(MSFactory * factory,const char * mime)345 MSFilter * ms_factory_create_decoder(MSFactory* factory, const char *mime){
346 //MSFilterDesc *desc=ms_filter_get_decoder(mime);
347 MSFilterDesc *desc = ms_factory_get_decoder(factory, mime);
348 if (desc!=NULL) return ms_factory_create_filter_from_desc(factory,desc);
349 return NULL;
350 }
351
ms_factory_create_filter_from_desc(MSFactory * factory,MSFilterDesc * desc)352 MSFilter *ms_factory_create_filter_from_desc(MSFactory* factory, MSFilterDesc *desc){
353 MSFilter *obj;
354 obj=(MSFilter *)ms_new0(MSFilter,1);
355 ms_mutex_init(&obj->lock,NULL);
356 obj->desc=desc;
357 if (desc->ninputs>0) obj->inputs=(MSQueue**)ms_new0(MSQueue*,desc->ninputs);
358 if (desc->noutputs>0) obj->outputs=(MSQueue**)ms_new0(MSQueue*,desc->noutputs);
359
360 if (factory->statistics_enabled){
361 obj->stats=find_or_create_stats(factory,desc);
362 }
363 obj->factory=factory;
364 if (obj->desc->init!=NULL)
365 obj->desc->init(obj);
366 return obj;
367 }
368
ms_factory_get_snd_card_manager(MSFactory * factory)369 struct _MSSndCardManager* ms_factory_get_snd_card_manager(MSFactory *factory){
370 return factory->sndcardmanager;
371 }
372
ms_factory_get_web_cam_manager(MSFactory * f)373 struct _MSWebCamManager* ms_factory_get_web_cam_manager(MSFactory* f){
374 return f->wbcmanager;
375 }
376
ms_factory_create_filter(MSFactory * factory,MSFilterId id)377 MSFilter *ms_factory_create_filter(MSFactory* factory, MSFilterId id){
378 MSFilterDesc *desc;
379 if (id==MS_FILTER_PLUGIN_ID){
380 ms_warning("cannot create plugin filters with ms_filter_new_from_id()");
381 return NULL;
382 }
383 desc=ms_factory_lookup_filter_by_id(factory,id);
384 if (desc) return ms_factory_create_filter_from_desc(factory,desc);
385 ms_error("No such filter with id %i",id);
386 return NULL;
387 }
388
ms_factory_lookup_filter_by_name(const MSFactory * factory,const char * filter_name)389 MSFilterDesc *ms_factory_lookup_filter_by_name(const MSFactory* factory, const char *filter_name){
390 bctbx_list_t *elem;
391 for (elem=factory->desc_list;elem!=NULL;elem=bctbx_list_next(elem)){
392 MSFilterDesc *desc=(MSFilterDesc*)elem->data;
393 if (strcmp(desc->name,filter_name)==0){
394 return desc;
395 }
396 }
397 return NULL;
398 }
399
ms_factory_lookup_filter_by_id(MSFactory * factory,MSFilterId id)400 MSFilterDesc* ms_factory_lookup_filter_by_id( MSFactory* factory, MSFilterId id){
401 bctbx_list_t *elem;
402
403 for (elem=factory->desc_list;elem!=NULL;elem=bctbx_list_next(elem)){
404 MSFilterDesc *desc=(MSFilterDesc*)elem->data;
405 if (desc->id==id){
406 return desc;
407 }
408 }
409 return NULL;
410 }
411
ms_factory_lookup_filter_by_interface(MSFactory * factory,MSFilterInterfaceId id)412 bctbx_list_t *ms_factory_lookup_filter_by_interface(MSFactory* factory, MSFilterInterfaceId id){
413 bctbx_list_t *ret=NULL;
414 bctbx_list_t *elem;
415 for(elem=factory->desc_list;elem!=NULL;elem=elem->next){
416 MSFilterDesc *desc=(MSFilterDesc*)elem->data;
417 if (ms_filter_desc_implements_interface(desc,id))
418 ret=bctbx_list_append(ret,desc);
419 }
420 return ret;
421 }
422
ms_factory_create_filter_from_name(MSFactory * factory,const char * filter_name)423 MSFilter *ms_factory_create_filter_from_name(MSFactory* factory, const char *filter_name){
424 MSFilterDesc *desc=ms_factory_lookup_filter_by_name(factory, filter_name);
425 if (desc==NULL) return NULL;
426 return ms_factory_create_filter_from_desc(factory,desc);
427 }
428
ms_factory_enable_statistics(MSFactory * obj,bool_t enabled)429 void ms_factory_enable_statistics(MSFactory* obj, bool_t enabled){
430 obj->statistics_enabled=enabled;
431 }
432
ms_factory_get_statistics(MSFactory * obj)433 const bctbx_list_t * ms_factory_get_statistics(MSFactory* obj){
434 return obj->stats_list;
435 }
436
ms_factory_reset_statistics(MSFactory * obj)437 void ms_factory_reset_statistics(MSFactory *obj){
438 bctbx_list_t *elem;
439
440 for(elem=obj->stats_list;elem!=NULL;elem=elem->next){
441 MSFilterStats *stats=(MSFilterStats *)elem->data;
442 stats->elapsed=0;
443 stats->count=0;
444 }
445 }
446
usage_compare(const MSFilterStats * s1,const MSFilterStats * s2)447 static int usage_compare(const MSFilterStats *s1, const MSFilterStats *s2){
448 if (s1->elapsed==s2->elapsed) return 0;
449 if (s1->elapsed<s2->elapsed) return 1;
450 return -1;
451 }
452
453
ms_factory_log_statistics(MSFactory * obj)454 void ms_factory_log_statistics(MSFactory *obj){
455 bctbx_list_t *sorted=NULL;
456 bctbx_list_t *elem;
457 uint64_t total=1;
458 for(elem=obj->stats_list;elem!=NULL;elem=elem->next){
459 MSFilterStats *stats=(MSFilterStats *)elem->data;
460 sorted=bctbx_list_insert_sorted(sorted,stats,(bctbx_compare_func)usage_compare);
461 total+=stats->elapsed;
462 }
463 ms_message("===========================================================");
464 ms_message(" FILTER USAGE STATISTICS ");
465 ms_message("Name Count Time/tick (ms) CPU Usage");
466 ms_message("-----------------------------------------------------------");
467 for(elem=sorted;elem!=NULL;elem=elem->next){
468 MSFilterStats *stats=(MSFilterStats *)elem->data;
469 double percentage=100.0*((double)stats->elapsed)/(double)total;
470 double tpt=((double)stats->elapsed*1e-6)/((double)stats->count+1.0);
471 ms_message("%-19s %-9i %-19g %-10g",stats->name,stats->count,tpt,percentage);
472 }
473 ms_message("===========================================================");
474 bctbx_list_free(sorted);
475 }
476
477 #ifndef PLUGINS_EXT
478 #define PLUGINS_EXT ".so"
479 #endif
480 typedef void (*init_func_t)(MSFactory *);
481
ms_factory_load_plugins(MSFactory * factory,const char * dir)482 int ms_factory_load_plugins(MSFactory *factory, const char *dir){
483 int num=0;
484 #if defined(_WIN32) && !defined(_WIN32_WCE)
485 WIN32_FIND_DATA FileData;
486 HANDLE hSearch;
487 char szDirPath[1024];
488 #ifdef UNICODE
489 wchar_t wszDirPath[1024];
490 #endif
491 char szPluginFile[1024];
492 BOOL fFinished = FALSE;
493 const char *tmp = NULL;
494 BOOL debug = FALSE;
495 #ifndef MS2_WINDOWS_UNIVERSAL
496 tmp = getenv("DEBUG");
497 #endif
498 debug = (tmp != NULL && atoi(tmp) == 1);
499
500 snprintf(szDirPath, sizeof(szDirPath), "%s", dir);
501
502 // Start searching for .dll files in the current directory.
503 snprintf(szDirPath, sizeof(szDirPath), "%s\\libms*.dll", dir);
504 #ifdef UNICODE
505 mbstowcs(wszDirPath, szDirPath, sizeof(wszDirPath));
506 hSearch = FindFirstFileExW(wszDirPath, FindExInfoStandard, &FileData, FindExSearchNameMatch, NULL, 0);
507 #else
508 hSearch = FindFirstFileExA(szDirPath, FindExInfoStandard, &FileData, FindExSearchNameMatch, NULL, 0);
509 #endif
510 if (hSearch == INVALID_HANDLE_VALUE)
511 {
512 ms_message("no plugin (*.dll) found in [%s] [%d].", szDirPath, (int)GetLastError());
513 return 0;
514 }
515 snprintf(szDirPath, sizeof(szDirPath), "%s", dir);
516
517 while (!fFinished)
518 {
519 /* load library */
520 #ifdef MS2_WINDOWS_DESKTOP
521 UINT em=0;
522 #endif
523 HINSTANCE os_handle;
524 #ifdef UNICODE
525 wchar_t wszPluginFile[2048];
526 char filename[512];
527 wcstombs(filename, FileData.cFileName, sizeof(filename));
528 snprintf(szPluginFile, sizeof(szPluginFile), "%s\\%s", szDirPath, filename);
529 mbstowcs(wszPluginFile, szPluginFile, sizeof(wszPluginFile));
530 #else
531 snprintf(szPluginFile, sizeof(szPluginFile), "%s\\%s", szDirPath, FileData.cFileName);
532 #endif
533 #ifdef MS2_WINDOWS_DESKTOP
534 if (!debug) em = SetErrorMode (SEM_FAILCRITICALERRORS);
535
536 #ifdef UNICODE
537 os_handle = LoadLibraryExW(wszPluginFile, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
538 #else
539 os_handle = LoadLibraryExA(szPluginFile, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
540 #endif
541 if (os_handle==NULL)
542 {
543 ms_message("Fail to load plugin %s with altered search path: error %i",szPluginFile,(int)GetLastError());
544 #ifdef UNICODE
545 os_handle = LoadLibraryExW(wszPluginFile, NULL, 0);
546 #else
547 os_handle = LoadLibraryExA(szPluginFile, NULL, 0);
548 #endif
549 }
550 if (!debug) SetErrorMode (em);
551 #else
552 os_handle = LoadPackagedLibrary(wszPluginFile, 0);
553 #endif
554 if (os_handle==NULL)
555 ms_error("Fail to load plugin %s: error %i", szPluginFile, (int)GetLastError());
556 else{
557 init_func_t initroutine;
558 char szPluginName[256];
559 char szMethodName[256];
560 char *minus;
561 #ifdef UNICODE
562 snprintf(szPluginName, sizeof(szPluginName), "%s", filename);
563 #else
564 snprintf(szPluginName, sizeof(szPluginName), "%s", FileData.cFileName);
565 #endif
566 /*on mingw, dll names might be libsomething-3.dll. We must skip the -X.dll stuff*/
567 minus=strchr(szPluginName,'-');
568 if (minus) *minus='\0';
569 else szPluginName[strlen(szPluginName)-4]='\0'; /*remove .dll*/
570 snprintf(szMethodName, sizeof(szMethodName), "%s_init", szPluginName);
571 initroutine = (init_func_t) GetProcAddress (os_handle, szMethodName);
572 if (initroutine!=NULL){
573 initroutine(factory);
574 ms_message("Plugin loaded (%s)", szPluginFile);
575 // Add this new loaded plugin to the list (useful for FreeLibrary at the end)
576 factory->ms_plugins_loaded_list=bctbx_list_append(factory->ms_plugins_loaded_list,os_handle);
577 num++;
578 }else{
579 ms_warning("Could not locate init routine of plugin %s. Should be %s",
580 szPluginFile, szMethodName);
581 }
582 }
583 if (!FindNextFile(hSearch, &FileData)) {
584 if (GetLastError() == ERROR_NO_MORE_FILES){
585 fFinished = TRUE;
586 }
587 else
588 {
589 ms_error("couldn't find next plugin dll.");
590 fFinished = TRUE;
591 }
592 }
593 }
594 /* Close the search handle. */
595 FindClose(hSearch);
596
597 #elif defined(HAVE_DLOPEN)
598 char plugin_name[64];
599 DIR *ds;
600 bctbx_list_t *loaded_plugins = NULL;
601 struct dirent *de;
602 char *ext;
603 char *fullpath;
604 ds=opendir(dir);
605 if (ds==NULL){
606 ms_message("Cannot open directory %s: %s",dir,strerror(errno));
607 return -1;
608 }
609 while( (de=readdir(ds))!=NULL){
610 if (
611 #ifndef __QNX__
612 (de->d_type==DT_REG || de->d_type==DT_UNKNOWN || de->d_type==DT_LNK) &&
613 #endif
614 (strstr(de->d_name, "libms") == de->d_name) && ((ext=strstr(de->d_name,PLUGINS_EXT))!=NULL)) {
615 void *handle;
616 snprintf(plugin_name, MIN(sizeof(plugin_name), (size_t)(ext - de->d_name + 1)), "%s", de->d_name);
617 if (bctbx_list_find_custom(loaded_plugins, (bctbx_compare_func)strcmp, plugin_name) != NULL) continue;
618 loaded_plugins = bctbx_list_append(loaded_plugins, ms_strdup(plugin_name));
619 fullpath=ms_strdup_printf("%s/%s",dir,de->d_name);
620 ms_message("Loading plugin %s...",fullpath);
621
622 if ( (handle=dlopen(fullpath,RTLD_NOW))==NULL){
623 ms_warning("Fail to load plugin %s : %s",fullpath,dlerror());
624 }else {
625 char *initroutine_name=ms_malloc0(strlen(de->d_name)+10);
626 char *p;
627 void *initroutine=NULL;
628 strcpy(initroutine_name,de->d_name);
629 p=strstr(initroutine_name,PLUGINS_EXT);
630 if (p!=NULL){
631 strcpy(p,"_init");
632 initroutine=dlsym(handle,initroutine_name);
633 }
634
635 #ifdef __APPLE__
636 if (initroutine==NULL){
637 /* on macosx: library name are libxxxx.1.2.3.dylib */
638 /* -> MUST remove the .1.2.3 */
639 p=strstr(initroutine_name,".");
640 if (p!=NULL)
641 {
642 strcpy(p,"_init");
643 initroutine=dlsym(handle,initroutine_name);
644 }
645 }
646 #endif
647
648 if (initroutine!=NULL){
649 init_func_t func=(init_func_t)initroutine;
650 func(factory);
651 ms_message("Plugin loaded (%s)", fullpath);
652 num++;
653 }else{
654 ms_warning("Could not locate init routine of plugin %s",de->d_name);
655 }
656 ms_free(initroutine_name);
657 }
658 ms_free(fullpath);
659 }
660 }
661 bctbx_list_for_each(loaded_plugins, ms_free);
662 bctbx_list_free(loaded_plugins);
663 closedir(ds);
664 #else
665 ms_warning("no loadable plugin support: plugins cannot be loaded.");
666 num=-1;
667 #endif
668 return num;
669 }
670
ms_factory_uninit_plugins(MSFactory * factory)671 void ms_factory_uninit_plugins(MSFactory *factory){
672 #if defined(_WIN32)
673 bctbx_list_t *elem;
674 #endif
675
676 #if defined(_WIN32)
677 for(elem=factory->ms_plugins_loaded_list;elem!=NULL;elem=elem->next)
678 {
679 HINSTANCE handle=(HINSTANCE )elem->data;
680 FreeLibrary(handle) ;
681 }
682
683 factory->ms_plugins_loaded_list = bctbx_list_free(factory->ms_plugins_loaded_list);
684 #endif
685 }
686
ms_factory_init_plugins(MSFactory * obj)687 void ms_factory_init_plugins(MSFactory *obj) {
688 if (obj->plugins_dir == NULL) {
689 #ifdef PACKAGE_PLUGINS_DIR
690 obj->plugins_dir = ms_strdup(PACKAGE_PLUGINS_DIR);
691 #else
692 obj->plugins_dir = ms_strdup("");
693 #endif
694 }
695 if (strlen(obj->plugins_dir) > 0) {
696 ms_message("Loading ms plugins from [%s]",obj->plugins_dir);
697 ms_factory_load_plugins(obj,obj->plugins_dir);
698 }
699 }
700
ms_factory_set_plugins_dir(MSFactory * obj,const char * path)701 void ms_factory_set_plugins_dir(MSFactory *obj, const char *path) {
702 if (obj->plugins_dir != NULL) {
703 ms_free(obj->plugins_dir);
704 obj->plugins_dir=NULL;
705 }
706 if (path)
707 obj->plugins_dir = ms_strdup(path);
708 }
709
ms_factory_create_event_queue(MSFactory * obj)710 struct _MSEventQueue *ms_factory_create_event_queue(MSFactory *obj) {
711 if (obj->evq==NULL){
712 obj->evq=ms_event_queue_new();
713 }
714 return obj->evq;
715 }
716
ms_factory_destroy_event_queue(MSFactory * obj)717 void ms_factory_destroy_event_queue(MSFactory *obj) {
718 if (obj->image_resources_dir) bctbx_free(obj->image_resources_dir);
719 ms_event_queue_destroy(obj->evq);
720 ms_factory_set_event_queue(obj,NULL);
721 }
722
723
ms_factory_get_event_queue(MSFactory * obj)724 struct _MSEventQueue *ms_factory_get_event_queue(MSFactory *obj){
725 return obj->evq;
726 }
727
728 /*this function is for compatibility, when event queues were created by the application*/
ms_factory_set_event_queue(MSFactory * obj,MSEventQueue * evq)729 void ms_factory_set_event_queue(MSFactory *obj, MSEventQueue *evq){
730 obj->evq=evq;
731 }
732
compare_fmt(const MSFmtDescriptor * a,const MSFmtDescriptor * b)733 static int compare_fmt(const MSFmtDescriptor *a, const MSFmtDescriptor *b){
734 if (a->type!=b->type) return -1;
735 if (strcasecmp(a->encoding,b->encoding)!=0) return -1;
736 if (a->rate!=b->rate) return -1;
737 if (a->nchannels!=b->nchannels) return -1;
738 if (a->fmtp==NULL && b->fmtp!=NULL) return -1;
739 if (a->fmtp!=NULL && b->fmtp==NULL) return -1;
740 if (a->fmtp && b->fmtp && strcmp(a->fmtp,b->fmtp)!=0) return -1;
741 if (a->type==MSVideo){
742 if (a->vsize.width!=b->vsize.width || a->vsize.height!=b->vsize.height) return -1;
743 if (a->fps!=b->fps) return -1;
744 }
745 return 0;
746 }
747
ms_fmt_descriptor_new_copy(const MSFmtDescriptor * orig)748 static MSFmtDescriptor * ms_fmt_descriptor_new_copy(const MSFmtDescriptor *orig){
749 MSFmtDescriptor *obj=ms_new0(MSFmtDescriptor,1);
750 obj->type=orig->type;
751 obj->rate=orig->rate;
752 obj->nchannels=orig->nchannels;
753 if (orig->fmtp) obj->fmtp=ms_strdup(orig->fmtp);
754 if (orig->encoding) obj->encoding=ms_strdup(orig->encoding);
755 obj->vsize=orig->vsize;
756 obj->fps=orig->fps;
757 return obj;
758 }
759
ms_fmt_descriptor_to_string(const MSFmtDescriptor * obj)760 const char *ms_fmt_descriptor_to_string(const MSFmtDescriptor *obj){
761 MSFmtDescriptor *mutable_fmt=(MSFmtDescriptor*)obj;
762 if (!obj) return "null";
763 if (obj->text==NULL){
764 if (obj->type==MSAudio){
765 mutable_fmt->text=ms_strdup_printf("type=audio;encoding=%s;rate=%i;channels=%i;fmtp='%s'",
766 obj->encoding,obj->rate,obj->nchannels,obj->fmtp ? obj->fmtp : "");
767 }else{
768 mutable_fmt->text=ms_strdup_printf("type=video;encoding=%s;vsize=%ix%i;fps=%f;fmtp='%s'",
769 obj->encoding,obj->vsize.width,obj->vsize.height,obj->fps,obj->fmtp ? obj->fmtp : "");
770 }
771 }
772 return obj->text;
773 }
774
ms_fmt_descriptor_equals(const MSFmtDescriptor * fmt1,const MSFmtDescriptor * fmt2)775 bool_t ms_fmt_descriptor_equals(const MSFmtDescriptor *fmt1, const MSFmtDescriptor *fmt2) {
776 if (!fmt1 || !fmt2) return FALSE;
777 return compare_fmt(fmt1, fmt2) == 0;
778 }
779
ms_fmt_descriptor_destroy(MSFmtDescriptor * obj)780 static void ms_fmt_descriptor_destroy(MSFmtDescriptor *obj){
781 if (obj->encoding) ms_free(obj->encoding);
782 if (obj->fmtp) ms_free(obj->fmtp);
783 if (obj->text) ms_free(obj->text);
784 ms_free(obj);
785 }
786
ms_factory_get_format(MSFactory * obj,const MSFmtDescriptor * ref)787 const MSFmtDescriptor *ms_factory_get_format(MSFactory *obj, const MSFmtDescriptor *ref){
788 MSFmtDescriptor *ret;
789 bctbx_list_t *found;
790 if ((found=bctbx_list_find_custom(obj->formats,(int (*)(const void*, const void*))compare_fmt, ref))==NULL){
791 obj->formats=bctbx_list_append(obj->formats,ret=ms_fmt_descriptor_new_copy(ref));
792 }else{
793 ret=(MSFmtDescriptor *)found->data;
794 }
795 return ret;
796 }
797
ms_factory_get_audio_format(MSFactory * obj,const char * mime,int rate,int channels,const char * fmtp)798 const MSFmtDescriptor * ms_factory_get_audio_format(MSFactory *obj, const char *mime, int rate, int channels, const char *fmtp){
799 MSFmtDescriptor tmp={0};
800 tmp.type=MSAudio;
801 tmp.encoding=(char*)mime;
802 tmp.rate=rate;
803 tmp.nchannels=channels;
804 tmp.fmtp=(char*)fmtp;
805 return ms_factory_get_format(obj,&tmp);
806 }
807
ms_factory_get_video_format(MSFactory * obj,const char * mime,MSVideoSize size,float fps,const char * fmtp)808 const MSFmtDescriptor * ms_factory_get_video_format(MSFactory *obj, const char *mime, MSVideoSize size, float fps, const char *fmtp){
809 MSFmtDescriptor tmp={0};
810 tmp.type=MSVideo;
811 tmp.encoding=(char*)mime;
812 tmp.rate=90000;
813 tmp.vsize=size;
814 tmp.fmtp=(char*)fmtp;
815 tmp.fps=fps;
816 return ms_factory_get_format(obj,&tmp);
817 }
818
ms_factory_enable_filter_from_name(MSFactory * factory,const char * name,bool_t enable)819 int ms_factory_enable_filter_from_name(MSFactory *factory, const char *name, bool_t enable) {
820 MSFilterDesc *desc=ms_factory_lookup_filter_by_name(factory,name);
821 if (!desc) {
822 ms_error("Cannot enable/disable unknown filter [%s] on factory [%p]",name,factory);
823 return -1;
824 }
825 if (enable) desc->flags |= MS_FILTER_IS_ENABLED;
826 else desc->flags &= ~MS_FILTER_IS_ENABLED;
827 ms_message("Filter [%s] %s on factory [%p]",name,(enable ? "enabled" : "disabled"),factory);
828 return 0;
829 }
830
ms_factory_filter_from_name_enabled(const MSFactory * factory,const char * name)831 bool_t ms_factory_filter_from_name_enabled(const MSFactory *factory, const char *name) {
832 MSFilterDesc *desc=ms_factory_lookup_filter_by_name(factory,name);
833 if (!desc) {
834 ms_error("Cannot get enable/disable state for unknown filter [%s] on factory [%p]",name,factory);
835 return FALSE;
836 }
837 return !!(desc->flags & MS_FILTER_IS_ENABLED);
838 }
839
840
ms_factory_register_offer_answer_provider(MSFactory * f,MSOfferAnswerProvider * offer_answer_prov)841 void ms_factory_register_offer_answer_provider(MSFactory *f, MSOfferAnswerProvider *offer_answer_prov){
842 if (bctbx_list_find(f->offer_answer_provider_list, offer_answer_prov)) return; /*avoid registering several time the same pointer*/
843 f->offer_answer_provider_list = bctbx_list_prepend(f->offer_answer_provider_list, offer_answer_prov);
844 }
845
ms_factory_get_offer_answer_provider(MSFactory * f,const char * mime_type)846 MSOfferAnswerProvider * ms_factory_get_offer_answer_provider(MSFactory *f, const char *mime_type){
847 const bctbx_list_t *elem;
848 for (elem = f->offer_answer_provider_list; elem != NULL; elem = elem->next){
849 MSOfferAnswerProvider *prov = (MSOfferAnswerProvider*) elem->data;
850 if (strcasecmp(mime_type, prov->mime_type) == 0)
851 return prov;
852 }
853 return NULL;
854 }
855
ms_factory_create_offer_answer_context(MSFactory * f,const char * mime_type)856 MSOfferAnswerContext * ms_factory_create_offer_answer_context(MSFactory *f, const char *mime_type){
857 MSOfferAnswerProvider *prov = ms_factory_get_offer_answer_provider(f, mime_type);
858 if (prov) return prov->create_context();
859 return NULL;
860 }
861
ms_factory_get_devices_info(MSFactory * f)862 MSDevicesInfo* ms_factory_get_devices_info(MSFactory *f) {
863 return f->devices_info;
864 }
865
ms_factory_get_image_resources_dir(const MSFactory * f)866 const char * ms_factory_get_image_resources_dir(const MSFactory *f) {
867 return f->image_resources_dir;
868 }
869
ms_factory_set_image_resources_dir(MSFactory * f,const char * path)870 void ms_factory_set_image_resources_dir(MSFactory *f, const char *path) {
871 if (f->image_resources_dir) {
872 bctbx_free(f->image_resources_dir);
873 f->image_resources_dir = NULL;
874 }
875 if (path)
876 f->image_resources_dir = bctbx_strdup(path);
877 }
878
ms_factory_set_expected_bandwidth(MSFactory * f,int bitrate)879 void ms_factory_set_expected_bandwidth(MSFactory *f, int bitrate) {
880 f->expected_video_bandwidth = bitrate;
881 }
882
ms_factory_get_expected_bandwidth(MSFactory * f)883 int ms_factory_get_expected_bandwidth(MSFactory *f) {
884 return f->expected_video_bandwidth;
885 }
886
887 #ifdef __ANDROID__
888 #include "sys/system_properties.h"
889 #include <jni.h>
890
891
892 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
893
Java_org_linphone_mediastream_Factory_enableFilterFromName(JNIEnv * env,jobject obj,jlong factoryPtr,jstring jname,jboolean enable)894 JNIEXPORT jint JNICALL Java_org_linphone_mediastream_Factory_enableFilterFromName(JNIEnv* env, jobject obj, jlong factoryPtr, jstring jname, jboolean enable) {
895 MSFactory *factory = (MSFactory *) factoryPtr;
896 const char *name = jname ? (*env)->GetStringUTFChars(env, jname, NULL) : NULL;
897 int result = ms_factory_enable_filter_from_name(factory, name, enable);
898 (*env)->ReleaseStringUTFChars(env, jname, name);
899 return result;
900 }
Java_org_linphone_mediastream_Factory_filterFromNameEnabled(JNIEnv * env,jobject obj,jlong factoryPtr,jstring jname)901 JNIEXPORT jboolean JNICALL Java_org_linphone_mediastream_Factory_filterFromNameEnabled(JNIEnv* env, jobject obj, jlong factoryPtr, jstring jname) {
902 const char *name = jname ? (*env)->GetStringUTFChars(env, jname, NULL) : NULL;
903 MSFactory *factory = (MSFactory *) factoryPtr;
904 jboolean result = ms_factory_filter_from_name_enabled(factory, name);
905 (*env)->ReleaseStringUTFChars(env, jname, name);
906 return result;
907 }
908
909
Java_org_linphone_mediastream_Factory_getEncoderText(JNIEnv * env,jobject obj,jlong factoryPtr,jstring jmime)910 JNIEXPORT jstring JNICALL Java_org_linphone_mediastream_Factory_getEncoderText(JNIEnv* env, jobject obj,
911 jlong factoryPtr, jstring jmime) {
912 MSFactory *factory = (MSFactory*)factoryPtr;
913 const char *mime = (*env)->GetStringUTFChars(env, jmime, NULL);
914 jstring jtext = NULL;
915 if (mime){
916 MSFilterDesc *desc = ms_factory_get_encoder(factory, mime);
917 if (desc) jtext =(*env)->NewStringUTF(env, desc->text);
918 (*env)->ReleaseStringUTFChars(env, jmime, mime);
919 }
920 return jtext;
921 }
922
Java_org_linphone_mediastream_Factory_getDecoderText(JNIEnv * env,jobject obj,jlong factoryPtr,jstring jmime)923 JNIEXPORT jstring JNICALL Java_org_linphone_mediastream_Factory_getDecoderText(JNIEnv* env, jobject obj,
924 jlong factoryPtr, jstring jmime) {
925 MSFactory *factory = (MSFactory*)factoryPtr;
926 const char *mime = (*env)->GetStringUTFChars(env, jmime, NULL);
927 jstring jtext = NULL;
928 if (mime){
929 MSFilterDesc *desc = ms_factory_get_decoder(factory, mime);
930 if (desc) jtext = (*env)->NewStringUTF(env, desc->text);
931 (*env)->ReleaseStringUTFChars(env, jmime, mime);
932 }
933 return jtext;
934 }
935
936 #ifdef _MSC_VER
937 #pragma warning(disable : 4996)
938 #else
939 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
940 #endif
941
Java_org_linphone_mediastream_MediastreamerAndroidContext_enableFilterFromNameImpl(JNIEnv * env,jobject obj,jstring jname,jboolean enable)942 JNIEXPORT jint JNICALL Java_org_linphone_mediastream_MediastreamerAndroidContext_enableFilterFromNameImpl(JNIEnv* env, jobject obj, jstring jname, jboolean enable) {
943 const char *mime;
944 int result;
945 if (ms_factory_get_fallback() == NULL) {
946 ms_error("Java_org_linphone_mediastream_MediastreamerAndroidContext_enableFilterFromNameImpl(): no fallback factory. Use Factory.enableFilterFromName()");
947 return -1;
948 }
949 mime = jname ? (*env)->GetStringUTFChars(env, jname, NULL) : NULL;
950 result = ms_factory_enable_filter_from_name(ms_factory_get_fallback(),mime,enable);
951 (*env)->ReleaseStringUTFChars(env, jname, mime);
952 return result;
953 }
Java_org_linphone_mediastream_MediastreamerAndroidContext_filterFromNameEnabledImpl(JNIEnv * env,jobject obj,jstring jname)954 JNIEXPORT jboolean JNICALL Java_org_linphone_mediastream_MediastreamerAndroidContext_filterFromNameEnabledImpl(JNIEnv* env, jobject obj, jstring jname) {
955 const char *mime;
956 jboolean result;
957 if (ms_factory_get_fallback() == NULL) {
958 ms_error("Java_org_linphone_mediastream_MediastreamerAndroidContext_filterFromNameEnabledImpl(): no fallback factory. Use Factory.filterFromNameEnabled()");
959 return FALSE;
960 }
961 mime = jname ? (*env)->GetStringUTFChars(env, jname, NULL) : NULL;
962 result = ms_factory_filter_from_name_enabled(ms_factory_get_fallback(),mime);
963 (*env)->ReleaseStringUTFChars(env, jname, mime);
964 return result;
965 }
966
967 #endif
968
969
970
971 #ifdef _MSC_VER
972 #pragma warning(disable : 4996)
973 #else
974 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
975 #endif
976
977 /**
978 * Destroy the factory.
979 * This should be done after destroying all objects created by the factory.
980 **/
ms_factory_destroy(MSFactory * factory)981 void ms_factory_destroy(MSFactory *factory) {
982 if (factory->voip_uninit_func) factory->voip_uninit_func(factory);
983 ms_factory_uninit_plugins(factory);
984 if (factory->evq) ms_factory_destroy_event_queue(factory);
985 factory->formats = bctbx_list_free_with_data(factory->formats, (void(*)(void*))ms_fmt_descriptor_destroy);
986 factory->desc_list = bctbx_list_free(factory->desc_list);
987 bctbx_list_for_each(factory->stats_list, ms_free);
988 factory->stats_list = bctbx_list_free(factory->stats_list);
989 factory->offer_answer_provider_list = bctbx_list_free(factory->offer_answer_provider_list);
990 bctbx_list_for_each(factory->platform_tags, ms_free);
991 factory->platform_tags = bctbx_list_free(factory->platform_tags);
992 if (factory->echo_canceller_filtername) ms_free(factory->echo_canceller_filtername);
993 if (factory->plugins_dir) ms_free(factory->plugins_dir);
994 ms_free(factory);
995 if (factory == fallback_factory) fallback_factory = NULL;
996 }
997
998
ms_factory_create_fallback(void)999 MSFactory *ms_factory_create_fallback(void){
1000 if (fallback_factory==NULL){
1001 fallback_factory=ms_factory_new();
1002 }
1003 return fallback_factory;
1004 }
1005
1006 /**
1007 * Used by the legacy functions before MSFactory was added.
1008 * Do not use in an application.
1009 **/
ms_factory_get_fallback(void)1010 MSFactory *ms_factory_get_fallback(void){
1011 return fallback_factory;
1012 }
1013
1014
1015