msfactory.c 31.2 KB
Newer Older
Simon Morlat's avatar
Simon Morlat committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2014  Belledonne Communications SARL

This program 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 2
of the License, or (at your option) any later version.

This program 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 this program; if not, write to the Free Software
17
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Simon Morlat's avatar
Simon Morlat committed
18 19 20 21 22 23 24 25 26
*/

#ifdef HAVE_CONFIG_H
#include "mediastreamer-config.h"
#include "gitversion.h"
#else
#   ifndef MEDIASTREAMER_VERSION
#   define MEDIASTREAMER_VERSION "unknown"
#   endif
27 28 29 30
#endif

#ifndef MS2_GIT_VERSION
#define MS2_GIT_VERSION "unknown"
Simon Morlat's avatar
Simon Morlat committed
31 32 33 34 35 36 37 38 39
#endif

#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/mseventqueue.h"
#include "basedescs.h"

#if !defined(_WIN32_WCE)
#include <sys/types.h>
#endif
40
#ifndef _WIN32
Simon Morlat's avatar
Simon Morlat committed
41 42 43
#include <dirent.h>
#else
#ifndef PACKAGE_PLUGINS_DIR
44 45
#if defined(_WIN32) || defined(_WIN32_WCE)
#ifdef MS2_WINDOWS_DESKTOP
Simon Morlat's avatar
Simon Morlat committed
46 47 48 49
#define PACKAGE_PLUGINS_DIR "lib\\mediastreamer\\plugins\\"
#else
#define PACKAGE_PLUGINS_DIR "."
#endif
50 51 52
#else
#define PACKAGE_PLUGINS_DIR "."
#endif
Simon Morlat's avatar
Simon Morlat committed
53 54
#endif
#endif
55 56 57 58 59

#ifndef PACKAGE_DATA_DIR
#define PACKAGE_DATA_DIR "share"
#endif

Simon Morlat's avatar
Simon Morlat committed
60 61 62 63 64 65 66 67 68 69 70 71 72
#ifdef HAVE_DLOPEN
#include <dlfcn.h>
#endif

#ifdef __APPLE__
   #include "TargetConditionals.h"
#endif

#ifdef __QNX__
#include <sys/syspage.h>
#endif


73
MS2_DEPRECATED static MSFactory *fallback_factory=NULL;
Simon Morlat's avatar
Simon Morlat committed
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106

static void ms_fmt_descriptor_destroy(MSFmtDescriptor *obj);

#define DEFAULT_MAX_PAYLOAD_SIZE 1440

int ms_factory_get_payload_max_size(MSFactory *factory){
	return factory->max_payload_size;
}

void ms_factory_set_payload_max_size(MSFactory *obj, int size){
	if (size<=0) size=DEFAULT_MAX_PAYLOAD_SIZE;
	obj->max_payload_size=size;
}

#define MS_MTU_DEFAULT 1500

void ms_factory_set_mtu(MSFactory *obj, int mtu){
	/*60= IPv6+UDP+RTP overhead */
	if (mtu>60){
		obj->mtu=mtu;
		ms_factory_set_payload_max_size(obj,mtu-60);
	}else {
		if (mtu>0){
			ms_warning("MTU is too short: %i bytes, using default value instead.",mtu);
		}
		ms_factory_set_mtu(obj,MS_MTU_DEFAULT);
	}
}

int ms_factory_get_mtu(MSFactory *obj){
	return obj->mtu;
}

107 108 109 110 111 112 113 114 115
void ms_factory_set_echo_canceller_filter_name(MSFactory *obj, const char *filtername) {
	if (obj->echo_canceller_filtername != NULL) ms_free(obj->echo_canceller_filtername);
	obj->echo_canceller_filtername = ms_strdup(filtername);
}

const char * ms_factory_get_echo_canceller_filter_name(const MSFactory *obj) {
	return obj->echo_canceller_filtername;
}

Simon Morlat's avatar
Simon Morlat committed
116 117 118 119 120 121 122 123 124
unsigned int ms_factory_get_cpu_count(MSFactory *obj) {
	return obj->cpu_count;
}

void ms_factory_set_cpu_count(MSFactory *obj, unsigned int c) {
	ms_message("CPU count set to %d", c);
	obj->cpu_count = c;
}

125
void ms_factory_add_platform_tag(MSFactory *obj, const char *tag) {
Ghislain MARY's avatar
Ghislain MARY committed
126
	if ((tag == NULL) || (tag[0] == '\0')) return;
127 128
	if (bctbx_list_find_custom(obj->platform_tags, (bctbx_compare_func)strcasecmp, tag) == NULL) {
		obj->platform_tags = bctbx_list_append(obj->platform_tags, ms_strdup(tag));
129 130 131
	}
}

132
bctbx_list_t * ms_factory_get_platform_tags(MSFactory *obj) {
133 134 135 136
	return obj->platform_tags;
}

char * ms_factory_get_platform_tags_as_string(MSFactory *obj) {
137 138 139 140 141
	return ms_tags_list_as_string(obj->platform_tags);
}

struct _MSVideoPresetsManager * ms_factory_get_video_presets_manager(MSFactory *factory) {
	return factory->video_presets_manager;
142 143
}

Simon Morlat's avatar
Simon Morlat committed
144 145 146 147 148
static int compare_stats_with_name(const MSFilterStats *stat, const char *name){
	return strcmp(stat->name,name);
}

static MSFilterStats *find_or_create_stats(MSFactory *factory, MSFilterDesc *desc){
149
	bctbx_list_t *elem=bctbx_list_find_custom(factory->stats_list,(bctbx_compare_func)compare_stats_with_name,desc->name);
Simon Morlat's avatar
Simon Morlat committed
150 151 152 153
	MSFilterStats *ret=NULL;
	if (elem==NULL){
		ret=ms_new0(MSFilterStats,1);
		ret->name=desc->name;
154
		factory->stats_list=bctbx_list_append(factory->stats_list,ret);
Simon Morlat's avatar
Simon Morlat committed
155 156 157 158 159 160 161
	}else ret=(MSFilterStats*)elem->data;
	return ret;
}

