tester.c 166 KB
Newer Older
Simon Morlat's avatar
Simon Morlat committed
/*
 * Copyright (c) 2010-2019 Belledonne Communications SARL.
 *
 * This file is part of Liblinphone.
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
#include "linphone/core.h"
#include "linphone/logging.h"
#include "logging-private.h"
#include "liblinphone_tester.h"
johan's avatar
johan committed
#include <bctoolbox/vfs.h>
Benjamin REIS's avatar
Benjamin REIS committed
#include "tester_utils.h"
#include "belle-sip/sipstack.h"
#include "shared_tester_functions.h"

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef _WIN32
#if defined(__MINGW32__) || !defined(WINAPI_FAMILY_PARTITION) || !defined(WINAPI_PARTITION_DESKTOP)
#define LINPHONE_WINDOWS_DESKTOP 1
#elif defined(WINAPI_FAMILY_PARTITION)
//See bctoolbox/include/port.h for WINAPI_PARTITION checker
#if defined(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#define LINPHONE_WINDOWS_DESKTOP 1
#elif defined (WINAPI_PARTITION_PC_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PC_APP)
#define LINPHONE_WINDOWS_DESKTOP 1
#define LINPHONE_WINDOWS_UNIVERSAL 1
#define LINPHONE_WINDOWS_UWP 1
#elif defined(WINAPI_PARTITION_PHONE_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
#define LINPHONE_WINDOWS_PHONE 1
#elif defined(WINAPI_PARTITION_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
#define LINPHONE_WINDOWS_UNIVERSAL 1
#endif
#endif
#endif
#ifdef _MSC_VER
#if (_MSC_VER >= 1900)
#define LINPHONE_MSC_VER_GREATER_19
#endif
#endif

#if _WIN32
#define unlink _unlink
#endif
Erwan Croze's avatar
Erwan Croze committed
#ifdef __ANDROID__
Erwan Croze's avatar
Erwan Croze committed
extern jobject system_context;
Erwan Croze's avatar
Erwan Croze committed
#else
void *system_context=0;
#endif
static char *liblinphone_tester_empty_rc_path = NULL;
static int liblinphone_tester_keep_accounts_flag = 0;
static bool_t liblinphone_tester_keep_record_files = FALSE;
static bool_t liblinphone_tester_leak_detector_disabled = FALSE;
bool_t liblinphone_tester_keep_uuid = FALSE;
bool_t liblinphone_tester_tls_support_disabled = FALSE;
const MSAudioDiffParams audio_cmp_params = {10,200};
const char* flexisip_tester_dns_server = "fs-test-3.linphone.org";
bctbx_list_t *flexisip_tester_dns_ip_addresses = NULL;
const char* test_domain="sipopen.example.org";
const char* auth_domain="sip.example.org";
const char* test_username="liblinphone_tester";
const char* test_sha_username="liblinphone_sha_tester";
const char* pure_sha256_user="pure_sha256_user";
const char* test_password="secret";
const char* test_route="sip2.linphone.org";
const char *userhostsfile = "tester_hosts";
const char *file_transfer_url="https://transfer.example.org:9444/flexisip-http-file-transfer-server/hft.php";
const char *file_transfer_url_tls_client_auth="https://transfer.example.org:9445/flexisip-http-file-transfer-server/hft.php";
const char *file_transfer_url_digest_auth="https://transfer.example.org:9446/flexisip-http-file-transfer-server/hft.php";
// Get proxy on the server using digest auth on sip.example.org
const char *file_transfer_get_proxy="https://transfer.example.org:9446/flexisip-http-file-transfer-server/download.php";
const char *file_transfer_url_digest_auth_any_domain="https://transfer.example.org:9447/flexisip-http-file-transfer-server/hft.php";
const char *file_transfer_url_small_files="https://transfer.example.org:9448/flexisip-http-file-transfer-server/hft.php";
const char *file_transfer_url_digest_auth_external_domain="https://transfer.external-domain.org:9544/flexisip-http-file-transfer-server/hft.php";
// Get proxy on the server using digest auth on sip.external-domain.org
const char *file_transfer_get_proxy_external_domain="https://transfer.external-domain.org:9544/flexisip-http-file-transfer-server/download.php";
// These lime server authenticate user using Digest auth only on sip.example.org domain
const char *lime_server_c25519_url="https://lime.wildcard1.linphone.org:8443/lime-server-c25519/lime-server.php";
const char *lime_server_c448_url="https://lime.wildcard1.linphone.org:8443/lime-server-c448/lime-server.php";
// These lime server authenticate user using Digest auth only on any auth domain (providing the flexisip base can authenticate the user)
const char *lime_server_any_domain_c25519_url="https://lime.wildcard1.linphone.org:8442/lime-server-c25519/lime-server.php";
const char *lime_server_any_domain_c448_url="https://lime.wildcard1.linphone.org:8442/lime-server-c448/lime-server.php";
johan's avatar
johan committed
// These lime server authenticate user using TLS auth only
const char *lime_server_c25519_tlsauth_req_url="https://lime.wildcard1.linphone.org:8543/lime-server-c25519/lime-server.php";
const char *lime_server_c448_tlsauth_req_url="https://lime.wildcard1.linphone.org:8543/lime-server-c448/lime-server.php";
// These lime server authenticate user using optionnal TLS auth, falling back on digest auth if client did not provide a client certificate
const char *lime_server_c25519_tlsauth_opt_url="https://lime.wildcard1.linphone.org:8544/lime-server-c25519/lime-server.php";
const char *lime_server_c448_tlsauth_opt_url="https://lime.wildcard1.linphone.org:8544/lime-server-c448/lime-server.php";
johan's avatar
johan committed
// Lime server using TLS and digest auth on external-domain
const char *lime_server_c25519_external_url="https://lime.external-domain.org:8643/lime-server-c25519/lime-server.php";
const char *lime_server_c448_external_url="https://lime.external-domain.org:8643/lime-server-c448/lime-server.php";
bool_t liblinphonetester_ipv6 = TRUE;
const char * liblinphone_tester_ipv6_probing_address = "2a01:e00::2";
bool_t liblinphonetester_show_account_manager_logs = FALSE;
bool_t liblinphonetester_no_account_creator = FALSE;
int liblinphonetester_transport_timeout = 9000; /*milliseconds. it is set to such low value to workaround a problem with our Freebox v6 when connecting to Ipv6 addresses.
			It was found that the freebox sometimes block SYN-ACK packets, which prevents connection to be succesful.
			Thanks to the timeout, it will fallback to IPv4*/
char* message_external_body_url=NULL;
static const char *notify_content="<somexml2>blabla</somexml2>";
const char *liblinphone_tester_mire_id="Mire: Mire (synthetic moving picture)";
const char *liblinphone_tester_static_image_id="StaticImage: Static picture";
static void network_reachable(LinphoneCore *lc, bool_t reachable) {
	stats* counters;
	ms_message("Network reachable [%s]",reachable?"TRUE":"FALSE");
	counters = get_stats(lc);
	if (reachable)
		counters->number_of_NetworkReachableTrue++;
	else
		counters->number_of_NetworkReachableFalse++;
}
void liblinphone_tester_clock_start(MSTimeSpec *start){
	ms_get_cur_time(start);
}