void ms_factory_init(MSFactory *obj){
	int i;
	long num_cpu=1;
162
	char *debug_log_enabled = NULL;
163
	char *tags;
164
#ifdef _WIN32
Simon Morlat's avatar
Simon Morlat committed
165 166 167 168 169 170
	SYSTEM_INFO sysinfo;
#endif

#if defined(ENABLE_NLS)
	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
#endif
171
#ifndef MS2_WINDOWS_UNIVERSAL
172
	debug_log_enabled=getenv("MEDIASTREAMER_DEBUG");
173
#endif
174
	if (debug_log_enabled!=NULL && (strcmp("1",debug_log_enabled)==0) ){
175
		bctbx_set_log_level(BCTBX_LOG_DOMAIN, BCTBX_LOG_MESSAGE);
Simon Morlat's avatar
Simon Morlat committed
176 177
	}

178
	ms_message("Mediastreamer2 factory " MEDIASTREAMER_VERSION " (git: " MS2_GIT_VERSION ") initialized.");
Simon Morlat's avatar
Simon Morlat committed
179 180 181 182 183
	/* register builtin MSFilter's */
	for (i=0;ms_base_filter_descs[i]!=NULL;i++){
		ms_factory_register_filter(obj,ms_base_filter_descs[i]);
	}

184
#ifdef _WIN32 /*fixme to be tested*/
185
	GetNativeSystemInfo( &sysinfo );
Simon Morlat's avatar
Simon Morlat committed
186 187 188

	num_cpu = sysinfo.dwNumberOfProcessors;
#elif __APPLE__ || __linux
189
	num_cpu = sysconf( _SC_NPROCESSORS_CONF); /*check the number of processors configured, not just the one that are currently active.*/
Simon Morlat's avatar
Simon Morlat committed
190 191 192 193 194 195 196
#elif __QNX__
	num_cpu = _syspage_ptr->num_cpu;
#else
#warning "There is no code that detects the number of CPU for this platform."
#endif
	ms_factory_set_cpu_count(obj,num_cpu);
	ms_factory_set_mtu(obj,MS_MTU_DEFAULT);
197
#ifdef _WIN32
198
	ms_factory_add_platform_tag(obj, "win32");
199
#ifdef MS2_WINDOWS_PHONE
200 201
	ms_factory_add_platform_tag(obj, "windowsphone");
#endif
202 203 204
#ifdef MS2_WINDOWS_UNIVERSAL
	ms_factory_add_platform_tag(obj, "windowsuniversal");
#endif
205 206 207 208 209 210 211 212 213 214
#endif
#ifdef __APPLE__
	ms_factory_add_platform_tag(obj, "apple");
#endif
#ifdef __linux
	ms_factory_add_platform_tag(obj, "linux");
#endif
#ifdef __QNX__
	ms_factory_add_platform_tag(obj, "qnx");
#endif
215
#ifdef __ANDROID__
216 217
	ms_factory_add_platform_tag(obj, "android");
#endif
Simon Morlat's avatar
Simon Morlat committed
218
#if TARGET_OS_IPHONE
219 220 221 222 223 224 225
	ms_factory_add_platform_tag(obj, "ios");
#endif
#if defined(__arm__) || defined(_M_ARM)
	ms_factory_add_platform_tag(obj, "arm");
#else
	ms_factory_add_platform_tag(obj, "x86");
#endif
226
#if defined(__ANDROID__) || (TARGET_OS_IPHONE == 1) || defined(__arm__) || defined(_M_ARM)
227
	ms_factory_add_platform_tag(obj, "embedded");
Simon Morlat's avatar
Simon Morlat committed
228
	obj->echo_canceller_filtername = ms_strdup("MSWebRTCAECM");
229 230
#else
	ms_factory_add_platform_tag(obj, "desktop");
Simon Morlat's avatar
Simon Morlat committed
231
	obj->echo_canceller_filtername = ms_strdup("MSWebRTCAEC");
232 233 234 235
#endif
	tags = ms_factory_get_platform_tags_as_string(obj);
	ms_message("ms_factory_init() done: platform_tags=%s", tags);
	ms_free(tags);
Simon Morlat's avatar
Simon Morlat committed
236
	
Simon Morlat's avatar
Simon Morlat committed
237
	obj->image_resources_dir = bctbx_strdup_printf("%s/images", PACKAGE_DATA_DIR);
Simon Morlat's avatar
Simon Morlat committed
238 239
}

240

Simon Morlat's avatar
Simon Morlat committed
241 242 243 244 245 246 247

MSFactory *ms_factory_new(void){
	MSFactory *obj=ms_new0(MSFactory,1);
	ms_factory_init(obj);
	return obj;
}

248

Simon Morlat's avatar
Simon Morlat committed
249 250 251 252
void ms_factory_register_filter(MSFactory* factory, MSFilterDesc* desc ) {
	if (desc->id==MS_FILTER_NOT_SET_ID){
		ms_fatal("MSFilterId for %s not set !",desc->name);
	}
253
	desc->flags|=MS_FILTER_IS_ENABLED; /*by default a registered filter is enabled*/
254

Simon Morlat's avatar
Simon Morlat committed
255
	/*lastly registered encoder/decoders may replace older ones*/
256
	factory->desc_list=bctbx_list_prepend(factory->desc_list,desc);
Simon Morlat's avatar
Simon Morlat committed
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
}

bool_t ms_factory_codec_supported(MSFactory* factory, const char *mime){
	MSFilterDesc *enc = ms_factory_get_encoding_capturer(factory, mime);
	MSFilterDesc *dec = ms_factory_get_decoding_renderer(factory, mime);

	if (enc == NULL) enc = ms_factory_get_encoder(factory, mime);
	if (dec == NULL) dec = ms_factory_get_decoder(factory, mime);

	if(enc!=NULL && dec!=NULL) return TRUE;

	if(enc==NULL) ms_message("Could not find encoder for %s", mime);
	if(dec==NULL) ms_message("Could not find decoder for %s", mime);
	return FALSE;
}

MSFilterDesc * ms_factory_get_encoding_capturer(MSFactory* factory, const char *mime) {
274
	bctbx_list_t *elem;
Simon Morlat's avatar
Simon Morlat committed
275

276
	for (elem = factory->desc_list; elem != NULL; elem = bctbx_list_next(elem)) {
Simon Morlat's avatar
Simon Morlat committed
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
		MSFilterDesc *desc = (MSFilterDesc *)elem->data;
		if (desc->category == MS_FILTER_ENCODING_CAPTURER) {
			char *saveptr=NULL;
			char *enc_fmt = ms_strdup(desc->enc_fmt);
			char *token = strtok_r(enc_fmt, " ", &saveptr);
			while (token != NULL) {
				if (strcasecmp(token, mime) == 0) {
					break;
				}
				token = strtok_r(NULL, " ", &saveptr);
			}
			ms_free(enc_fmt);
			if (token != NULL) return desc;
		}
	}
	return NULL;
}

MSFilterDesc * ms_factory_get_decoding_renderer(MSFactory* factory, const char *mime) {
296
	bctbx_list_t *elem;
Simon Morlat's avatar
Simon Morlat committed
297

298
	for (elem = factory->desc_list; elem != NULL; elem = bctbx_list_next(elem)) {
Simon Morlat's avatar
Simon Morlat committed
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
		MSFilterDesc *desc = (MSFilterDesc *)elem->data;
		if (desc->category == MS_FILTER_DECODER_RENDERER) {
			char *saveptr=NULL;
			char *enc_fmt = ms_strdup(desc->enc_fmt);
			char *token = strtok_r(enc_fmt, " ", &saveptr);
			while (token != NULL) {
				if (strcasecmp(token, mime) == 0) {
					break;
				}
				token = strtok_r(NULL, " ", &saveptr);
			}
			ms_free(enc_fmt);
			if (token != NULL) return desc;
		}
	}
	return NULL;
}

MSFilterDesc * ms_factory_get_encoder(MSFactory* factory, const char *mime){
318 319
	bctbx_list_t *elem;
	for (elem=factory->desc_list;elem!=NULL;elem=bctbx_list_next(elem)){
Simon Morlat's avatar
Simon Morlat committed
320
		MSFilterDesc *desc=(MSFilterDesc*)elem->data;
321
		if ((desc->flags & MS_FILTER_IS_ENABLED)
322 323
			&& (desc->category==MS_FILTER_ENCODER || desc->category==MS_FILTER_ENCODING_CAPTURER)
			&& strcasecmp(desc->enc_fmt,mime)==0){
Simon Morlat's avatar
Simon Morlat committed
324 325 326 327 328 329 330
			return desc;
		}
	}
	return NULL;
}

MSFilterDesc * ms_factory_get_decoder(MSFactory* factory, const char *mime){
331 332
	bctbx_list_t *elem;
	for (elem=factory->desc_list;elem!=NULL;elem=bctbx_list_next(elem)){
Simon Morlat's avatar
Simon Morlat committed
333
		MSFilterDesc *desc=(MSFilterDesc*)elem->data;
334
		if ((desc->flags & MS_FILTER_IS_ENABLED)
335 336
			&& (desc->category==MS_FILTER_DECODER || desc->category==MS_FILTER_DECODER_RENDERER)
			&& strcasecmp(desc->enc_fmt,mime)==0){
Simon Morlat's avatar
Simon Morlat committed
337 338 339 340 341 342 343 344 345 346 347 348 349
			return desc;
		}
	}
	return NULL;
}

MSFilter * ms_factory_create_encoder(MSFactory* factory, const char *mime){
	MSFilterDesc *desc=ms_factory_get_encoder(factory,mime);
	if (desc!=NULL) return ms_factory_create_filter_from_desc(factory,desc);
	return NULL;
}

MSFilter * ms_factory_create_decoder(MSFactory* factory, const char *mime){
350 351
	//MSFilterDesc *desc=ms_filter_get_decoder(mime);
	MSFilterDesc *desc = ms_factory_get_decoder(factory, mime);
Simon Morlat's avatar
Simon Morlat committed
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
	if (desc!=NULL) return ms_factory_create_filter_from_desc(factory,desc);
	return NULL;
}

MSFilter *ms_factory_create_filter_from_desc(MSFactory* factory, MSFilterDesc *desc){
	MSFilter *obj;
	obj=(MSFilter *)ms_new0(MSFilter,1);
	ms_mutex_init(&obj->lock,NULL);
	obj->desc=desc;
	if (desc->ninputs>0)	obj->inputs=(MSQueue**)ms_new0(MSQueue*,desc->ninputs);
	if (desc->noutputs>0)	obj->outputs=(MSQueue**)ms_new0(MSQueue*,desc->noutputs);

	if (factory->statistics_enabled){
		obj->stats=find_or_create_stats(factory,desc);
	}
	obj->factory=factory;
	if (obj->desc->init!=NULL)
		obj->desc->init(obj);
	return obj;
}
372 373 374 375 376 377 378 379

struct _MSSndCardManager* ms_factory_get_snd_card_manager(MSFactory *factory){
	return factory->sndcardmanager;
}

struct _MSWebCamManager* ms_factory_get_web_cam_manager(MSFactory* f){
	return f->wbcmanager;
}
Simon Morlat's avatar
Simon Morlat committed
380 381 382 383 384 385 386 387 388 389 390 391 392

MSFilter *ms_factory_create_filter(MSFactory* factory, MSFilterId id){
	MSFilterDesc *desc;
	if (id==MS_FILTER_PLUGIN_ID){
		ms_warning("cannot create plugin filters with ms_filter_new_from_id()");
		return NULL;
	}
	desc=ms_factory_lookup_filter_by_id(factory,id);
	if (desc) return ms_factory_create_filter_from_desc(factory,desc);
	ms_error("No such filter with id %i",id);
	return NULL;
}

393
MSFilterDesc *ms_factory_lookup_filter_by_name(const MSFactory* factory, const char *filter_name){
394 395
	bctbx_list_t *elem;
	for (elem=factory->desc_list;elem!=NULL;elem=bctbx_list_next(elem)){
Simon Morlat's avatar
Simon Morlat committed
396 397 398 399 400 401 402 403 404
		MSFilterDesc *desc=(MSFilterDesc*)elem->data;
		if (strcmp(desc->name,filter_name)==0){
			return desc;
		}
	}
	return NULL;
}