bool_t liblinphone_tester_clock_elapsed(const MSTimeSpec *start, int value_ms){
	MSTimeSpec current;
	ms_get_cur_time(&current);
	if ((((current.tv_sec-start->tv_sec)*1000LL) + ((current.tv_nsec-start->tv_nsec)/1000000LL))>=value_ms)
		return TRUE;
	return FALSE;
}

LinphoneAddress * create_linphone_address(const char * domain) {
	return create_linphone_address_for_algo(domain,NULL);
}

LinphoneAddress * create_linphone_address_for_algo(const char * domain, const char* username) {
	LinphoneAddress *addr = linphone_address_new(NULL);
	if (!BC_ASSERT_PTR_NOT_NULL(addr)) return NULL;
	/* For clients who support different algorithms, their usernames must be differnet for having diffrent forms of password */
	if (username) linphone_address_set_username(addr,username);
	else linphone_address_set_username(addr,test_username);
	if (username) BC_ASSERT_STRING_EQUAL(username, linphone_address_get_username(addr));
	else BC_ASSERT_STRING_EQUAL(test_username, linphone_address_get_username(addr));
	if (!domain) domain = test_route;
	linphone_address_set_domain(addr,domain);
	BC_ASSERT_STRING_EQUAL(domain, linphone_address_get_domain(addr));
	linphone_address_set_display_name(addr, NULL);
	linphone_address_set_display_name(addr, "Mr Tester");
	BC_ASSERT_STRING_EQUAL("Mr Tester", linphone_address_get_display_name(addr));
	return addr;
static void auth_info_requested(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
	ms_message("Auth info requested (deprecated callback) for user id [%s] at realm [%s]\n", username, realm);
	counters = get_stats(lc);
	counters->number_of_auth_info_requested++;
}

void reset_counters( stats* counters) {
	if (counters->last_received_chat_message) linphone_chat_message_unref(counters->last_received_chat_message);
	if (counters->last_received_info_message) linphone_info_message_unref(counters->last_received_info_message);
	if (counters->dtmf_list_received) bctbx_free(counters->dtmf_list_received);

	memset(counters,0,sizeof(stats));
}

static void setup_dns(LinphoneCore *lc, const char *path){
	if (flexisip_tester_dns_ip_addresses){
		linphone_core_set_dns_servers(lc, flexisip_tester_dns_ip_addresses);
	}else if (strcmp(userhostsfile, "none") != 0) {
		char *dnsuserhostspath = strchr(userhostsfile, '/') ? ms_strdup(userhostsfile) : ms_strdup_printf("%s/%s", path, userhostsfile);
		sal_set_dns_user_hosts_file(linphone_core_get_sal(lc), dnsuserhostspath);
		ms_free(dnsuserhostspath);
	} else{
		bctbx_warning("No dns-hosts file and no flexisip-tester dns server used.");
void configure_lc(LinphoneCore *lc, const char *path, void *user_data) {
	linphone_core_enable_ipv6(lc, liblinphonetester_ipv6);
	linphone_core_set_sip_transport_timeout(lc, liblinphonetester_transport_timeout);
	linphone_core_set_user_data(lc, user_data);

	sal_enable_test_features(linphone_core_get_sal(lc), TRUE);

	belle_sip_stack_set_dns_engine(sal_get_stack_impl(linphone_core_get_sal(lc)), BELLE_SIP_DNS_DNS_C); // Make sure we are not using Apple DNS Service during liblinphone tests
jehan's avatar
jehan committed
LinphoneCore *configure_lc_from(LinphoneCoreCbs *cbs, const char *path, LinphoneConfig *config, void *user_data) {
	char *ringpath         = NULL;
	char *ringbackpath     = NULL;
	char *rootcapath       = NULL;
	char *nowebcampath     = NULL;
	// setup dynamic-path assets
	ringpath         = ms_strdup_printf("%s/sounds/oldphone.wav",path);
	ringbackpath     = ms_strdup_printf("%s/sounds/ringback.wav", path);
	nowebcampath     = ms_strdup_printf("%s/images/nowebcamCIF.jpg", path);
	rootcapath       = ms_strdup_printf("%s/certificates/cn/cafile.pem", path);
		linphone_config_set_string(config, "sound", "remote_ring", ringbackpath);
		linphone_config_set_string(config, "sound", "local_ring" , ringpath);
		linphone_config_set_string(config, "sip",   "root_ca"    , rootcapath);

		LinphoneCoreManager *mgr = (LinphoneCoreManager *)user_data;
		if (mgr && mgr->app_group_id) {
			lc = linphone_factory_create_shared_core_with_config(linphone_factory_get(), config, system_context, mgr->app_group_id, mgr->main_core);
		} else {
			lc = linphone_factory_create_core_with_config_3(linphone_factory_get(), config, system_context);
		}
		lc = linphone_factory_create_core_3(linphone_factory_get(), NULL, liblinphone_tester_get_empty_rc(), system_context);
		linphone_core_set_ring(lc, ringpath);
		linphone_core_set_ringback(lc, ringbackpath);
		linphone_core_set_root_ca(lc, rootcapath);
	if (cbs)
		linphone_core_add_callbacks(lc, cbs);
#ifdef VIDEO_ENABLED
	linphone_core_set_static_picture(lc,nowebcampath);

	ms_free(ringpath);
	ms_free(ringbackpath);
	ms_free(nowebcampath);
	ms_free(rootcapath);
bool_t wait_for_until_interval(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int min,int max,int timeout) {
	bctbx_list_t* lcs=NULL;
	bool_t result;
	if (lc_1)
		lcs=bctbx_list_append(lcs,lc_1);
	if (lc_2)
		lcs=bctbx_list_append(lcs,lc_2);
	result=wait_for_list_interval(lcs,counter,min,max,timeout);
	bctbx_list_free(lcs);
	return result;
}

bool_t wait_for_until(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value,int timeout) {
	bctbx_list_t* lcs=NULL;
		lcs=bctbx_list_append(lcs,lc_1);
		lcs=bctbx_list_append(lcs,lc_2);
	result=wait_for_list(lcs,counter,value,timeout);
	return result;
}

bool_t wait_for(LinphoneCore* lc_1, LinphoneCore* lc_2,int* counter,int value) {
	return wait_for_until(lc_1, lc_2,counter,value,10000);
bool_t wait_for_list_interval(bctbx_list_t* lcs,int* counter,int min, int max,int timeout_ms) {
	bctbx_list_t* iterator;
	MSTimeSpec start;

	liblinphone_tester_clock_start(&start);
	while ((counter==NULL || *counter<min || *counter>max) && !liblinphone_tester_clock_elapsed(&start,timeout_ms)) {
		for (iterator=lcs;iterator!=NULL;iterator=iterator->next) {
			linphone_core_iterate((LinphoneCore*)(iterator->data));
		}
		bc_tester_process_events();
#if !defined(LINPHONE_WINDOWS_UWP) && defined(LINPHONE_WINDOWS_DESKTOP)
		{
			MSG msg;
			while (PeekMessage(&msg, NULL, 0, 0,1)){
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
#endif
		ms_usleep(20000);
	}
	if(counter && (*counter<min || *counter>max)) return FALSE;
	else return TRUE;
}

bool_t wait_for_list(bctbx_list_t* lcs,int* counter,int value,int timeout_ms) {
	bctbx_list_t* iterator;
	MSTimeSpec start;
	liblinphone_tester_clock_start(&start);
	while ((counter==NULL || *counter<value) && !liblinphone_tester_clock_elapsed(&start,timeout_ms)) {
		for (iterator=lcs;iterator!=NULL;iterator=iterator->next) {
			linphone_core_iterate((LinphoneCore*)(iterator->data));
		}
#ifdef LINPHONE_WINDOWS_UWP
		{
			bc_tester_process_events();
		}
#elif defined(LINPHONE_WINDOWS_DESKTOP)
		{
			MSG msg;
			while (PeekMessage(&msg, NULL, 0, 0,1)){
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
#endif
	}
	if(counter && *counter<value) return FALSE;
	else return TRUE;
}

bool_t wait_for_stun_resolution(LinphoneCoreManager *m) {
	MSTimeSpec start;
	int timeout_ms = 10000;
	liblinphone_tester_clock_start(&start);
Ghislain MARY's avatar
Ghislain MARY committed
	while (linphone_core_get_stun_server_addrinfo(m->lc) == NULL && !liblinphone_tester_clock_elapsed(&start,timeout_ms)) {
Ghislain MARY's avatar
Ghislain MARY committed
	return linphone_core_get_stun_server_addrinfo(m->lc) != NULL;
static void enable_codec(LinphoneCore* lc,const char* type,int rate) {
	bctbx_list_t* codecs=bctbx_list_copy(linphone_core_get_audio_codecs(lc));
	bctbx_list_t* codecs_it;
	PayloadType* pt;
	for (codecs_it=codecs;codecs_it!=NULL;codecs_it=codecs_it->next) {
		linphone_core_enable_payload_type(lc,(PayloadType*)codecs_it->data,0);
	if ((pt = linphone_core_find_payload_type(lc,type,rate,1))) {
		linphone_core_enable_payload_type(lc,pt, TRUE);
	bctbx_list_free(codecs);
}
stats * get_stats(LinphoneCore *lc){
	LinphoneCoreManager *manager=(LinphoneCoreManager *)linphone_core_get_user_data(lc);
	return &manager->stat;
}

LinphoneCoreManager *get_manager(LinphoneCore *lc){
	LinphoneCoreManager *manager=(LinphoneCoreManager *)linphone_core_get_user_data(lc);
	return manager;
}

bool_t transport_supported(LinphoneTransportType transport) {
	if ((transport == LinphoneTransportDtls || transport == LinphoneTransportTls) && liblinphone_tester_tls_support_disabled == TRUE) {
		return FALSE;
	} else {
		Sal *sal = sal_init(NULL);
		bool_t supported = sal_transport_available(sal,(SalTransport)transport);
		if (!supported) ms_message("TLS transport not supported, falling back to TCP if possible otherwise skipping test.");
		sal_uninit(sal);
		return  supported;
	}
static void avoid_pulseaudio_hack(LinphoneCoreManager *mgr){
	bctbx_list_t *cards = linphone_core_get_sound_devices_list(mgr->lc);
	bctbx_list_t *it;
	bool_t capture_set = FALSE, playback_set = FALSE;
	bool_t pulseaudio_found = FALSE;
	for (it = cards; it != NULL ; it = it->next){
		const char * card_id = (const char *)it->data;
		if (strstr(card_id, "PulseAudio") != NULL) {
			pulseaudio_found = TRUE;
			continue;
		}
		if (!capture_set && linphone_core_sound_device_can_capture(mgr->lc, card_id)){
			capture_set = TRUE;
			linphone_core_set_capture_device(mgr->lc, card_id);
		}
		if (!playback_set && linphone_core_sound_device_can_playback(mgr->lc, card_id)){
			playback_set = TRUE;
			linphone_core_set_playback_device(mgr->lc, card_id);
			linphone_core_set_ringer_device(mgr->lc, card_id);
		}
		if (playback_set && capture_set){
			if (pulseaudio_found) ms_warning("PulseAudio is not used in liblinphone_tester because of internal random crashes or hangs.");
			break;
		}
	}
	if (!playback_set || !capture_set){
		ms_error("Could not find soundcard other than pulseaudio to use during tests. Some tests may crash or hang.");
	}
	bctbx_list_free(cards);
}
#endif

void linphone_core_manager_setup_dns(LinphoneCoreManager *mgr){
	setup_dns(mgr->lc, bc_tester_get_resource_dir_prefix());
}
LinphoneCore *linphone_core_manager_configure_lc(LinphoneCoreManager *mgr) {
	LinphoneCore *lc;
	char *filepath = mgr->rc_path ? bctbx_strdup_printf("%s/%s", bc_tester_get_resource_dir_prefix(), mgr->rc_path) : NULL;
jehan's avatar
jehan committed
	if (filepath && bctbx_file_exist(filepath) != 0) {
		ms_fatal("Could not find file %s in path %s, did you configured resources directory correctly?", mgr->rc_path, bc_tester_get_resource_dir_prefix());
	}
	LinphoneConfig * config = linphone_factory_create_config_with_factory(linphone_factory_get(), mgr->rc_local, filepath);
jehan's avatar
jehan committed
	linphone_config_set_string(config, "storage", "backend", "sqlite3");
	linphone_config_set_string(config, "storage", "uri", mgr->database_path);
	linphone_config_set_string(config, "storage", "call_logs_db_uri", mgr->call_logs_database_path);
	linphone_config_set_string(config, "storage", "zrtp_secrets_db_uri", mgr->zrtp_secrets_database_path);
jehan's avatar
jehan committed
	linphone_config_set_string(config, "lime", "x3dh_db_path", mgr->lime_database_path);
	linphone_config_set_bool(config, "misc", "auto_iterate", FALSE);
	lc = configure_lc_from(mgr->cbs, bc_tester_get_resource_dir_prefix(), config, mgr);
jehan's avatar
jehan committed
	linphone_config_unref(config);
	return lc;
}

void linphone_core_manager_configure(LinphoneCoreManager *mgr) {
	LinphoneImNotifPolicy *im_notif_policy;
	char *hellopath = bc_tester_res("sounds/hello8000.wav");
	char *filepath = mgr->rc_path ? bctbx_strdup_printf("%s/%s", bc_tester_get_resource_dir_prefix(), mgr->rc_path) : NULL;
	if (filepath && bctbx_file_exist(filepath) != 0) {
		ms_fatal("Could not find file %s in path %s, did you configured resources directory correctly?", mgr->rc_path, bc_tester_get_resource_dir_prefix());
	}

	mgr->lc = linphone_core_manager_configure_lc(mgr);
	linphone_core_manager_check_accounts(mgr);
	im_notif_policy = linphone_core_get_im_notif_policy(mgr->lc);
	if (im_notif_policy != NULL) {
		/* The IM notification policy can be NULL at this point in case of remote provisioning. */
		linphone_im_notif_policy_clear(im_notif_policy);
		linphone_im_notif_policy_set_send_is_composing(im_notif_policy, TRUE);
		linphone_im_notif_policy_set_recv_is_composing(im_notif_policy, TRUE);
	}
Guillaume BIENKOWSKI's avatar
Guillaume BIENKOWSKI committed
#if TARGET_OS_IPHONE
	linphone_core_set_ringer_device( mgr->lc, "AQ: Audio Queue Device");
	linphone_core_set_ringback(mgr->lc, NULL);
#elif __QNX__
	linphone_core_set_playback_device(mgr->lc, "QSA: voice");
	{
		/* Special trick for linux. Pulseaudio has random hangs, deadlocks or abort while executing test suites.
		 * It never happens in the linphone app.
		 * So far we could not identify something bad in our pulseaudio usage. As a workaround, we disable pulseaudio for the tests.*/
		avoid_pulseaudio_hack(mgr);
	}
		cam = ms_web_cam_manager_get_cam(ms_factory_get_web_cam_manager(linphone_core_get_ms_factory(mgr->lc)), "Mire: Mire (synthetic moving picture)");
		//Usefull especially for encoders not supporting qcif
		#ifdef __ANDROID__
			MSVideoSize vsize = MS_VIDEO_SIZE_CIF;
			linphone_core_set_preferred_video_size(mgr->lc, vsize);
		#endif

Simon Morlat's avatar
Simon Morlat committed
			MSWebCamDesc *desc = ms_mire_webcam_desc_get();
			if (desc){
				cam=ms_web_cam_new(desc);
				ms_web_cam_manager_add_cam(ms_factory_get_web_cam_manager(linphone_core_get_ms_factory(mgr->lc)), cam);
Simon Morlat's avatar
Simon Morlat committed
			}
	linphone_core_set_play_file(mgr->lc,hellopath); /*is also used when in pause*/
	ms_free(hellopath);
		char *recordpath = ms_strdup_printf("%s/record_for_lc_%p.wav",bc_tester_get_writable_dir_prefix(),mgr->lc);
		ms_message("Manager for '%s' using files", mgr->rc_path ? mgr->rc_path : "--");
		linphone_core_set_record_file(mgr->lc,recordpath);
		ms_free(recordpath);
	linphone_core_set_user_certificates_path(mgr->lc,bc_tester_get_writable_dir_prefix());
	/*for now, we need the periodical updates facility to compute bandwidth measurements correctly during tests*/
	linphone_core_enable_send_call_stats_periodical_updates(mgr->lc, TRUE);
	// clean
	if (filepath) bctbx_free(filepath);
static void generate_random_database_path (LinphoneCoreManager *mgr) {
	char random_id[32];
	belle_sip_random_token(random_id, sizeof random_id);
	char *database_path_format = bctbx_strdup_printf("linphone_%s.db", random_id);
	mgr->database_path = bc_tester_file(database_path_format);
	bctbx_free(database_path_format);
jehan's avatar
jehan committed
	database_path_format = bctbx_strdup_printf("lime_%s.db", random_id);
	mgr->lime_database_path = bc_tester_file(database_path_format);
	bctbx_free(database_path_format);
	char *call_logs_database_path_format = bctbx_strdup_printf("call-history-%s.db", random_id);
	mgr->call_logs_database_path = bc_tester_file(call_logs_database_path_format);
	bctbx_free(call_logs_database_path_format);
	char *zrtp_secrets_database_path_format = bctbx_strdup_printf("zrtp-secrets-%s.db", random_id);
	mgr->zrtp_secrets_database_path = bc_tester_file(zrtp_secrets_database_path_format);
	bctbx_free(zrtp_secrets_database_path_format);
Andrea Gianarda's avatar
Andrea Gianarda committed
static void conference_state_changed (LinphoneConference *conference, LinphoneConferenceState newState) {
	LinphoneCore *core = linphone_conference_get_core(conference);
	LinphoneCoreManager *manager = (LinphoneCoreManager *)linphone_core_get_user_data(core);
	const LinphoneAddress * address = linphone_conference_get_conference_address(conference);
	char * address_str = NULL;
	if (address) {
		address_str = linphone_address_as_string(address);
Andrea Gianarda's avatar
Andrea Gianarda committed
		//ms_message("Conference [%s] state changed: %s", addr_str, linphone_conference_state_to_string(newState));
		ms_message("Conference [%s] state changed: %d", address_str, newState);
Andrea Gianarda's avatar
Andrea Gianarda committed
	}

	if ((newState != LinphoneConferenceStateNone) && (newState != LinphoneConferenceStateInstantiated) && (newState != LinphoneConferenceStateCreationPending)) {
			LinphoneParticipant *me = linphone_conference_get_me(conference);
			BC_ASSERT_PTR_NOT_NULL(me);
	}

	switch (newState) {
		case LinphoneConferenceStateNone:
			break;
		case LinphoneConferenceStateInstantiated:
			manager->stat.number_of_LinphoneConferenceStateInstantiated++;
			break;
		case LinphoneConferenceStateCreationPending:
			manager->stat.number_of_LinphoneConferenceStateCreationPending++;
			break;
		case LinphoneConferenceStateCreated:
			manager->stat.number_of_LinphoneConferenceStateCreated++;
			break;
		case LinphoneConferenceStateCreationFailed:
			manager->stat.number_of_LinphoneConferenceStateCreationFailed++;
			break;
		case LinphoneConferenceStateTerminationPending:
			manager->stat.number_of_LinphoneConferenceStateTerminationPending++;
			break;
		case LinphoneConferenceStateTerminated:
			manager->stat.number_of_LinphoneConferenceStateTerminated++;
			break;
		case LinphoneConferenceStateTerminationFailed:
			manager->stat.number_of_LinphoneConferenceStateTerminationFailed++;
			break;
		case LinphoneConferenceStateDeleted:
			manager->stat.number_of_LinphoneConferenceStateDeleted++;
			break;
		default:
			ms_error("Invalid Conference state for Conference [%s] EndOfEnum is used ONLY as a guard", address_str ? address_str : "Unknown address");
	if (address_str) {
		bctbx_free(address_str);
	}
Andrea Gianarda's avatar
Andrea Gianarda committed
}

void core_conference_state_changed (LinphoneCore *core, LinphoneConference *conference, LinphoneConferenceState state) {
	if (state == LinphoneConferenceStateInstantiated) {
		LinphoneConferenceCbs * cbs = linphone_factory_create_conference_cbs(linphone_factory_get());
		linphone_conference_cbs_set_state_changed(cbs, conference_state_changed);

		linphone_conference_add_callbacks(conference, cbs);
		linphone_conference_cbs_unref(cbs);
	}
}

LinphoneStatus add_participant_to_local_conference_through_invite(bctbx_list_t *lcs, LinphoneCoreManager * conf_mgr, bctbx_list_t *participants, const LinphoneCallParams *params) {

	stats conf_initial_stats = conf_mgr->stat;
	stats * participants_initial_stats = NULL;
	bool_t * existing_call = NULL;
	bctbx_list_t * participant_addresses = NULL;
	int counter = 1;

	LinphoneConference * local_conference = linphone_core_get_conference(conf_mgr->lc);
	BC_ASSERT_PTR_NOT_NULL(local_conference);
	const LinphoneAddress * local_conference_address = linphone_conference_get_conference_address(local_conference);

Andrea Gianarda's avatar
Andrea Gianarda committed
	for (bctbx_list_t *it = participants; it; it = bctbx_list_next(it)) {
		LinphoneCoreManager * m = (LinphoneCoreManager *)bctbx_list_get_data(it);
		participant_addresses = bctbx_list_append(participant_addresses, m->identity);

		// Allocate memory
		existing_call = (bool_t*)realloc(existing_call, counter * sizeof(bool_t));
		participants_initial_stats = (stats*)realloc(participants_initial_stats, counter * sizeof(stats));
		// Append element
		participants_initial_stats[counter - 1] = m->stat;
		LinphoneCall * conf_call = linphone_core_get_call_by_remote_address2(conf_mgr->lc, m->identity);
		existing_call[counter - 1] = (conf_call != NULL);
		// Increment counter
		counter++;

		LinphoneAddress *participant_uri = linphone_address_new(linphone_core_get_identity(m->lc));
		LinphoneConference * participant_conference = linphone_core_search_conference(m->lc, NULL, participant_uri, local_conference_address, NULL);
		linphone_address_unref(participant_uri);
		BC_ASSERT_PTR_NULL(participant_conference);

	LinphoneStatus status = linphone_conference_invite_participants(local_conference, participant_addresses, params);
Andrea Gianarda's avatar
Andrea Gianarda committed

	if (participants != NULL) {
		int idx = 0;
		int new_call_cnt = 0;
		for (bctbx_list_t *itm = participants; itm; itm = bctbx_list_next(itm)) {
			LinphoneCoreManager * m = (LinphoneCoreManager *)bctbx_list_get_data(itm);
			if (existing_call[idx] == FALSE) {
				new_call_cnt++;
				BC_ASSERT_TRUE(wait_for_list(lcs,&conf_mgr->stat.number_of_LinphoneCallOutgoingProgress,conf_initial_stats.number_of_LinphoneCallOutgoingProgress + new_call_cnt,2000));
				if (linphone_core_is_network_reachable(m->lc)) {
					BC_ASSERT_TRUE(wait_for_list(lcs,&m->stat.number_of_LinphoneCallIncomingReceived,(participants_initial_stats[idx].number_of_LinphoneCallIncomingReceived + 1),10000));

				}
			}
			idx++;
		}
	}

	if (participants_initial_stats) {
		ms_free(participants_initial_stats);
	}

	if (existing_call) {
		ms_free(existing_call);
	}

	if (participant_addresses) {
		bctbx_list_free(participant_addresses);
	}

Andrea Gianarda's avatar
Andrea Gianarda committed
	return status;

}

void check_conference_medias(LinphoneConference * local_conference, LinphoneConference * remote_conference) {
	BC_ASSERT_PTR_NOT_NULL(local_conference);
	BC_ASSERT_PTR_NOT_NULL(remote_conference);
	if (local_conference && remote_conference) {
		bctbx_list_t *local_conference_participants = linphone_conference_get_participant_list(local_conference);

		LinphoneParticipant * remote_conference_me = linphone_conference_get_me(remote_conference);
		const LinphoneAddress * remote_me_address = linphone_participant_get_address(remote_conference_me);
		for (bctbx_list_t *itp = local_conference_participants; itp; itp = bctbx_list_next(itp)) {
			LinphoneParticipant * p = (LinphoneParticipant *)bctbx_list_get_data(itp);
			const LinphoneAddress * p_address = linphone_participant_get_address (p);
			bctbx_list_t *local_devices = NULL;
			if (linphone_address_equal(p_address, remote_me_address)) {
				const bool_t remote_is_in = linphone_conference_is_in(remote_conference);
				const LinphoneConferenceParams * remote_params = linphone_conference_get_current_params(remote_conference);
				LinphoneMediaDirection audio_direction = ((remote_is_in == FALSE) || (!!linphone_conference_params_is_audio_enabled(remote_params) == FALSE)) ? LinphoneMediaDirectionInactive : LinphoneMediaDirectionSendRecv;
				LinphoneMediaDirection video_direction = ((remote_is_in == FALSE) || (!!linphone_conference_params_is_video_enabled(remote_params) == FALSE)) ? LinphoneMediaDirectionInactive : LinphoneMediaDirectionSendRecv;
				LinphoneMediaDirection text_direction = ((remote_is_in == FALSE) || (!!linphone_conference_params_is_chat_enabled(remote_params) == FALSE)) ? LinphoneMediaDirectionInactive : LinphoneMediaDirectionSendRecv;
				local_devices = linphone_participant_get_devices (p);
				for (bctbx_list_t *itd = local_devices; itd; itd = bctbx_list_next(itd)) {
					LinphoneParticipantDevice * d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
					BC_ASSERT_EQUAL(linphone_participant_device_get_audio_direction(d), audio_direction, int, "%0d");
					BC_ASSERT_EQUAL(linphone_participant_device_get_video_direction(d), video_direction, int, "%0d");
					BC_ASSERT_EQUAL(linphone_participant_device_get_text_direction(d), text_direction, int, "%0d");
				}
			} else {
				LinphoneParticipant * remote_participant = linphone_conference_find_participant(remote_conference, p_address);
				BC_ASSERT_PTR_NOT_NULL(remote_participant);
				if (remote_participant) {
					local_devices = linphone_participant_get_devices (p);
					for (bctbx_list_t *itd = local_devices; itd; itd = bctbx_list_next(itd)) {
						LinphoneParticipantDevice * d = (LinphoneParticipantDevice *)bctbx_list_get_data(itd);
						LinphoneParticipantDevice * remote_device = linphone_participant_find_device (remote_participant, linphone_participant_device_get_address(d));
						BC_ASSERT_PTR_NOT_NULL(remote_device);
						if (remote_device) {
							BC_ASSERT_EQUAL(linphone_participant_device_get_audio_direction(d), linphone_participant_device_get_audio_direction(remote_device), int, "%0d");
							BC_ASSERT_EQUAL(linphone_participant_device_get_video_direction(d), linphone_participant_device_get_video_direction(remote_device), int, "%0d");
							BC_ASSERT_EQUAL(linphone_participant_device_get_text_direction(d), linphone_participant_device_get_text_direction(remote_device), int, "%0d");
						}
					}
				}
			}
			if (local_devices) {
				bctbx_list_free_with_data(local_devices, (void (*)(void *))linphone_participant_device_unref);
			}
		}

		bctbx_list_free_with_data(local_conference_participants, (void (*)(void *))linphone_participant_unref);

		const LinphoneConferenceParams * local_params = linphone_conference_get_current_params(local_conference);
		const LinphoneConferenceParams * remote_params = linphone_conference_get_current_params(remote_conference);
		BC_ASSERT_EQUAL(linphone_conference_params_is_audio_enabled(local_params), linphone_conference_params_is_audio_enabled(remote_params), int, "%0d");
		BC_ASSERT_EQUAL(linphone_conference_params_is_video_enabled(local_params), linphone_conference_params_is_video_enabled(remote_params), int, "%0d");
		BC_ASSERT_EQUAL(linphone_conference_params_is_chat_enabled(local_params), linphone_conference_params_is_chat_enabled(remote_params), int, "%0d");
	}
}

static void check_participant_added_to_conference(bctbx_list_t *lcs, LinphoneCoreManager * conf_mgr, stats conf_initial_stats, bctbx_list_t *new_participants, stats* new_participant_initial_stats, bool_t * is_call_paused, bctbx_list_t *participants, stats* participant_initial_stats, LinphoneConference * conference) {
Andrea Gianarda's avatar
Andrea Gianarda committed

	const int no_new_participants = (int)bctbx_list_size(new_participants);
	const int no_participants = (int)bctbx_list_size(participants);
	int no_participants_without_event_log = 0;

	BC_ASSERT_TRUE(wait_for_list(lcs,&conf_mgr->stat.number_of_LinphoneCallStreamsRunning,conf_initial_stats.number_of_LinphoneCallStreamsRunning + no_new_participants,3000));

	//  Check that me has focus attribute set to true
	BC_ASSERT_PTR_NOT_NULL(conference);
	if (conference) {
		LinphoneParticipant *me = linphone_conference_get_me(conference);
		BC_ASSERT_PTR_NOT_NULL(me);
		BC_ASSERT_TRUE(linphone_participant_is_focus(me));
	}
Andrea Gianarda's avatar
Andrea Gianarda committed

	int * notifyExpected = NULL;
	for (int idx = 0; idx < no_participants; idx++) {
		notifyExpected = (int*)realloc(notifyExpected, (idx + 1) * sizeof(int));
		notifyExpected[idx] = 0;
	}

	int idx = 0;
	bool_t conf_event_log_enabled = linphone_config_get_bool(linphone_core_get_config(conf_mgr->lc), "misc", "conference_event_log_enabled", TRUE );
Andrea Gianarda's avatar
Andrea Gianarda committed
	for (bctbx_list_t *it = new_participants; it; it = bctbx_list_next(it)) {
		LinphoneCoreManager * m = (LinphoneCoreManager *)bctbx_list_get_data(it);

		BC_ASSERT_TRUE(wait_for_list(lcs,&m->stat.number_of_LinphoneCallStreamsRunning,new_participant_initial_stats[idx].number_of_LinphoneCallStreamsRunning + 1 + (is_call_paused[idx]) ? 1 : 0,3000));

		// Remote conference creation
		BC_ASSERT_TRUE(wait_for_list(lcs, &m->stat.number_of_LinphoneConferenceStateCreationPending, new_participant_initial_stats[idx].number_of_LinphoneConferenceStateCreationPending + 1, 5000));

		bool_t p_event_log_enabled = linphone_config_get_bool(linphone_core_get_config(m->lc), "misc", "conference_event_log_enabled", TRUE );
		if (p_event_log_enabled) {
Andrea Gianarda's avatar
Andrea Gianarda committed
			// Check subscriptions
Simon Morlat's avatar
Simon Morlat committed
			BC_ASSERT_TRUE(wait_for_list(lcs,&m->stat.number_of_LinphoneSubscriptionOutgoingProgress,(new_participant_initial_stats[idx].number_of_LinphoneSubscriptionOutgoingProgress + 1),5000));
			if (conf_event_log_enabled) {
				BC_ASSERT_TRUE(wait_for_list(lcs,&conf_mgr->stat.number_of_LinphoneSubscriptionIncomingReceived,(conf_initial_stats.number_of_LinphoneSubscriptionIncomingReceived + idx - no_participants_without_event_log + 1),5000));
				BC_ASSERT_TRUE(wait_for_list(lcs,&conf_mgr->stat.number_of_LinphoneSubscriptionActive,(conf_initial_stats.number_of_LinphoneSubscriptionActive + idx + 1),5000));
				BC_ASSERT_TRUE(wait_for_list(lcs,&m->stat.number_of_LinphoneSubscriptionActive,new_participant_initial_stats[idx].number_of_LinphoneSubscriptionActive + 1,3000));
				BC_ASSERT_TRUE(wait_for_list(lcs, &m->stat.number_of_LinphoneConferenceStateCreated, new_participant_initial_stats[idx].number_of_LinphoneConferenceStateCreated + 1, 5000));
			}

Andrea Gianarda's avatar
Andrea Gianarda committed
		} else {
			no_participants_without_event_log++;
		}

		// Notify
		int idx2 = 0;
		for (bctbx_list_t *itm = participants; itm; itm = bctbx_list_next(itm)) {
			LinphoneCoreManager * m2 = (LinphoneCoreManager *)bctbx_list_get_data(itm);
			bool_t p2_event_log_enabled = linphone_config_get_bool(linphone_core_get_config(m2->lc), "misc", "conference_event_log_enabled", TRUE );
			if (p2_event_log_enabled && conf_event_log_enabled) {
Andrea Gianarda's avatar
Andrea Gianarda committed
				if (bctbx_list_find(new_participants,m2)) {
					// When a participant is added, it receives the notification only once even though more participants are added at the same time
					if (m2 == m) {
						// Participant added
						notifyExpected[idx2] = notifyExpected[idx2] + 1;
					}
				} else {
					// Participant added
					// Participant device added
					notifyExpected[idx2] = notifyExpected[idx2] + 2;
				}
				BC_ASSERT_TRUE(wait_for_list(lcs,&m2->stat.number_of_NotifyReceived,(participant_initial_stats[idx2].number_of_NotifyReceived + notifyExpected[idx2]),3000));
			}
			idx2++;
		}

		if (p_event_log_enabled) {
			if (conf_event_log_enabled) {
				// Number of subscription errors should not change as they the participant should received a notification
				BC_ASSERT_EQUAL(m->stat.number_of_LinphoneSubscriptionError,new_participant_initial_stats[idx].number_of_LinphoneSubscriptionError, int, "%0d");
			} else {
				BC_ASSERT_TRUE(wait_for_list(lcs,&m->stat.number_of_LinphoneSubscriptionError,(participant_initial_stats[idx].number_of_LinphoneSubscriptionError + 1),3000));
			}
		}
Andrea Gianarda's avatar
Andrea Gianarda committed

		// Number of subscription terminated should not change as they the participant should received a notification
		BC_ASSERT_EQUAL(m->stat.number_of_LinphoneSubscriptionTerminated, new_participant_initial_stats[idx].number_of_LinphoneSubscriptionTerminated, int, "%d");
		idx++;
	}

	int expected_subscriptions = 0;
	if (conference) {
		expected_subscriptions = linphone_conference_get_participant_count(conference);
		for (bctbx_list_t *itm = participants; itm; itm = bctbx_list_next(itm)) {
			LinphoneCoreManager * m = (LinphoneCoreManager *)bctbx_list_get_data(itm);
			bool_t event_log_enabled = linphone_config_get_bool(linphone_core_get_config(m->lc), "misc", "conference_event_log_enabled", TRUE );
			// If events logs are not enabled, subscribes are not sent
			if (!event_log_enabled) {
				expected_subscriptions--;
			}
		}
	}

	int* subscription_count = ((int *)(conf_mgr->user_info));
	BC_ASSERT_TRUE(wait_for_list(lcs,subscription_count, expected_subscriptions,5000));
	if (conf_event_log_enabled) {
		BC_ASSERT_TRUE(wait_for_list(lcs,&conf_mgr->stat.number_of_LinphoneSubscriptionActive,expected_subscriptions,3000));
	} else {
		BC_ASSERT_EQUAL(conf_mgr->stat.number_of_LinphoneSubscriptionActive,0,int,"%d");
	}
Andrea Gianarda's avatar
Andrea Gianarda committed

	BC_ASSERT_EQUAL(conf_mgr->stat.number_of_LinphoneSubscriptionError,conf_initial_stats.number_of_LinphoneSubscriptionError, int, "%0d");

	if (conf_event_log_enabled) {
		BC_ASSERT_EQUAL(conf_mgr->stat.number_of_LinphoneSubscriptionTerminated, conf_initial_stats.number_of_LinphoneSubscriptionTerminated, int, "%d");
	} else {
		BC_ASSERT_TRUE(wait_for_list(lcs,&conf_mgr->stat.number_of_LinphoneSubscriptionTerminated,(conf_initial_stats.number_of_LinphoneSubscriptionTerminated + no_new_participants),3000));
	}
Andrea Gianarda's avatar
Andrea Gianarda committed

	ms_free(notifyExpected);

	// Add a short wait to ensure that all NOTIFYs are replied
	wait_for_list(lcs,NULL,0,1000);

	if (!conference) {
		conference = linphone_core_get_conference(conf_mgr->lc);
	}
	BC_ASSERT_PTR_NOT_NULL(conference);
	if (conference) {
		const LinphoneAddress * local_conference_address = linphone_conference_get_conference_address(conference);
		for (bctbx_list_t *it = new_participants; it; it = bctbx_list_next(it)) {
			LinphoneCoreManager * m = (LinphoneCoreManager *)bctbx_list_get_data(it);
			bool_t p_event_log_enabled = linphone_config_get_bool(linphone_core_get_config(m->lc), "misc", "conference_event_log_enabled", TRUE );
			if (p_event_log_enabled && conf_event_log_enabled) {
				LinphoneAddress *m_uri = linphone_address_new(linphone_core_get_identity(m->lc));
				LinphoneConference * remote_conference = linphone_core_search_conference(m->lc, NULL, m_uri, local_conference_address, NULL);
				linphone_address_unref(m_uri);
				BC_ASSERT_PTR_NOT_NULL(remote_conference);
				if (remote_conference) {
					check_conference_medias(conference, remote_conference);
				}
			}
		}
	}


Andrea Gianarda's avatar
Andrea Gianarda committed
}

LinphoneStatus add_calls_to_remote_conference(bctbx_list_t *lcs, LinphoneCoreManager * focus_mgr, LinphoneCoreManager * conf_mgr, bctbx_list_t *new_participants) {

	stats conf_initial_stats = conf_mgr->stat;
	stats focus_initial_stats = focus_mgr->stat;

	LinphoneCall * conf_to_focus_call = linphone_core_get_call_by_remote_address2(conf_mgr->lc, focus_mgr->identity);

	int counter = 1;
	for (bctbx_list_t *it = new_participants; it; it = bctbx_list_next(it)) {
		LinphoneCoreManager * m = (LinphoneCoreManager *)bctbx_list_get_data(it);
		stats initial_stats = m->stat;
		LinphoneCall * conf_call = linphone_core_get_call_by_remote_address2(conf_mgr->lc, m->identity);
		BC_ASSERT_PTR_NOT_NULL(conf_call);
		linphone_core_add_to_conference(conf_mgr->lc,conf_call);

		BC_ASSERT_TRUE(wait_for_list(lcs,&m->stat.number_of_LinphoneConferenceStateCreationPending, initial_stats.number_of_LinphoneConferenceStateCreationPending + 1, 5000));
		BC_ASSERT_TRUE(wait_for_list(lcs,&m->stat.number_of_LinphoneConferenceStateCreated, initial_stats.number_of_LinphoneConferenceStateCreated + 1, 5000));

Simon Morlat's avatar
Simon Morlat committed
		BC_ASSERT_TRUE(wait_for_list(lcs,&m->stat.number_of_LinphoneSubscriptionOutgoingProgress,(initial_stats.number_of_LinphoneSubscriptionOutgoingProgress + 1),5000));
Andrea Gianarda's avatar
Andrea Gianarda committed
//		BC_ASSERT_TRUE(wait_for_list(lcs,&focus_mgr->stat.number_of_LinphoneSubscriptionIncomingReceived,(focus_initial_stats.number_of_LinphoneSubscriptionIncomingReceived + counter),1000));

		BC_ASSERT_TRUE(wait_for_list(lcs,&m->stat.number_of_LinphoneSubscriptionActive,initial_stats.number_of_LinphoneSubscriptionActive + 1,3000));
//		BC_ASSERT_TRUE(wait_for_list(lcs,&focus_mgr->stat.number_of_LinphoneSubscriptionActive,(focus_initial_stats.number_of_LinphoneSubscriptionActive + counter),1000));

		BC_ASSERT_TRUE(wait_for_list(lcs,&focus_mgr->stat.number_of_LinphoneCallStreamsRunning,(focus_initial_stats.number_of_LinphoneCallStreamsRunning+counter),5000));
		BC_ASSERT_TRUE(wait_for_list(lcs,&conf_mgr->stat.number_of_LinphoneTransferCallConnected,conf_initial_stats.number_of_LinphoneTransferCallConnected+counter,5000));

		// End of call between conference and participant
		BC_ASSERT_TRUE(wait_for_list(lcs,&conf_mgr->stat.number_of_LinphoneCallEnd,conf_initial_stats.number_of_LinphoneCallEnd+counter,5000));
		BC_ASSERT_TRUE(wait_for_list(lcs,&m->stat.number_of_LinphoneCallEnd,initial_stats.number_of_LinphoneCallEnd+1,5000));

		BC_ASSERT_TRUE(wait_for_list(lcs,&conf_mgr->stat.number_of_LinphoneCallReleased,conf_initial_stats.number_of_LinphoneCallReleased+counter,5000));
		BC_ASSERT_TRUE(wait_for_list(lcs,&m->stat.number_of_LinphoneCallReleased,initial_stats.number_of_LinphoneCallReleased+1,5000));

		BC_ASSERT_TRUE(wait_for_list(lcs,&m->stat.number_of_NotifyReceived,(initial_stats.number_of_NotifyReceived + 1),5000));
Andrea Gianarda's avatar
Andrea Gianarda committed
		// Local conference
		LinphoneCall * focus_call = linphone_core_get_call_by_remote_address2(focus_mgr->lc, m->identity);
		BC_ASSERT_PTR_NOT_NULL(focus_call);
		if (focus_call) {
			BC_ASSERT_PTR_NOT_NULL(linphone_call_get_conference(focus_call));
			BC_ASSERT_TRUE(linphone_call_is_in_conference(focus_call));
		}
Andrea Gianarda's avatar
Andrea Gianarda committed

		// Remote  conference
		LinphoneCall * participant_call = linphone_core_get_call_by_remote_address2(m->lc, focus_mgr->identity);
		BC_ASSERT_PTR_NOT_NULL(participant_call);
		if (participant_call) {
			BC_ASSERT_PTR_NOT_NULL(linphone_call_get_conference(participant_call));
			BC_ASSERT_FALSE(linphone_call_is_in_conference(participant_call));
		}
Andrea Gianarda's avatar
Andrea Gianarda committed

		counter++;
	}

	// Remote  conference
	if (conf_to_focus_call == NULL) {
		// Asserts to verify that call between focus and confernece manager is correctly set up
Simon Morlat's avatar
Simon Morlat committed
		BC_ASSERT_TRUE(wait_for_list(lcs,&conf_mgr->stat.number_of_LinphoneSubscriptionOutgoingProgress,(conf_initial_stats.number_of_LinphoneSubscriptionOutgoingProgress + 1),5000));
Andrea Gianarda's avatar
Andrea Gianarda committed
//		BC_ASSERT_TRUE(wait_for_list(lcs,&focus_mgr->stat.number_of_LinphoneSubscriptionIncomingReceived,(focus_initial_stats.number_of_LinphoneSubscriptionIncomingReceived + counter + 1),1000));
		BC_ASSERT_TRUE(wait_for_list(lcs,&focus_mgr->stat.number_of_LinphoneConferenceStateCreationPending, focus_initial_stats.number_of_LinphoneConferenceStateCreationPending + 1, 5000));
		BC_ASSERT_TRUE(wait_for_list(lcs,&focus_mgr->stat.number_of_LinphoneConferenceStateCreated, focus_initial_stats.number_of_LinphoneConferenceStateCreated + 1, 5000));
		BC_ASSERT_TRUE(wait_for_list(lcs,&conf_mgr->stat.number_of_LinphoneSubscriptionActive,conf_initial_stats.number_of_LinphoneSubscriptionActive + 1,3000));
//		BC_ASSERT_TRUE(wait_for_list(lcs,&focus_mgr->stat.number_of_LinphoneSubscriptionActive,(focus_initial_stats.number_of_LinphoneSubscriptionActive + counter + 1),1000));
		BC_ASSERT_TRUE(wait_for_list(lcs,&conf_mgr->stat.number_of_LinphoneCallStreamsRunning,(conf_initial_stats.number_of_LinphoneCallStreamsRunning+1),5000));
		BC_ASSERT_TRUE(wait_for_list(lcs,&focus_mgr->stat.number_of_LinphoneCallStreamsRunning,(focus_initial_stats.number_of_LinphoneCallStreamsRunning+counter+1),5000));

		conf_to_focus_call = linphone_core_get_call_by_remote_address2(conf_mgr->lc, focus_mgr->identity);
	}
	BC_ASSERT_PTR_NOT_NULL(conf_to_focus_call);
	BC_ASSERT_PTR_NOT_NULL(linphone_call_get_conference(conf_to_focus_call));
	BC_ASSERT_FALSE(linphone_call_is_in_conference(conf_to_focus_call));

	// Local conference
	LinphoneCall * focus_to_conf_call = linphone_core_get_call_by_remote_address2(focus_mgr->lc, conf_mgr->identity);
	BC_ASSERT_PTR_NOT_NULL(focus_to_conf_call);
	BC_ASSERT_PTR_NOT_NULL(linphone_call_get_conference(focus_to_conf_call));
	BC_ASSERT_TRUE(linphone_call_is_in_conference(focus_to_conf_call));

	return 0;

}

LinphoneStatus add_calls_to_local_conference(bctbx_list_t *lcs, LinphoneCoreManager * conf_mgr, LinphoneConference * conference, bctbx_list_t *new_participants, bool_t one_by_one) {
Andrea Gianarda's avatar
Andrea Gianarda committed

	stats conf_initial_stats = conf_mgr->stat;

	stats* participants_initial_stats = NULL;
	bctbx_list_t *participants = NULL;
	int counter = 1;
	for (bctbx_list_t *it = lcs; it; it = bctbx_list_next(it)) {
		LinphoneCore * c = (LinphoneCore *)bctbx_list_get_data(it);
		LinphoneCoreManager * m = get_manager(c);
		if (m != conf_mgr) {
			// Allocate memory
			participants_initial_stats = (stats*)realloc(participants_initial_stats, counter * sizeof(stats));
			// Append element
			participants_initial_stats[counter - 1] = m->stat;
			// Increment counter
			counter++;
			participants = bctbx_list_append(participants, m);
		}
	}

	counter = 1;
	stats* new_participants_initial_stats = NULL;
	for (bctbx_list_t *it = new_participants; it; it = bctbx_list_next(it)) {
		LinphoneCoreManager * m = (LinphoneCoreManager *)bctbx_list_get_data(it);
		// Allocate memory
		new_participants_initial_stats = (stats*)realloc(new_participants_initial_stats, counter * sizeof(stats));
		// Append element
		new_participants_initial_stats[counter - 1] = m->stat;
		// Increment counter
		counter++;
	}

	bool_t * call_paused = NULL;

	counter = 1;
	if (one_by_one) {
		for (bctbx_list_t *it = new_participants; it; it = bctbx_list_next(it)) {
			LinphoneCoreManager * m = (LinphoneCoreManager *)bctbx_list_get_data(it);
			stats initial_stats = m->stat;
			LinphoneCall * conf_call = linphone_core_get_call_by_remote_address2(conf_mgr->lc, m->identity);
			BC_ASSERT_PTR_NOT_NULL(conf_call);
			call_paused = (bool_t*)realloc(call_paused, counter * sizeof(bool_t));
			call_paused[counter - 1] = FALSE;
			if (conf_call) {
				bool_t is_call_paused = (linphone_call_get_state(conf_call) == LinphoneCallStatePaused);
				call_paused[counter - 1] = is_call_paused;
				if (conference) {
					linphone_conference_add_participant(conference,conf_call);
					conference_used = conference;
				} else {
					linphone_core_add_to_conference(conf_mgr->lc,conf_call);
					conference_used = linphone_core_get_conference(conf_mgr->lc);
				}

				if (is_call_paused) {
					BC_ASSERT_TRUE(wait_for_list(lcs,&conf_mgr->stat.number_of_LinphoneCallResuming,conf_initial_stats.number_of_LinphoneCallResuming+1,2000));