MSFilterDesc* ms_factory_lookup_filter_by_id( MSFactory* factory, MSFilterId id){
405
	bctbx_list_t *elem;
406

407
	for (elem=factory->desc_list;elem!=NULL;elem=bctbx_list_next(elem)){
Simon Morlat's avatar
Simon Morlat committed
408 409 410 411 412 413 414 415
		MSFilterDesc *desc=(MSFilterDesc*)elem->data;
		if (desc->id==id){
			return desc;
		}
	}
	return NULL;
}

416 417 418
bctbx_list_t *ms_factory_lookup_filter_by_interface(MSFactory* factory, MSFilterInterfaceId id){
	bctbx_list_t *ret=NULL;
	bctbx_list_t *elem;
Simon Morlat's avatar
Simon Morlat committed
419 420 421
	for(elem=factory->desc_list;elem!=NULL;elem=elem->next){
		MSFilterDesc *desc=(MSFilterDesc*)elem->data;
		if (ms_filter_desc_implements_interface(desc,id))
422
			ret=bctbx_list_append(ret,desc);
Simon Morlat's avatar
Simon Morlat committed
423 424 425 426 427 428 429 430 431 432 433 434 435 436
	}
	return ret;
}

MSFilter *ms_factory_create_filter_from_name(MSFactory* factory, const char *filter_name){
	MSFilterDesc *desc=ms_factory_lookup_filter_by_name(factory, filter_name);
	if (desc==NULL) return NULL;
	return ms_factory_create_filter_from_desc(factory,desc);
}

void ms_factory_enable_statistics(MSFactory* obj, bool_t enabled){
	obj->statistics_enabled=enabled;
}

437
const bctbx_list_t * ms_factory_get_statistics(MSFactory* obj){
Simon Morlat's avatar
Simon Morlat committed
438 439 440 441
	return obj->stats_list;
}

void ms_factory_reset_statistics(MSFactory *obj){
442
	bctbx_list_t *elem;
Simon Morlat's avatar
Simon Morlat committed
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458

	for(elem=obj->stats_list;elem!=NULL;elem=elem->next){
		MSFilterStats *stats=(MSFilterStats *)elem->data;
		stats->elapsed=0;
		stats->count=0;
	}
}

static int usage_compare(const MSFilterStats *s1, const MSFilterStats *s2){
	if (s1->elapsed==s2->elapsed) return 0;
	if (s1->elapsed<s2->elapsed) return 1;
	return -1;
}


void ms_factory_log_statistics(MSFactory *obj){
459 460
	bctbx_list_t *sorted=NULL;
	bctbx_list_t *elem;
Simon Morlat's avatar
Simon Morlat committed
461 462 463
	uint64_t total=1;
	for(elem=obj->stats_list;elem!=NULL;elem=elem->next){
		MSFilterStats *stats=(MSFilterStats *)elem->data;
464
		sorted=bctbx_list_insert_sorted(sorted,stats,(bctbx_compare_func)usage_compare);
Simon Morlat's avatar
Simon Morlat committed
465 466 467 468 469 470 471 472 473 474 475 476 477
		total+=stats->elapsed;
	}
	ms_message("===========================================================");
	ms_message("                  FILTER USAGE STATISTICS                  ");
	ms_message("Name                Count     Time/tick (ms)      CPU Usage");
	ms_message("-----------------------------------------------------------");
	for(elem=sorted;elem!=NULL;elem=elem->next){
		MSFilterStats *stats=(MSFilterStats *)elem->data;
		double percentage=100.0*((double)stats->elapsed)/(double)total;
		double tpt=((double)stats->elapsed*1e-6)/((double)stats->count+1.0);
		ms_message("%-19s %-9i %-19g %-10g",stats->name,stats->count,tpt,percentage);
	}
	ms_message("===========================================================");
478
	bctbx_list_free(sorted);
Simon Morlat's avatar
Simon Morlat committed
479 480 481 482 483 484 485 486 487
}

#ifndef PLUGINS_EXT
	#define PLUGINS_EXT ".so"
#endif
typedef void (*init_func_t)(MSFactory *);

int ms_factory_load_plugins(MSFactory *factory, const char *dir){
	int num=0;
488
#if defined(_WIN32) && !defined(_WIN32_WCE)
Simon Morlat's avatar
Simon Morlat committed
489 490 491
	WIN32_FIND_DATA FileData;
	HANDLE hSearch;
	char szDirPath[1024];
492
#ifdef UNICODE
493 494
	wchar_t wszDirPath[1024];
#endif
Simon Morlat's avatar
Simon Morlat committed
495 496
	char szPluginFile[1024];
	BOOL fFinished = FALSE;
497 498 499 500 501 502
	const char *tmp = NULL;
	BOOL debug = FALSE;
#ifndef MS2_WINDOWS_UNIVERSAL
	tmp = getenv("DEBUG");
#endif
	debug = (tmp != NULL && atoi(tmp) == 1);
503

Simon Morlat's avatar
Simon Morlat committed
504 505 506
	snprintf(szDirPath, sizeof(szDirPath), "%s", dir);

	// Start searching for .dll files in the current directory.
507
	snprintf(szDirPath, sizeof(szDirPath), "%s\\libms*.dll", dir);
508 509 510 511 512 513
#ifdef UNICODE
	mbstowcs(wszDirPath, szDirPath, sizeof(wszDirPath));
	hSearch = FindFirstFileExW(wszDirPath, FindExInfoStandard, &FileData, FindExSearchNameMatch, NULL, 0);
#else
	hSearch = FindFirstFileExA(szDirPath, FindExInfoStandard, &FileData, FindExSearchNameMatch, NULL, 0);
#endif
Simon Morlat's avatar
Simon Morlat committed
514 515
	if (hSearch == INVALID_HANDLE_VALUE)
	{
Simon Morlat's avatar
Simon Morlat committed
516
		ms_message("no plugin (*.dll) found in [%s] [%d].", szDirPath, (int)GetLastError());
Simon Morlat's avatar
Simon Morlat committed
517 518 519 520 521 522 523
		return 0;
	}
	snprintf(szDirPath, sizeof(szDirPath), "%s", dir);

	while (!fFinished)
	{
		/* load library */
524
#ifdef MS2_WINDOWS_DESKTOP
525 526
		UINT em=0;
#endif
Simon Morlat's avatar
Simon Morlat committed
527
		HINSTANCE os_handle;
528
#ifdef UNICODE
Simon Morlat's avatar
Simon Morlat committed
529
		wchar_t wszPluginFile[2048];
530 531 532
		char filename[512];
		wcstombs(filename, FileData.cFileName, sizeof(filename));
		snprintf(szPluginFile, sizeof(szPluginFile), "%s\\%s", szDirPath, filename);
533
		mbstowcs(wszPluginFile, szPluginFile, sizeof(wszPluginFile));
534 535 536
#else
		snprintf(szPluginFile, sizeof(szPluginFile), "%s\\%s", szDirPath, FileData.cFileName);
#endif
537
#ifdef MS2_WINDOWS_DESKTOP
Simon Morlat's avatar
Simon Morlat committed
538 539
		if (!debug) em = SetErrorMode (SEM_FAILCRITICALERRORS);

Simon Morlat's avatar
Simon Morlat committed
540
#ifdef UNICODE
541 542 543 544
		os_handle = LoadLibraryExW(wszPluginFile, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
#else
		os_handle = LoadLibraryExA(szPluginFile, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
#endif
Simon Morlat's avatar
Simon Morlat committed
545 546 547
		if (os_handle==NULL)
		{
			ms_message("Fail to load plugin %s with altered search path: error %i",szPluginFile,(int)GetLastError());
Simon Morlat's avatar
Simon Morlat committed
548
#ifdef UNICODE
549 550 551 552
			os_handle = LoadLibraryExW(wszPluginFile, NULL, 0);
#else
			os_handle = LoadLibraryExA(szPluginFile, NULL, 0);
#endif
Simon Morlat's avatar
Simon Morlat committed
553 554
		}
		if (!debug) SetErrorMode (em);
555 556
#else
		os_handle = LoadPackagedLibrary(wszPluginFile, 0);
557
#endif
Simon Morlat's avatar
Simon Morlat committed
558
		if (os_handle==NULL)
559
			ms_error("Fail to load plugin %s: error %i", szPluginFile, (int)GetLastError());
Simon Morlat's avatar
Simon Morlat committed
560 561 562 563 564
		else{
			init_func_t initroutine;
			char szPluginName[256];
			char szMethodName[256];
			char *minus;
565
#ifdef UNICODE
566 567 568 569
			snprintf(szPluginName, sizeof(szPluginName), "%s", filename);
#else
			snprintf(szPluginName, sizeof(szPluginName), "%s", FileData.cFileName);
#endif
Simon Morlat's avatar
Simon Morlat committed
570 571 572 573
			/*on mingw, dll names might be libsomething-3.dll. We must skip the -X.dll stuff*/
			minus=strchr(szPluginName,'-');
			if (minus) *minus='\0';
			else szPluginName[strlen(szPluginName)-4]='\0'; /*remove .dll*/
574
			snprintf(szMethodName, sizeof(szMethodName), "%s_init", szPluginName);
Simon Morlat's avatar
Simon Morlat committed
575 576 577 578 579
			initroutine = (init_func_t) GetProcAddress (os_handle, szMethodName);
				if (initroutine!=NULL){
					initroutine(factory);
					ms_message("Plugin loaded (%s)", szPluginFile);
					// Add this new loaded plugin to the list (useful for FreeLibrary at the end)
580
					factory->ms_plugins_loaded_list=bctbx_list_append(factory->ms_plugins_loaded_list,os_handle);
Simon Morlat's avatar
Simon Morlat committed
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
					num++;
				}else{
					ms_warning("Could not locate init routine of plugin %s. Should be %s",
					szPluginFile, szMethodName);
				}
		}
		if (!FindNextFile(hSearch, &FileData)) {
			if (GetLastError() == ERROR_NO_MORE_FILES){
				fFinished = TRUE;
			}
			else
			{
				ms_error("couldn't find next plugin dll.");
				fFinished = TRUE;
			}
		}
	}
	/* Close the search handle. */
	FindClose(hSearch);

601
#elif defined(HAVE_DLOPEN)
Simon Morlat's avatar
Simon Morlat committed
602 603
	char plugin_name[64];
	DIR *ds;
604
	bctbx_list_t *loaded_plugins = NULL;
Simon Morlat's avatar
Simon Morlat committed
605 606 607 608 609 610 611 612 613 614 615 616 617
	struct dirent *de;
	char *ext;
	char *fullpath;
	ds=opendir(dir);
	if (ds==NULL){
		ms_message("Cannot open directory %s: %s",dir,strerror(errno));
		return -1;
	}
	while( (de=readdir(ds))!=NULL){
		if (
#ifndef __QNX__
			(de->d_type==DT_REG || de->d_type==DT_UNKNOWN || de->d_type==DT_LNK) &&
#endif
618
			(strstr(de->d_name, "libms") == de->d_name) && ((ext=strstr(de->d_name,PLUGINS_EXT))!=NULL)) {
Simon Morlat's avatar
Simon Morlat committed
619
			void *handle;
620
			snprintf(plugin_name, MIN(sizeof(plugin_name), (size_t)(ext - de->d_name + 1)), "%s", de->d_name);
621 622
			if (bctbx_list_find_custom(loaded_plugins, (bctbx_compare_func)strcmp, plugin_name) != NULL) continue;
			loaded_plugins = bctbx_list_append(loaded_plugins, ms_strdup(plugin_name));
Simon Morlat's avatar
Simon Morlat committed
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
			fullpath=ms_strdup_printf("%s/%s",dir,de->d_name);
			ms_message("Loading plugin %s...",fullpath);

			if ( (handle=dlopen(fullpath,RTLD_NOW))==NULL){
				ms_warning("Fail to load plugin %s : %s",fullpath,dlerror());
			}else {
				char *initroutine_name=ms_malloc0(strlen(de->d_name)+10);
				char *p;
				void *initroutine=NULL;
				strcpy(initroutine_name,de->d_name);
				p=strstr(initroutine_name,PLUGINS_EXT);
				if (p!=NULL){
					strcpy(p,"_init");
					initroutine=dlsym(handle,initroutine_name);
				}

#ifdef __APPLE__
				if (initroutine==NULL){
					/* on macosx: library name are libxxxx.1.2.3.dylib */
					/* -> MUST remove the .1.2.3 */
					p=strstr(initroutine_name,".");
					if (p!=NULL)
					{
						strcpy(p,"_init");
						initroutine=dlsym(handle,initroutine_name);
					}
				}
#endif

				if (initroutine!=NULL){
					init_func_t func=(init_func_t)initroutine;
					func(factory);
					ms_message("Plugin loaded (%s)", fullpath);
					num++;
				}else{
					ms_warning("Could not locate init routine of plugin %s",de->d_name);
				}
				ms_free(initroutine_name);
			}
			ms_free(fullpath);
		}
	}
665 666
	bctbx_list_for_each(loaded_plugins, ms_free);
	bctbx_list_free(loaded_plugins);
Simon Morlat's avatar
Simon Morlat committed
667 668 669 670 671 672 673 674 675
	closedir(ds);
#else
	ms_warning("no loadable plugin support: plugins cannot be loaded.");
	num=-1;
#endif
	return num;
}

void ms_factory_uninit_plugins(MSFactory *factory){
676
#if defined(_WIN32)
677
	bctbx_list_t *elem;
Simon Morlat's avatar
Simon Morlat committed
678 679
#endif

680
#if defined(_WIN32)
Simon Morlat's avatar
Simon Morlat committed
681 682 683 684 685 686
	for(elem=factory->ms_plugins_loaded_list;elem!=NULL;elem=elem->next)
	{
		HINSTANCE handle=(HINSTANCE )elem->data;
		FreeLibrary(handle) ;
	}

687
	factory->ms_plugins_loaded_list = bctbx_list_free(factory->ms_plugins_loaded_list);
Simon Morlat's avatar
Simon Morlat committed
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
#endif
}

void ms_factory_init_plugins(MSFactory *obj) {
	if (obj->plugins_dir == NULL) {
#ifdef PACKAGE_PLUGINS_DIR
		obj->plugins_dir = ms_strdup(PACKAGE_PLUGINS_DIR);
#else
		obj->plugins_dir = ms_strdup("");
#endif
	}
	if (strlen(obj->plugins_dir) > 0) {
		ms_message("Loading ms plugins from [%s]",obj->plugins_dir);
		ms_factory_load_plugins(obj,obj->plugins_dir);
	}
}

void ms_factory_set_plugins_dir(MSFactory *obj, const char *path) {
	if (obj->plugins_dir != NULL) {
		ms_free(obj->plugins_dir);
		obj->plugins_dir=NULL;
	}
	if (path)
		obj->plugins_dir = ms_strdup(path);
}

714
struct _MSEventQueue *ms_factory_create_event_queue(MSFactory *obj) {
Simon Morlat's avatar
Simon Morlat committed
715 716 717 718 719 720
	if (obj->evq==NULL){
		obj->evq=ms_event_queue_new();
	}
	return obj->evq;
}

721
void ms_factory_destroy_event_queue(MSFactory *obj) {
Simon Morlat's avatar
Simon Morlat committed
722
	if (obj->image_resources_dir) bctbx_free(obj->image_resources_dir);
723
	ms_event_queue_destroy(obj->evq);
724
	ms_factory_set_event_queue(obj,NULL);
725 726 727
}


728 729 730 731
struct _MSEventQueue *ms_factory_get_event_queue(MSFactory *obj){
	return obj->evq;
}

732
/*this function is for compatibility, when event queues were created by the application*/
Simon Morlat's avatar
Simon Morlat committed
733 734 735 736 737 738 739 740 741 742 743 744 745 746
void ms_factory_set_event_queue(MSFactory *obj, MSEventQueue *evq){
	obj->evq=evq;
}

static int compare_fmt(const MSFmtDescriptor *a, const MSFmtDescriptor *b){
	if (a->type!=b->type) return -1;
	if (strcasecmp(a->encoding,b->encoding)!=0) return -1;
	if (a->rate!=b->rate) return -1;
	if (a->nchannels!=b->nchannels) return -1;
	if (a->fmtp==NULL && b->fmtp!=NULL) return -1;
	if (a->fmtp!=NULL && b->fmtp==NULL) return -1;
	if (a->fmtp && b->fmtp && strcmp(a->fmtp,b->fmtp)!=0) return -1;
	if (a->type==MSVideo){
		if (a->vsize.width!=b->vsize.width || a->vsize.height!=b->vsize.height) return -1;
747
		if (a->fps!=b->fps) return -1;
Simon Morlat's avatar
Simon Morlat committed
748 749 750 751 752 753 754 755 756 757 758 759
	}
	return 0;
}

static MSFmtDescriptor * ms_fmt_descriptor_new_copy(const MSFmtDescriptor *orig){
	MSFmtDescriptor *obj=ms_new0(MSFmtDescriptor,1);
	obj->type=orig->type;
	obj->rate=orig->rate;
	obj->nchannels=orig->nchannels;
	if (orig->fmtp) obj->fmtp=ms_strdup(orig->fmtp);
	if (orig->encoding) obj->encoding=ms_strdup(orig->encoding);
	obj->vsize=orig->vsize;
760
	obj->fps=orig->fps;
Simon Morlat's avatar
Simon Morlat committed
761 762 763 764 765
	return obj;
}

const char *ms_fmt_descriptor_to_string(const MSFmtDescriptor *obj){
	MSFmtDescriptor *mutable_fmt=(MSFmtDescriptor*)obj;
766
	if (!obj) return "null";
Simon Morlat's avatar
Simon Morlat committed
767 768 769 770 771
	if (obj->text==NULL){
		if (obj->type==MSAudio){
			mutable_fmt->text=ms_strdup_printf("type=audio;encoding=%s;rate=%i;channels=%i;fmtp='%s'",
							 obj->encoding,obj->rate,obj->nchannels,obj->fmtp ? obj->fmtp : "");
		}else{
772 773
			mutable_fmt->text=ms_strdup_printf("type=video;encoding=%s;vsize=%ix%i;fps=%f;fmtp='%s'",
							 obj->encoding,obj->vsize.width,obj->vsize.height,obj->fps,obj->fmtp ? obj->fmtp : "");
Simon Morlat's avatar
Simon Morlat committed
774 775 776 777 778
		}
	}
	return obj->text;
}

Sylvain Berfini's avatar
Sylvain Berfini committed
779 780 781 782 783
bool_t ms_fmt_descriptor_equals(const MSFmtDescriptor *fmt1, const MSFmtDescriptor *fmt2) {
	if (!fmt1 || !fmt2) return FALSE;
	return compare_fmt(fmt1, fmt2) == 0;
}

Simon Morlat's avatar
Simon Morlat committed
784 785 786
static void ms_fmt_descriptor_destroy(MSFmtDescriptor *obj){
	if (obj->encoding) ms_free(obj->encoding);
	if (obj->fmtp) ms_free(obj->fmtp);
Simon Morlat's avatar
Simon Morlat committed
787
	if (obj->text) ms_free(obj->text);
Simon Morlat's avatar
Simon Morlat committed
788 789 790
	ms_free(obj);
}

791
const MSFmtDescriptor *ms_factory_get_format(MSFactory *obj, const MSFmtDescriptor *ref){
Simon Morlat's avatar
Simon Morlat committed
792
	MSFmtDescriptor *ret;
793 794 795
	bctbx_list_t *found;
	if ((found=bctbx_list_find_custom(obj->formats,(int (*)(const void*, const void*))compare_fmt, ref))==NULL){
		obj->formats=bctbx_list_append(obj->formats,ret=ms_fmt_descriptor_new_copy(ref));
Simon Morlat's avatar
Simon Morlat committed
796 797 798 799 800 801 802 803 804 805 806 807 808
	}else{
		ret=(MSFmtDescriptor *)found->data;
	}
	return ret;
}

const MSFmtDescriptor * ms_factory_get_audio_format(MSFactory *obj, const char *mime, int rate, int channels, const char *fmtp){
	MSFmtDescriptor tmp={0};
	tmp.type=MSAudio;
	tmp.encoding=(char*)mime;
	tmp.rate=rate;
	tmp.nchannels=channels;
	tmp.fmtp=(char*)fmtp;
809
	return ms_factory_get_format(obj,&tmp);
Simon Morlat's avatar
Simon Morlat committed
810 811
}

812
const MSFmtDescriptor * ms_factory_get_video_format(MSFactory *obj, const char *mime, MSVideoSize size, float fps, const char *fmtp){
Simon Morlat's avatar
Simon Morlat committed
813
	MSFmtDescriptor tmp={0};
Simon Morlat's avatar
Simon Morlat committed
814
	tmp.type=MSVideo;
Simon Morlat's avatar
Simon Morlat committed
815 816
	tmp.encoding=(char*)mime;
	tmp.rate=90000;
817
	tmp.vsize=size;
Simon Morlat's avatar
Simon Morlat committed
818
	tmp.fmtp=(char*)fmtp;
819 820
	tmp.fps=fps;
	return ms_factory_get_format(obj,&tmp);
Simon Morlat's avatar
Simon Morlat committed
821
}
822

823
int ms_factory_enable_filter_from_name(MSFactory *factory, const char *name, bool_t enable) {
824 825 826 827 828
	MSFilterDesc *desc=ms_factory_lookup_filter_by_name(factory,name);
	if (!desc) {
		ms_error("Cannot enable/disable unknown filter [%s] on factory [%p]",name,factory);
		return -1;
	}
829 830 831
	if (enable) desc->flags |= MS_FILTER_IS_ENABLED;
	else desc->flags &= ~MS_FILTER_IS_ENABLED;
	ms_message("Filter [%s]  %s on factory [%p]",name,(enable ? "enabled" : "disabled"),factory);
832 833
	return 0;
}
834

835 836 837 838 839 840
bool_t ms_factory_filter_from_name_enabled(const MSFactory *factory, const char *name) {
	MSFilterDesc *desc=ms_factory_lookup_filter_by_name(factory,name);
	if (!desc) {
		ms_error("Cannot get enable/disable state for unknown filter [%s] on factory [%p]",name,factory);
		return FALSE;
	}
841
	return !!(desc->flags & MS_FILTER_IS_ENABLED);
842 843
}

844 845

void ms_factory_register_offer_answer_provider(MSFactory *f, MSOfferAnswerProvider *offer_answer_prov){
846 847
	if (bctbx_list_find(f->offer_answer_provider_list, offer_answer_prov)) return; /*avoid registering several time the same pointer*/
	f->offer_answer_provider_list = bctbx_list_prepend(f->offer_answer_provider_list, offer_answer_prov);
848 849 850
}

MSOfferAnswerProvider * ms_factory_get_offer_answer_provider(MSFactory *f, const char *mime_type){
851
	const bctbx_list_t *elem;
852 853 854 855 856 857 858 859 860 861 862 863 864 865
	for (elem = f->offer_answer_provider_list; elem != NULL; elem = elem->next){
		MSOfferAnswerProvider *prov = (MSOfferAnswerProvider*) elem->data;
		if (strcasecmp(mime_type, prov->mime_type) == 0)
			return prov;
	}
	return NULL;
}

MSOfferAnswerContext * ms_factory_create_offer_answer_context(MSFactory *f, const char *mime_type){
	MSOfferAnswerProvider *prov = ms_factory_get_offer_answer_provider(f, mime_type);
	if (prov) return prov->create_context();
	return NULL;
}

866 867 868 869
MSDevicesInfo* ms_factory_get_devices_info(MSFactory *f) {
	return f->devices_info;
}

Simon Morlat's avatar
Simon Morlat committed
870 871
const char * ms_factory_get_image_resources_dir(const MSFactory *f) {
	return f->image_resources_dir;
872 873 874
}

void ms_factory_set_image_resources_dir(MSFactory *f, const char *path) {
Simon Morlat's avatar
Simon Morlat committed
875 876 877 878 879 880
	if (f->image_resources_dir) {
		bctbx_free(f->image_resources_dir);
		f->image_resources_dir = NULL;
	}
	if (path)
		f->image_resources_dir = bctbx_strdup(path);
881 882
}

883 884 885 886 887 888 889 890
void ms_factory_set_expected_bandwidth(MSFactory *f, int bitrate) {
	f->expected_video_bandwidth = bitrate;
}

int ms_factory_get_expected_bandwidth(MSFactory *f) {
	return f->expected_video_bandwidth;
}

891
#ifdef __ANDROID__
892 893 894
#include "sys/system_properties.h"
#include <jni.h>

895

Simon Morlat's avatar
Simon Morlat committed
896
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
897

Simon Morlat's avatar
Simon Morlat committed
898
JNIEXPORT jint JNICALL Java_org_linphone_mediastream_Factory_enableFilterFromName(JNIEnv* env,  jobject obj, jlong factoryPtr, jstring jname, jboolean enable) {
899
	MSFactory *factory = (MSFactory *) factoryPtr;
Simon Morlat's avatar
Simon Morlat committed
900 901 902
	const char *name = jname ? (*env)->GetStringUTFChars(env, jname, NULL) : NULL;
	int result = ms_factory_enable_filter_from_name(factory, name, enable);
	(*env)->ReleaseStringUTFChars(env, jname, name);
903 904
	return result;
}
Simon Morlat's avatar
Simon Morlat committed
905 906
JNIEXPORT jboolean JNICALL Java_org_linphone_mediastream_Factory_filterFromNameEnabled(JNIEnv* env, jobject obj, jlong factoryPtr, jstring jname) {
	const char *name = jname ? (*env)->GetStringUTFChars(env, jname, NULL) : NULL;
907
	MSFactory *factory = (MSFactory *) factoryPtr;
Simon Morlat's avatar
Simon Morlat committed
908 909
	jboolean result = ms_factory_filter_from_name_enabled(factory, name);
	(*env)->ReleaseStringUTFChars(env, jname, name);
910 911 912
	return result;
}

913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939

JNIEXPORT jstring JNICALL Java_org_linphone_mediastream_Factory_getEncoderText(JNIEnv* env, jobject obj,
    jlong factoryPtr, jstring jmime) {
	MSFactory *factory = (MSFactory*)factoryPtr;
	const char *mime = (*env)->GetStringUTFChars(env, jmime, NULL);
	jstring jtext = NULL;
	if (mime){
		MSFilterDesc *desc = ms_factory_get_encoder(factory, mime);
		if (desc) jtext =(*env)->NewStringUTF(env, desc->text);
		(*env)->ReleaseStringUTFChars(env, jmime, mime);
	}
	return jtext;
}

JNIEXPORT jstring JNICALL Java_org_linphone_mediastream_Factory_getDecoderText(JNIEnv* env, jobject obj,
    jlong factoryPtr, jstring jmime) {
	MSFactory *factory = (MSFactory*)factoryPtr;
	const char *mime = (*env)->GetStringUTFChars(env, jmime, NULL);
	jstring jtext = NULL;
	if (mime){
		MSFilterDesc *desc = ms_factory_get_decoder(factory, mime);
		if (desc) jtext = (*env)->NewStringUTF(env, desc->text);
		(*env)->ReleaseStringUTFChars(env, jmime, mime);
	}
	return jtext;
}

940 941 942 943 944 945
#ifdef _MSC_VER
#pragma warning(disable : 4996)
#else
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif

946
JNIEXPORT jint JNICALL Java_org_linphone_mediastream_MediastreamerAndroidContext_enableFilterFromNameImpl(JNIEnv* env,  jobject obj, jstring jname, jboolean enable) {
947 948
	const char *mime;
	int result;
949 950 951 952
	if (ms_factory_get_fallback() == NULL) {
		ms_error("Java_org_linphone_mediastream_MediastreamerAndroidContext_enableFilterFromNameImpl(): no fallback factory. Use Factory.enableFilterFromName()");
		return -1;
	}
953 954
	mime = jname ? (*env)->GetStringUTFChars(env, jname, NULL) : NULL;
	result = ms_factory_enable_filter_from_name(ms_factory_get_fallback(),mime,enable);
955 956 957 958
	(*env)->ReleaseStringUTFChars(env, jname, mime);
	return result;
}
JNIEXPORT jboolean JNICALL Java_org_linphone_mediastream_MediastreamerAndroidContext_filterFromNameEnabledImpl(JNIEnv* env, jobject obj, jstring jname) {
959 960
	const char *mime;
	jboolean result;
961 962 963 964
	if (ms_factory_get_fallback() == NULL) {
		ms_error("Java_org_linphone_mediastream_MediastreamerAndroidContext_filterFromNameEnabledImpl(): no fallback factory. Use Factory.filterFromNameEnabled()");
		return FALSE;
	}
965 966
	mime = jname ? (*env)->GetStringUTFChars(env, jname, NULL) : NULL;
	result = ms_factory_filter_from_name_enabled(ms_factory_get_fallback(),mime);
967 968 969
	(*env)->ReleaseStringUTFChars(env, jname, mime);
	return result;
}
970

971
#endif
972 973 974



Ghislain MARY's avatar
Ghislain MARY committed
975 976 977
#ifdef _MSC_VER
#pragma warning(disable : 4996)
#else
978
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
Ghislain MARY's avatar
Ghislain MARY committed
979
#endif
980

981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
/**
* Destroy the factory.
* This should be done after destroying all objects created by the factory.
**/
void ms_factory_destroy(MSFactory *factory) {
	if (factory->voip_uninit_func) factory->voip_uninit_func(factory);
	ms_factory_uninit_plugins(factory);
	if (factory->evq) ms_factory_destroy_event_queue(factory);
	factory->formats = bctbx_list_free_with_data(factory->formats, (void(*)(void*))ms_fmt_descriptor_destroy);
	factory->desc_list = bctbx_list_free(factory->desc_list);
	bctbx_list_for_each(factory->stats_list, ms_free);
	factory->stats_list = bctbx_list_free(factory->stats_list);
	factory->offer_answer_provider_list = bctbx_list_free(factory->offer_answer_provider_list);
	bctbx_list_for_each(factory->platform_tags, ms_free);
	factory->platform_tags = bctbx_list_free(factory->platform_tags);
996
	if (factory->echo_canceller_filtername) ms_free(factory->echo_canceller_filtername);
997 998 999 1000 1001 1002
	if (factory->plugins_dir) ms_free(factory->plugins_dir);
	ms_free(factory);
	if (factory == fallback_factory) fallback_factory = NULL;
}


1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
MSFactory *ms_factory_create_fallback(void){
	if (fallback_factory==NULL){
		fallback_factory=ms_factory_new();
	}
	return fallback_factory;
}

/**
 * Used by the legacy functions before MSFactory was added.
 * Do not use in an application.
**/
MSFactory *ms_factory_get_fallback(void){
	return fallback_factory;
}